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.
23 -----------------------------------------------------------------------------
24 -- LTN12 - Filters, sources, sinks and pumps.
26 -- Author: Diego Nehab
27 -- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $
28 -----------------------------------------------------------------------------
30 -----------------------------------------------------------------------------
32 -----------------------------------------------------------------------------
33 local string = require("string")
34 local table = require("table")
43 -- 2048 seems to be better in windows...
45 _VERSION = "LTN12 1.0.1"
47 -----------------------------------------------------------------------------
49 -----------------------------------------------------------------------------
50 -- returns a high level filter that cycles a low-level filter
51 function filter.cycle(low, ctx, extra)
53 return function(chunk)
55 ret, ctx = low(ctx, chunk, extra)
60 -- chains a bunch of filters together
61 -- (thanks to Wim Couwenberg)
62 function filter.chain(...)
63 local n = table.getn(arg)
64 local top, index = 1, 1
66 return function(chunk)
67 retry = chunk and retry
70 chunk = arg[index](chunk)
71 if chunk == "" or top == n then return chunk
72 elseif chunk then index = index + 1
78 chunk = arg[index](chunk or "")
83 if index == n then return chunk
84 else index = index + 1 end
85 else base.error("filter returned inappropriate nil") end
91 -----------------------------------------------------------------------------
93 -----------------------------------------------------------------------------
94 -- create an empty source
95 local function empty()
99 function source.empty()
103 -- returns a source that just outputs an error
104 function source.error(err)
110 -- creates a file source
111 function source.file(handle, io_err)
114 local chunk = handle:read(BLOCKSIZE)
115 if not chunk then handle:close() end
118 else return source.error(io_err or "unable to open file") end
121 -- turns a fancy source into a simple source
122 function source.simplify(src)
125 local chunk, err_or_new = src()
126 src = err_or_new or src
127 if not chunk then return nil, err_or_new
128 else return chunk end
132 -- creates string source
133 function source.string(s)
137 local chunk = string.sub(s, i, i+BLOCKSIZE-1)
139 if chunk ~= "" then return chunk
142 else return source.empty() end
145 -- creates rewindable source
146 function source.rewind(src)
149 return function(chunk)
151 chunk = table.remove(t)
152 if not chunk then return src()
153 else return chunk end
155 table.insert(t, chunk)
160 function source.chain(src, f)
161 base.assert(src and f)
162 local last_in, last_out = "", ""
163 local state = "feeding"
167 base.error('source is empty!', 2)
170 if state == "feeding" then
172 if err then return nil, err end
173 last_out = f(last_in)
176 base.error('filter returned inappropriate nil')
180 elseif last_out ~= "" then
182 if last_in then last_in = "" end
186 last_out = f(last_in)
187 if last_out == "" then
188 if last_in == "" then
191 base.error('filter returned ""')
193 elseif not last_out then
195 base.error('filter returned inappropriate nil')
207 -- creates a source that produces contents of several sources, one after the
208 -- other, as if they were concatenated
209 -- (thanks to Wim Couwenberg)
210 function source.cat(...)
211 local src = table.remove(arg, 1)
214 local chunk, err = src()
215 if chunk then return chunk end
216 if err then return nil, err end
217 src = table.remove(arg, 1)
222 -----------------------------------------------------------------------------
224 -----------------------------------------------------------------------------
225 -- creates a sink that stores into a table
226 function sink.table(t)
228 local f = function(chunk, err)
229 if chunk then table.insert(t, chunk) end
235 -- turns a fancy sink into a simple sink
236 function sink.simplify(snk)
238 return function(chunk, err)
239 local ret, err_or_new = snk(chunk, err)
240 if not ret then return nil, err_or_new end
241 snk = err_or_new or snk
246 -- creates a file sink
247 function sink.file(handle, io_err)
249 return function(chunk, err)
253 else return handle:write(chunk) end
255 else return sink.error(io_err or "unable to open file") end
258 -- creates a sink that discards data
259 local function null()
267 -- creates a sink that just returns an error
268 function sink.error(err)
274 -- chains a sink with a filter
275 function sink.chain(f, snk)
276 base.assert(f and snk)
277 return function(chunk, err)
279 local filtered = f(chunk)
280 local done = chunk and ""
282 local ret, snkerr = snk(filtered, err)
283 if not ret then return nil, snkerr end
284 if filtered == done then return 1 end
291 -----------------------------------------------------------------------------
293 -----------------------------------------------------------------------------
294 -- pumps one chunk from the source to the sink
295 function pump.step(src, snk)
296 local chunk, src_err = src()
297 local ret, snk_err = snk(chunk, src_err)
298 if chunk and ret then return 1
299 else return nil, src_err or snk_err end
302 -- pumps all data from a source to a sink, using a step function
303 function pump.all(src, snk, step)
304 base.assert(src and snk)
305 step = step or pump.step
307 local ret, err = step(src, snk)
309 if err then return nil, err