* libs/core: Moved ltn12 inside LuCI to avoid package conflicts with luasocket
[project/luci.git] / libs / core / luasrc / ltn12.lua
1 --[[
2 LuaSocket 2.0.2 license
3 Copyright � 2004-2007 Diego Nehab
4
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:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
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.
22 ]]--
23 -----------------------------------------------------------------------------
24 -- LTN12 - Filters, sources, sinks and pumps.
25 -- LuaSocket toolkit.
26 -- Author: Diego Nehab
27 -- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $
28 -----------------------------------------------------------------------------
29
30 -----------------------------------------------------------------------------
31 -- Declare module
32 -----------------------------------------------------------------------------
33 local string = require("string")
34 local table = require("table")
35 local base = _G
36 module("luci.ltn12")
37
38 filter = {}
39 source = {}
40 sink = {}
41 pump = {}
42
43 -- 2048 seems to be better in windows...
44 BLOCKSIZE = 2048
45 _VERSION = "LTN12 1.0.1"
46
47 -----------------------------------------------------------------------------
48 -- Filter stuff
49 -----------------------------------------------------------------------------
50 -- returns a high level filter that cycles a low-level filter
51 function filter.cycle(low, ctx, extra)
52 base.assert(low)
53 return function(chunk)
54 local ret
55 ret, ctx = low(ctx, chunk, extra)
56 return ret
57 end
58 end
59
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
65 local retry = ""
66 return function(chunk)
67 retry = chunk and retry
68 while true do
69 if index == top then
70 chunk = arg[index](chunk)
71 if chunk == "" or top == n then return chunk
72 elseif chunk then index = index + 1
73 else
74 top = top+1
75 index = top
76 end
77 else
78 chunk = arg[index](chunk or "")
79 if chunk == "" then
80 index = index - 1
81 chunk = retry
82 elseif chunk then
83 if index == n then return chunk
84 else index = index + 1 end
85 else base.error("filter returned inappropriate nil") end
86 end
87 end
88 end
89 end
90
91 -----------------------------------------------------------------------------
92 -- Source stuff
93 -----------------------------------------------------------------------------
94 -- create an empty source
95 local function empty()
96 return nil
97 end
98
99 function source.empty()
100 return empty
101 end
102
103 -- returns a source that just outputs an error
104 function source.error(err)
105 return function()
106 return nil, err
107 end
108 end
109
110 -- creates a file source
111 function source.file(handle, io_err)
112 if handle then
113 return function()
114 local chunk = handle:read(BLOCKSIZE)
115 if not chunk then handle:close() end
116 return chunk
117 end
118 else return source.error(io_err or "unable to open file") end
119 end
120
121 -- turns a fancy source into a simple source
122 function source.simplify(src)
123 base.assert(src)
124 return function()
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
129 end
130 end
131
132 -- creates string source
133 function source.string(s)
134 if s then
135 local i = 1
136 return function()
137 local chunk = string.sub(s, i, i+BLOCKSIZE-1)
138 i = i + BLOCKSIZE
139 if chunk ~= "" then return chunk
140 else return nil end
141 end
142 else return source.empty() end
143 end
144
145 -- creates rewindable source
146 function source.rewind(src)
147 base.assert(src)
148 local t = {}
149 return function(chunk)
150 if not chunk then
151 chunk = table.remove(t)
152 if not chunk then return src()
153 else return chunk end
154 else
155 table.insert(t, chunk)
156 end
157 end
158 end
159
160 function source.chain(src, f)
161 base.assert(src and f)
162 local last_in, last_out = "", ""
163 local state = "feeding"
164 local err
165 return function()
166 if not last_out then
167 base.error('source is empty!', 2)
168 end
169 while true do
170 if state == "feeding" then
171 last_in, err = src()
172 if err then return nil, err end
173 last_out = f(last_in)
174 if not last_out then
175 if last_in then
176 base.error('filter returned inappropriate nil')
177 else
178 return nil
179 end
180 elseif last_out ~= "" then
181 state = "eating"
182 if last_in then last_in = "" end
183 return last_out
184 end
185 else
186 last_out = f(last_in)
187 if last_out == "" then
188 if last_in == "" then
189 state = "feeding"
190 else
191 base.error('filter returned ""')
192 end
193 elseif not last_out then
194 if last_in then
195 base.error('filter returned inappropriate nil')
196 else
197 return nil
198 end
199 else
200 return last_out
201 end
202 end
203 end
204 end
205 end
206
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)
212 return function()
213 while src do
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)
218 end
219 end
220 end
221
222 -----------------------------------------------------------------------------
223 -- Sink stuff
224 -----------------------------------------------------------------------------
225 -- creates a sink that stores into a table
226 function sink.table(t)
227 t = t or {}
228 local f = function(chunk, err)
229 if chunk then table.insert(t, chunk) end
230 return 1
231 end
232 return f, t
233 end
234
235 -- turns a fancy sink into a simple sink
236 function sink.simplify(snk)
237 base.assert(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
242 return 1
243 end
244 end
245
246 -- creates a file sink
247 function sink.file(handle, io_err)
248 if handle then
249 return function(chunk, err)
250 if not chunk then
251 handle:close()
252 return 1
253 else return handle:write(chunk) end
254 end
255 else return sink.error(io_err or "unable to open file") end
256 end
257
258 -- creates a sink that discards data
259 local function null()
260 return 1
261 end
262
263 function sink.null()
264 return null
265 end
266
267 -- creates a sink that just returns an error
268 function sink.error(err)
269 return function()
270 return nil, err
271 end
272 end
273
274 -- chains a sink with a filter
275 function sink.chain(f, snk)
276 base.assert(f and snk)
277 return function(chunk, err)
278 if chunk ~= "" then
279 local filtered = f(chunk)
280 local done = chunk and ""
281 while true do
282 local ret, snkerr = snk(filtered, err)
283 if not ret then return nil, snkerr end
284 if filtered == done then return 1 end
285 filtered = f(done)
286 end
287 else return 1 end
288 end
289 end
290
291 -----------------------------------------------------------------------------
292 -- Pump stuff
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
300 end
301
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
306 while true do
307 local ret, err = step(src, snk)
308 if not ret then
309 if err then return nil, err
310 else return 1 end
311 end
312 end
313 end
314