Mercurial > luasocket
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 |