comparison src/ltn12.lua @ 0:4b915342e2a8

LuaSocket 2.0.2 + CMake build description.
author Eric Wing <ewing . public |-at-| gmail . com>
date Tue, 26 Aug 2008 18:40:01 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4b915342e2a8
1 -----------------------------------------------------------------------------
2 -- LTN12 - Filters, sources, sinks and pumps.
3 -- LuaSocket toolkit.
4 -- Author: Diego Nehab
5 -- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $
6 -----------------------------------------------------------------------------
7
8 -----------------------------------------------------------------------------
9 -- Declare module
10 -----------------------------------------------------------------------------
11 local string = require("string")
12 local table = require("table")
13 local base = _G
14 module("ltn12")
15
16 filter = {}
17 source = {}
18 sink = {}
19 pump = {}
20
21 -- 2048 seems to be better in windows...
22 BLOCKSIZE = 2048
23 _VERSION = "LTN12 1.0.1"
24
25 -----------------------------------------------------------------------------
26 -- Filter stuff
27 -----------------------------------------------------------------------------
28 -- returns a high level filter that cycles a low-level filter
29 function filter.cycle(low, ctx, extra)
30 base.assert(low)
31 return function(chunk)
32 local ret
33 ret, ctx = low(ctx, chunk, extra)
34 return ret
35 end
36 end
37
38 -- chains a bunch of filters together
39 -- (thanks to Wim Couwenberg)
40 function filter.chain(...)
41 local n = table.getn(arg)
42 local top, index = 1, 1
43 local retry = ""
44 return function(chunk)
45 retry = chunk and retry
46 while true do
47 if index == top then
48 chunk = arg[index](chunk)
49 if chunk == "" or top == n then return chunk
50 elseif chunk then index = index + 1
51 else
52 top = top+1
53 index = top
54 end
55 else
56 chunk = arg[index](chunk or "")
57 if chunk == "" then
58 index = index - 1
59 chunk = retry
60 elseif chunk then
61 if index == n then return chunk
62 else index = index + 1 end
63 else base.error("filter returned inappropriate nil") end
64 end
65 end
66 end
67 end
68
69 -----------------------------------------------------------------------------
70 -- Source stuff
71 -----------------------------------------------------------------------------
72 -- create an empty source
73 local function empty()
74 return nil
75 end
76
77 function source.empty()
78 return empty
79 end
80
81 -- returns a source that just outputs an error
82 function source.error(err)
83 return function()
84 return nil, err
85 end
86 end
87
88 -- creates a file source
89 function source.file(handle, io_err)
90 if handle then
91 return function()
92 local chunk = handle:read(BLOCKSIZE)
93 if not chunk then handle:close() end
94 return chunk
95 end
96 else return source.error(io_err or "unable to open file") end
97 end
98
99 -- turns a fancy source into a simple source
100 function source.simplify(src)
101 base.assert(src)
102 return function()
103 local chunk, err_or_new = src()
104 src = err_or_new or src
105 if not chunk then return nil, err_or_new
106 else return chunk end
107 end
108 end
109
110 -- creates string source
111 function source.string(s)
112 if s then
113 local i = 1
114 return function()
115 local chunk = string.sub(s, i, i+BLOCKSIZE-1)
116 i = i + BLOCKSIZE
117 if chunk ~= "" then return chunk
118 else return nil end
119 end
120 else return source.empty() end
121 end
122
123 -- creates rewindable source
124 function source.rewind(src)
125 base.assert(src)
126 local t = {}
127 return function(chunk)
128 if not chunk then
129 chunk = table.remove(t)
130 if not chunk then return src()
131 else return chunk end
132 else
133 table.insert(t, chunk)
134 end
135 end
136 end
137
138 function source.chain(src, f)
139 base.assert(src and f)
140 local last_in, last_out = "", ""
141 local state = "feeding"
142 local err
143 return function()
144 if not last_out then
145 base.error('source is empty!', 2)
146 end
147 while true do
148 if state == "feeding" then
149 last_in, err = src()
150 if err then return nil, err end
151 last_out = f(last_in)
152 if not last_out then
153 if last_in then
154 base.error('filter returned inappropriate nil')
155 else
156 return nil
157 end
158 elseif last_out ~= "" then
159 state = "eating"
160 if last_in then last_in = "" end
161 return last_out
162 end
163 else
164 last_out = f(last_in)
165 if last_out == "" then
166 if last_in == "" then
167 state = "feeding"
168 else
169 base.error('filter returned ""')
170 end
171 elseif not last_out then
172 if last_in then
173 base.error('filter returned inappropriate nil')
174 else
175 return nil
176 end
177 else
178 return last_out
179 end
180 end
181 end
182 end
183 end
184
185 -- creates a source that produces contents of several sources, one after the
186 -- other, as if they were concatenated
187 -- (thanks to Wim Couwenberg)
188 function source.cat(...)
189 local src = table.remove(arg, 1)
190 return function()
191 while src do
192 local chunk, err = src()
193 if chunk then return chunk end
194 if err then return nil, err end
195 src = table.remove(arg, 1)
196 end
197 end
198 end
199
200 -----------------------------------------------------------------------------
201 -- Sink stuff
202 -----------------------------------------------------------------------------
203 -- creates a sink that stores into a table
204 function sink.table(t)
205 t = t or {}
206 local f = function(chunk, err)
207 if chunk then table.insert(t, chunk) end
208 return 1
209 end
210 return f, t
211 end
212
213 -- turns a fancy sink into a simple sink
214 function sink.simplify(snk)
215 base.assert(snk)
216 return function(chunk, err)
217 local ret, err_or_new = snk(chunk, err)
218 if not ret then return nil, err_or_new end
219 snk = err_or_new or snk
220 return 1
221 end
222 end
223
224 -- creates a file sink
225 function sink.file(handle, io_err)
226 if handle then
227 return function(chunk, err)
228 if not chunk then
229 handle:close()
230 return 1
231 else return handle:write(chunk) end
232 end
233 else return sink.error(io_err or "unable to open file") end
234 end
235
236 -- creates a sink that discards data
237 local function null()
238 return 1
239 end
240
241 function sink.null()
242 return null
243 end
244
245 -- creates a sink that just returns an error
246 function sink.error(err)
247 return function()
248 return nil, err
249 end
250 end
251
252 -- chains a sink with a filter
253 function sink.chain(f, snk)
254 base.assert(f and snk)
255 return function(chunk, err)
256 if chunk ~= "" then
257 local filtered = f(chunk)
258 local done = chunk and ""
259 while true do
260 local ret, snkerr = snk(filtered, err)
261 if not ret then return nil, snkerr end
262 if filtered == done then return 1 end
263 filtered = f(done)
264 end
265 else return 1 end
266 end
267 end
268
269 -----------------------------------------------------------------------------
270 -- Pump stuff
271 -----------------------------------------------------------------------------
272 -- pumps one chunk from the source to the sink
273 function pump.step(src, snk)
274 local chunk, src_err = src()
275 local ret, snk_err = snk(chunk, src_err)
276 if chunk and ret then return 1
277 else return nil, src_err or snk_err end
278 end
279
280 -- pumps all data from a source to a sink, using a step function
281 function pump.all(src, snk, step)
282 base.assert(src and snk)
283 step = step or pump.step
284 while true do
285 local ret, err = step(src, snk)
286 if not ret then
287 if err then return nil, err
288 else return 1 end
289 end
290 end
291 end
292