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 -- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts
50 -- 2048 seems to be better in windows...
52 _VERSION = "LTN12 1.0.1"
54 -----------------------------------------------------------------------------
56 -----------------------------------------------------------------------------
59 -- by passing it each chunk and updating a context between calls.
60 function filter.cycle(low, ctx, extra)
62 return function(chunk)
64 ret, ctx = low(ctx, chunk, extra)
69 -- (thanks to Wim Couwenberg)
70 function filter.chain(...)
71 local n = table.getn(arg)
72 local top, index = 1, 1
74 return function(chunk)
75 retry = chunk and retry
78 chunk = arg[index](chunk)
79 if chunk == "" or top == n then return chunk
80 elseif chunk then index = index + 1
86 chunk = arg[index](chunk or "")
91 if index == n then return chunk
92 else index = index + 1 end
93 else base.error("filter returned inappropriate nil") end
99 -----------------------------------------------------------------------------
101 -----------------------------------------------------------------------------
104 -- create an empty source
105 local function empty()
109 function source.empty()
113 function source.error(err)
119 function source.file(handle, io_err)
122 local chunk = handle:read(BLOCKSIZE)
123 if chunk and chunk:len() == 0 then chunk = nil end
124 if not chunk then handle:close() end
127 else return source.error(io_err or "unable to open file") end
130 function source.simplify(src)
133 local chunk, err_or_new = src()
134 src = err_or_new or src
135 if not chunk then return nil, err_or_new
136 else return chunk end
140 function source.string(s)
144 local chunk = string.sub(s, i, i+BLOCKSIZE-1)
146 if chunk ~= "" then return chunk
149 else return source.empty() end
152 function source.rewind(src)
155 return function(chunk)
157 chunk = table.remove(t)
158 if not chunk then return src()
159 else return chunk end
166 function source.chain(src, f)
167 base.assert(src and f)
168 local last_in, last_out = "", ""
169 local state = "feeding"
173 base.error('source is empty!', 2)
176 if state == "feeding" then
178 if err then return nil, err end
179 last_out = f(last_in)
182 base.error('filter returned inappropriate nil')
186 elseif last_out ~= "" then
188 if last_in then last_in = "" end
192 last_out = f(last_in)
193 if last_out == "" then
194 if last_in == "" then
197 base.error('filter returned ""')
199 elseif not last_out then
201 base.error('filter returned inappropriate nil')
213 -- Sources will be used one after the other, as if they were concatenated
214 -- (thanks to Wim Couwenberg)
215 function source.cat(...)
216 local src = table.remove(arg, 1)
219 local chunk, err = src()
220 if chunk then return chunk end
221 if err then return nil, err end
222 src = table.remove(arg, 1)
227 -----------------------------------------------------------------------------
229 -----------------------------------------------------------------------------
232 function sink.table(t)
234 local f = function(chunk, err)
235 if chunk then t[#t+1] = chunk end
241 function sink.simplify(snk)
243 return function(chunk, err)
244 local ret, err_or_new = snk(chunk, err)
245 if not ret then return nil, err_or_new end
246 snk = err_or_new or snk
251 function sink.file(handle, io_err)
253 return function(chunk, err)
257 else return handle:write(chunk) end
259 else return sink.error(io_err or "unable to open file") end
262 -- creates a sink that discards data
263 local function null()
271 function sink.error(err)
277 function sink.chain(f, snk)
278 base.assert(f and snk)
279 return function(chunk, err)
281 local filtered = f(chunk)
282 local done = chunk and ""
284 local ret, snkerr = snk(filtered, err)
285 if not ret then return nil, snkerr end
286 if filtered == done then return 1 end
293 -----------------------------------------------------------------------------
295 -----------------------------------------------------------------------------
298 function pump.step(src, snk)
299 local chunk, src_err = src()
300 local ret, snk_err = snk(chunk, src_err)
301 if chunk and ret then return 1
302 else return nil, src_err or snk_err end
305 function pump.all(src, snk, step)
306 base.assert(src and snk)
307 step = step or pump.step
309 local ret, err = step(src, snk)
311 if err then return nil, err