beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / ltn12.lua
blobfca1cb20ffd717207e6aae38bfc094e8cdef743b
1 -----------------------------------------------------------------------------
2 -- LTN12 - Filters, sources, sinks and pumps.
3 -- LuaSocket toolkit.
4 -- Author: Diego Nehab
5 -----------------------------------------------------------------------------
7 -----------------------------------------------------------------------------
8 -- Declare module
9 -----------------------------------------------------------------------------
10 local string = require("string")
11 local table = require("table")
12 local base = _G
13 module("ltn12")
15 filter = {}
16 source = {}
17 sink = {}
18 pump = {}
20 -- 2048 seems to be better in windows...
21 BLOCKSIZE = 2048
22 _VERSION = "LTN12 1.0.2"
24 -----------------------------------------------------------------------------
25 -- Filter stuff
26 -----------------------------------------------------------------------------
27 -- returns a high level filter that cycles a low-level filter
28 function filter.cycle(low, ctx, extra)
29 base.assert(low)
30 return function(chunk)
31 local ret
32 ret, ctx = low(ctx, chunk, extra)
33 return ret
34 end
35 end
37 -- chains a bunch of filters together
38 -- (thanks to Wim Couwenberg)
39 function filter.chain(...)
40 local arg = {...}
41 local n = #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
69 -----------------------------------------------------------------------------
70 -- Source stuff
71 -----------------------------------------------------------------------------
72 -- create an empty source
73 local function empty()
74 return nil
75 end
77 function source.empty()
78 return empty
79 end
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
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
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
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
120 else return source.empty() end
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)
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)
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
158 elseif last_out ~= "" then
159 state = "eating"
160 if last_in then last_in = "" end
161 return last_out
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 ""')
171 elseif not last_out then
172 if last_in then
173 base.error('filter returned inappropriate nil')
174 else
175 return nil
177 else
178 return last_out
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 arg = {...}
190 local src = table.remove(arg, 1)
191 return function()
192 while src do
193 local chunk, err = src()
194 if chunk then return chunk end
195 if err then return nil, err end
196 src = table.remove(arg, 1)
201 -----------------------------------------------------------------------------
202 -- Sink stuff
203 -----------------------------------------------------------------------------
204 -- creates a sink that stores into a table
205 function sink.table(t)
206 t = t or {}
207 local f = function(chunk, err)
208 if chunk then table.insert(t, chunk) end
209 return 1
211 return f, t
214 -- turns a fancy sink into a simple sink
215 function sink.simplify(snk)
216 base.assert(snk)
217 return function(chunk, err)
218 local ret, err_or_new = snk(chunk, err)
219 if not ret then return nil, err_or_new end
220 snk = err_or_new or snk
221 return 1
225 -- creates a file sink
226 function sink.file(handle, io_err)
227 if handle then
228 return function(chunk, err)
229 if not chunk then
230 handle:close()
231 return 1
232 else return handle:write(chunk) end
234 else return sink.error(io_err or "unable to open file") end
237 -- creates a sink that discards data
238 local function null()
239 return 1
242 function sink.null()
243 return null
246 -- creates a sink that just returns an error
247 function sink.error(err)
248 return function()
249 return nil, err
253 -- chains a sink with a filter
254 function sink.chain(f, snk)
255 base.assert(f and snk)
256 return function(chunk, err)
257 if chunk ~= "" then
258 local filtered = f(chunk)
259 local done = chunk and ""
260 while true do
261 local ret, snkerr = snk(filtered, err)
262 if not ret then return nil, snkerr end
263 if filtered == done then return 1 end
264 filtered = f(done)
266 else return 1 end
270 -----------------------------------------------------------------------------
271 -- Pump stuff
272 -----------------------------------------------------------------------------
273 -- pumps one chunk from the source to the sink
274 function pump.step(src, snk)
275 local chunk, src_err = src()
276 local ret, snk_err = snk(chunk, src_err)
277 if chunk and ret then return 1
278 else return nil, src_err or snk_err end
281 -- pumps all data from a source to a sink, using a step function
282 function pump.all(src, snk, step)
283 base.assert(src and snk)
284 step = step or pump.step
285 while true do
286 local ret, err = step(src, snk)
287 if not ret then
288 if err then return nil, err
289 else return 1 end