diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-02-11 03:31:53 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-02-11 03:31:53 +0000 |
commit | 390846b640ee7013d51a766b4b2472bdcfbbdfcc (patch) | |
tree | 3bedd023a0a84feb714615245b58eab5ffb4309b /src/ltn12.lua | |
parent | 0b2542d1a61fc5425ff65ab3dbf7ba7de174763f (diff) | |
download | luasocket-390846b640ee7013d51a766b4b2472bdcfbbdfcc.tar.gz luasocket-390846b640ee7013d51a766b4b2472bdcfbbdfcc.tar.bz2 luasocket-390846b640ee7013d51a766b4b2472bdcfbbdfcc.zip |
Added ltn12 module. Modified mime to be stand alone.
Still crashes on invalid input. Dunno why.
Diffstat (limited to 'src/ltn12.lua')
-rw-r--r-- | src/ltn12.lua | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/ltn12.lua b/src/ltn12.lua new file mode 100644 index 0000000..548588a --- /dev/null +++ b/src/ltn12.lua | |||
@@ -0,0 +1,171 @@ | |||
1 | -- create code namespace inside LuaSocket namespace | ||
2 | ltn12 = ltn12 or {} | ||
3 | -- make all module globals fall into mime namespace | ||
4 | setmetatable(ltn12, { __index = _G }) | ||
5 | setfenv(1, ltn12) | ||
6 | |||
7 | -- sub namespaces | ||
8 | filter = {} | ||
9 | source = {} | ||
10 | sink = {} | ||
11 | |||
12 | -- 2048 seems to be better in windows... | ||
13 | BLOCKSIZE = 2048 | ||
14 | |||
15 | -- returns a high level filter that cycles a cycles a low-level filter | ||
16 | function filter.cycle(low, ctx, extra) | ||
17 | return function(chunk) | ||
18 | local ret | ||
19 | ret, ctx = low(ctx, chunk, extra) | ||
20 | return ret | ||
21 | end | ||
22 | end | ||
23 | |||
24 | -- chains two filters together | ||
25 | local function chain2(f1, f2) | ||
26 | return function(chunk) | ||
27 | local ret = f2(f1(chunk)) | ||
28 | if chunk then return ret | ||
29 | else return ret .. f2() end | ||
30 | end | ||
31 | end | ||
32 | |||
33 | -- chains a bunch of filters together | ||
34 | function filter.chain(...) | ||
35 | local f = arg[1] | ||
36 | for i = 2, table.getn(arg) do | ||
37 | f = chain2(f, arg[i]) | ||
38 | end | ||
39 | return f | ||
40 | end | ||
41 | |||
42 | -- create an empty source | ||
43 | function source.empty(err) | ||
44 | return function() | ||
45 | return nil, err | ||
46 | end | ||
47 | end | ||
48 | |||
49 | -- creates a file source | ||
50 | function source.file(handle, io_err) | ||
51 | if handle then | ||
52 | return function() | ||
53 | local chunk = handle:read(BLOCKSIZE) | ||
54 | if not chunk then handle:close() end | ||
55 | return chunk | ||
56 | end | ||
57 | else source.empty(io_err or "unable to open file") end | ||
58 | end | ||
59 | |||
60 | -- turns a fancy source into a simple source | ||
61 | function source.simplify(src) | ||
62 | return function() | ||
63 | local chunk, err_or_new = src() | ||
64 | src = err_or_new or src | ||
65 | if not chunk then return nil, err_or_new | ||
66 | else return chunk end | ||
67 | end | ||
68 | end | ||
69 | |||
70 | -- creates string source | ||
71 | function source.string(s) | ||
72 | if s then | ||
73 | local i = 1 | ||
74 | return function() | ||
75 | local chunk = string.sub(s, i, i+BLOCKSIZE-1) | ||
76 | i = i + BLOCKSIZE | ||
77 | if chunk ~= "" then return chunk | ||
78 | else return nil end | ||
79 | end | ||
80 | else source.empty() end | ||
81 | end | ||
82 | |||
83 | -- creates rewindable source | ||
84 | function source.rewind(src) | ||
85 | local t = {} | ||
86 | src = source.simplify(src) | ||
87 | return function(chunk) | ||
88 | if not chunk then | ||
89 | chunk = table.remove(t) | ||
90 | if not chunk then return src() | ||
91 | else return chunk end | ||
92 | else | ||
93 | table.insert(t, chunk) | ||
94 | end | ||
95 | end | ||
96 | end | ||
97 | |||
98 | -- chains a source with a filter | ||
99 | function source.chain(src, f) | ||
100 | src = source.simplify(src) | ||
101 | local chain = function() | ||
102 | local chunk, err = src() | ||
103 | if not chunk then return f(nil), source.empty(err) | ||
104 | else return f(chunk) end | ||
105 | end | ||
106 | return source.simplify(chain) | ||
107 | end | ||
108 | |||
109 | -- creates a sink that stores into a table | ||
110 | function sink.table(t) | ||
111 | t = t or {} | ||
112 | local f = function(chunk, err) | ||
113 | if chunk then table.insert(t, chunk) end | ||
114 | return 1 | ||
115 | end | ||
116 | return f, t | ||
117 | end | ||
118 | |||
119 | -- turns a fancy sink into a simple sink | ||
120 | function sink.simplify(snk) | ||
121 | return function(chunk, err) | ||
122 | local ret, err_or_new = snk(chunk, err) | ||
123 | if not ret then return nil, err_or_new end | ||
124 | snk = err_or_new or snk | ||
125 | return 1 | ||
126 | end | ||
127 | end | ||
128 | |||
129 | -- creates a file sink | ||
130 | function sink.file(handle, io_err) | ||
131 | if handle then | ||
132 | return function(chunk, err) | ||
133 | if not chunk then | ||
134 | handle:close() | ||
135 | return nil, err | ||
136 | end | ||
137 | return handle:write(chunk) | ||
138 | end | ||
139 | else sink.null() end | ||
140 | end | ||
141 | |||
142 | -- creates a sink that discards data | ||
143 | local function null() | ||
144 | return 1 | ||
145 | end | ||
146 | |||
147 | function sink.null() | ||
148 | return null | ||
149 | end | ||
150 | |||
151 | -- chains a sink with a filter | ||
152 | function sink.chain(f, snk) | ||
153 | snk = sink.simplify(snk) | ||
154 | return function(chunk, err) | ||
155 | local r, e = snk(f(chunk)) | ||
156 | if not r then return nil, e end | ||
157 | if not chunk then return snk(nil, err) end | ||
158 | return 1 | ||
159 | end | ||
160 | end | ||
161 | |||
162 | -- pumps all data from a source to a sink | ||
163 | function pump(src, snk) | ||
164 | snk = sink.simplify(snk) | ||
165 | for chunk, src_err in source.simplify(src) do | ||
166 | local ret, snk_err = snk(chunk, src_err) | ||
167 | if not chunk or not ret then | ||
168 | return not src_err and not snk_err, src_err or snk_err | ||
169 | end | ||
170 | end | ||
171 | end | ||