2 LuaSocket 2.0.2 license
3 Copyright � 2004-2007 Diego Nehab
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
24 Changes made by LuCI project:
25 * Renamed to luci.ltn12 to avoid collisions with luasocket
26 * Added inline documentation
28 -----------------------------------------------------------------------------
29 -- LTN12 - Filters, sources, sinks and pumps.
31 -- Author: Diego Nehab
33 -----------------------------------------------------------------------------
35 -----------------------------------------------------------------------------
37 -----------------------------------------------------------------------------
38 local string = require("string")
39 local table = require("table")
42 --- Diego Nehab's LTN12 - Filters, sources, sinks and pumps.
43 -- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts
51 -- 2048 seems to be better in windows...
53 _VERSION = "LTN12 1.0.1"
55 -----------------------------------------------------------------------------
57 -----------------------------------------------------------------------------
59 --- LTN12 Filter constructors
61 -- @name luci.ltn12.filter
63 --- Return a high level filter that cycles a low-level filter
64 -- by passing it each chunk and updating a context between calls.
65 -- @param low Low-level filter
67 -- @param extra Extra argument passed to the low-level filter
68 -- @return LTN12 filter
69 function filter.cycle(low, ctx, extra)
71 return function(chunk)
73 ret, ctx = low(ctx, chunk, extra)
78 --- Chain a bunch of filters together.
79 -- (thanks to Wim Couwenberg)
80 -- @param ... filters to be chained
81 -- @return LTN12 filter
82 function filter.chain(...)
83 local n = table.getn(arg)
84 local top, index = 1, 1
86 return function(chunk)
87 retry = chunk and retry
90 chunk = arg[index](chunk)
91 if chunk == "" or top == n then return chunk
92 elseif chunk then index = index + 1
98 chunk = arg[index](chunk or "")
103 if index == n then return chunk
104 else index = index + 1 end
105 else base.error("filter returned inappropriate nil") end
111 -----------------------------------------------------------------------------
113 -----------------------------------------------------------------------------
115 --- LTN12 Source constructors
117 -- @name luci.ltn12.source
119 -- create an empty source
120 local function empty()
124 --- Create an empty source.
125 -- @return LTN12 source
126 function source.empty()
130 --- Return a source that just outputs an error.
131 -- @param err Error object
132 -- @return LTN12 source
133 function source.error(err)
139 --- Create a file source.
140 -- @param handle File handle ready for reading
141 -- @param io_err IO error object
142 -- @return LTN12 source
143 function source.file(handle, io_err)
146 local chunk = handle:read(BLOCKSIZE)
147 if not chunk then handle:close() end
150 else return source.error(io_err or "unable to open file") end
153 --- Turn a fancy source into a simple source.
154 -- @param src fancy source
155 -- @return LTN12 source
156 function source.simplify(src)
159 local chunk, err_or_new = src()
160 src = err_or_new or src
161 if not chunk then return nil, err_or_new
162 else return chunk end
166 --- Create a string source.
168 -- @return LTN12 source
169 function source.string(s)
173 local chunk = string.sub(s, i, i+BLOCKSIZE-1)
175 if chunk ~= "" then return chunk
178 else return source.empty() end
181 --- Creates rewindable source.
182 -- @param src LTN12 source to be made rewindable
183 -- @return LTN12 source
184 function source.rewind(src)
187 return function(chunk)
189 chunk = table.remove(t)
190 if not chunk then return src()
191 else return chunk end
198 --- Chain a source and a filter together.
199 -- @param src LTN12 source
200 -- @param f LTN12 filter
201 -- @return LTN12 source
202 function source.chain(src, f)
203 base.assert(src and f)
204 local last_in, last_out = "", ""
205 local state = "feeding"
209 base.error('source is empty!', 2)
212 if state == "feeding" then
214 if err then return nil, err end
215 last_out = f(last_in)
218 base.error('filter returned inappropriate nil')
222 elseif last_out ~= "" then
224 if last_in then last_in = "" end
228 last_out = f(last_in)
229 if last_out == "" then
230 if last_in == "" then
233 base.error('filter returned ""')
235 elseif not last_out then
237 base.error('filter returned inappropriate nil')
249 --- Create a source that produces contents of several sources.
250 -- Sources will be used one after the other, as if they were concatenated
251 -- (thanks to Wim Couwenberg)
252 -- @param ... LTN12 sources
253 -- @return LTN12 source
254 function source.cat(...)
255 local src = table.remove(arg, 1)
258 local chunk, err = src()
259 if chunk then return chunk end
260 if err then return nil, err end
261 src = table.remove(arg, 1)
266 -----------------------------------------------------------------------------
268 -----------------------------------------------------------------------------
270 --- LTN12 sink constructors
272 -- @name luci.ltn12.sink
274 --- Create a sink that stores into a table.
275 -- @param t output table to store into
276 -- @return LTN12 sink
277 function sink.table(t)
279 local f = function(chunk, err)
280 if chunk then t[#t+1] = chunk end
286 --- Turn a fancy sink into a simple sink.
287 -- @param snk fancy sink
288 -- @return LTN12 sink
289 function sink.simplify(snk)
291 return function(chunk, err)
292 local ret, err_or_new = snk(chunk, err)
293 if not ret then return nil, err_or_new end
294 snk = err_or_new or snk
299 --- Create a file sink.
300 -- @param handle file handle to write to
301 -- @param io_err IO error
302 -- @return LTN12 sink
303 function sink.file(handle, io_err)
305 return function(chunk, err)
309 else return handle:write(chunk) end
311 else return sink.error(io_err or "unable to open file") end
314 -- creates a sink that discards data
315 local function null()
319 --- Create a sink that discards data.
320 -- @return LTN12 sink
325 --- Create a sink that just returns an error.
326 -- @param err Error object
327 -- @return LTN12 sink
328 function sink.error(err)
334 --- Chain a sink with a filter.
335 -- @param f LTN12 filter
336 -- @param snk LTN12 sink
337 -- @return LTN12 sink
338 function sink.chain(f, snk)
339 base.assert(f and snk)
340 return function(chunk, err)
342 local filtered = f(chunk)
343 local done = chunk and ""
345 local ret, snkerr = snk(filtered, err)
346 if not ret then return nil, snkerr end
347 if filtered == done then return 1 end
354 -----------------------------------------------------------------------------
356 -----------------------------------------------------------------------------
358 --- LTN12 pump functions
360 -- @name luci.ltn12.pump
362 --- Pump one chunk from the source to the sink.
363 -- @param src LTN12 source
364 -- @param snk LTN12 sink
365 -- @return Chunk of data or nil if an error occured
366 -- @return Error object
367 function pump.step(src, snk)
368 local chunk, src_err = src()
369 local ret, snk_err = snk(chunk, src_err)
370 if chunk and ret then return 1
371 else return nil, src_err or snk_err end
374 --- Pump all data from a source to a sink, using a step function.
375 -- @param src LTN12 source
376 -- @param snk LTN12 sink
377 -- @param step step function (optional)
378 -- @return 1 if the operation succeeded otherwise nil
379 -- @return Error object
380 function pump.all(src, snk, step)
381 base.assert(src and snk)
382 step = step or pump.step
384 local ret, err = step(src, snk)
386 if err then return nil, err