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 chunk and chunk:len() == 0 then chunk = nil end
148 if not chunk then handle:close() end
151 else return source.error(io_err or "unable to open file") end
154 --- Turn a fancy source into a simple source.
155 -- @param src fancy source
156 -- @return LTN12 source
157 function source.simplify(src)
160 local chunk, err_or_new = src()
161 src = err_or_new or src
162 if not chunk then return nil, err_or_new
163 else return chunk end
167 --- Create a string source.
169 -- @return LTN12 source
170 function source.string(s)
174 local chunk = string.sub(s, i, i+BLOCKSIZE-1)
176 if chunk ~= "" then return chunk
179 else return source.empty() end
182 --- Creates rewindable source.
183 -- @param src LTN12 source to be made rewindable
184 -- @return LTN12 source
185 function source.rewind(src)
188 return function(chunk)
190 chunk = table.remove(t)
191 if not chunk then return src()
192 else return chunk end
199 --- Chain a source and a filter together.
200 -- @param src LTN12 source
201 -- @param f LTN12 filter
202 -- @return LTN12 source
203 function source.chain(src, f)
204 base.assert(src and f)
205 local last_in, last_out = "", ""
206 local state = "feeding"
210 base.error('source is empty!', 2)
213 if state == "feeding" then
215 if err then return nil, err end
216 last_out = f(last_in)
219 base.error('filter returned inappropriate nil')
223 elseif last_out ~= "" then
225 if last_in then last_in = "" end
229 last_out = f(last_in)
230 if last_out == "" then
231 if last_in == "" then
234 base.error('filter returned ""')
236 elseif not last_out then
238 base.error('filter returned inappropriate nil')
250 --- Create a source that produces contents of several sources.
251 -- Sources will be used one after the other, as if they were concatenated
252 -- (thanks to Wim Couwenberg)
253 -- @param ... LTN12 sources
254 -- @return LTN12 source
255 function source.cat(...)
256 local src = table.remove(arg, 1)
259 local chunk, err = src()
260 if chunk then return chunk end
261 if err then return nil, err end
262 src = table.remove(arg, 1)
267 -----------------------------------------------------------------------------
269 -----------------------------------------------------------------------------
271 --- LTN12 sink constructors
273 -- @name luci.ltn12.sink
275 --- Create a sink that stores into a table.
276 -- @param t output table to store into
277 -- @return LTN12 sink
278 function sink.table(t)
280 local f = function(chunk, err)
281 if chunk then t[#t+1] = chunk end
287 --- Turn a fancy sink into a simple sink.
288 -- @param snk fancy sink
289 -- @return LTN12 sink
290 function sink.simplify(snk)
292 return function(chunk, err)
293 local ret, err_or_new = snk(chunk, err)
294 if not ret then return nil, err_or_new end
295 snk = err_or_new or snk
300 --- Create a file sink.
301 -- @param handle file handle to write to
302 -- @param io_err IO error
303 -- @return LTN12 sink
304 function sink.file(handle, io_err)
306 return function(chunk, err)
310 else return handle:write(chunk) end
312 else return sink.error(io_err or "unable to open file") end
315 -- creates a sink that discards data
316 local function null()
320 --- Create a sink that discards data.
321 -- @return LTN12 sink
326 --- Create a sink that just returns an error.
327 -- @param err Error object
328 -- @return LTN12 sink
329 function sink.error(err)
335 --- Chain a sink with a filter.
336 -- @param f LTN12 filter
337 -- @param snk LTN12 sink
338 -- @return LTN12 sink
339 function sink.chain(f, snk)
340 base.assert(f and snk)
341 return function(chunk, err)
343 local filtered = f(chunk)
344 local done = chunk and ""
346 local ret, snkerr = snk(filtered, err)
347 if not ret then return nil, snkerr end
348 if filtered == done then return 1 end
355 -----------------------------------------------------------------------------
357 -----------------------------------------------------------------------------
359 --- LTN12 pump functions
361 -- @name luci.ltn12.pump
363 --- Pump one chunk from the source to the sink.
364 -- @param src LTN12 source
365 -- @param snk LTN12 sink
366 -- @return Chunk of data or nil if an error occured
367 -- @return Error object
368 function pump.step(src, snk)
369 local chunk, src_err = src()
370 local ret, snk_err = snk(chunk, src_err)
371 if chunk and ret then return 1
372 else return nil, src_err or snk_err end
375 --- Pump all data from a source to a sink, using a step function.
376 -- @param src LTN12 source
377 -- @param snk LTN12 sink
378 -- @param step step function (optional)
379 -- @return 1 if the operation succeeded otherwise nil
380 -- @return Error object
381 function pump.all(src, snk, step)
382 base.assert(src and snk)
383 step = step or pump.step
385 local ret, err = step(src, snk)
387 if err then return nil, err