diff options
| -rw-r--r-- | TODO | 6 | ||||
| -rw-r--r-- | doc/reference.html | 2 | ||||
| -rw-r--r-- | etc/eol.lua | 4 | ||||
| -rw-r--r-- | etc/qp.lua | 4 | ||||
| -rw-r--r-- | src/ltn12.lua | 171 | ||||
| -rw-r--r-- | src/luasocket.c | 2 | ||||
| -rw-r--r-- | src/mime.c | 84 | ||||
| -rw-r--r-- | src/mime.lua | 74 | ||||
| -rw-r--r-- | src/wsocket.c | 8 | ||||
| -rw-r--r-- | src/wsocket.h | 1 | ||||
| -rw-r--r-- | test/ltn12test.lua | 3 | ||||
| -rw-r--r-- | test/mimetest.lua | 93 |
12 files changed, 291 insertions, 161 deletions
| @@ -19,10 +19,16 @@ | |||
| 19 | * Separar as classes em arquivos | 19 | * Separar as classes em arquivos |
| 20 | * Retorno de sendto em datagram sockets pode ser refused | 20 | * Retorno de sendto em datagram sockets pode ser refused |
| 21 | 21 | ||
| 22 | unify filter and send/receive callback. new sink/source/pump idea. | ||
| 23 | get rid of aux_optlstring | ||
| 24 | wrap sink and sources with a function that performs the replacement | ||
| 25 | get rid of unpack in mime.lua | ||
| 22 | 26 | ||
| 23 | check garbage collection in test*.lua | 27 | check garbage collection in test*.lua |
| 24 | pop3??? | 28 | pop3??? |
| 25 | 29 | ||
| 30 | break chain into a simpler binary chain and a complex (recursive) one. | ||
| 31 | |||
| 26 | add socket.TIMEOUT to be default timeout? | 32 | add socket.TIMEOUT to be default timeout? |
| 27 | 33 | ||
| 28 | manual | 34 | manual |
diff --git a/doc/reference.html b/doc/reference.html index e6efb6e..6e14891 100644 --- a/doc/reference.html +++ b/doc/reference.html | |||
| @@ -126,7 +126,7 @@ | |||
| 126 | <a href="mime.html">MIME (socket.mime) </a> | 126 | <a href="mime.html">MIME (socket.mime) </a> |
| 127 | <blockquote> | 127 | <blockquote> |
| 128 | <a href="mime.html#high">high-level</a>: | 128 | <a href="mime.html#high">high-level</a>: |
| 129 | <a href="mime.html#decode">canonic</a>, | 129 | <a href="mime.html#normalize">normalize</a>, |
| 130 | <a href="mime.html#chain">chain</a>, | 130 | <a href="mime.html#chain">chain</a>, |
| 131 | <a href="mime.html#decode">decode</a>, | 131 | <a href="mime.html#decode">decode</a>, |
| 132 | <a href="mime.html#encode">encode</a>, | 132 | <a href="mime.html#encode">encode</a>, |
diff --git a/etc/eol.lua b/etc/eol.lua index fea5da9..6b2a8a9 100644 --- a/etc/eol.lua +++ b/etc/eol.lua | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | marker = {['-u'] = '\10', ['-d'] = '\13\10'} | 1 | marker = {['-u'] = '\10', ['-d'] = '\13\10'} |
| 2 | arg = arg or {'-u'} | 2 | arg = arg or {'-u'} |
| 3 | marker = marker[arg[1]] or marker['-u'] | 3 | marker = marker[arg[1]] or marker['-u'] |
| 4 | local convert = socket.mime.canonic(marker) | 4 | local convert = socket.mime.normalize(marker) |
| 5 | while 1 do | 5 | while 1 do |
| 6 | local chunk = io.read(4096) | 6 | local chunk = io.read(1) |
| 7 | io.write(convert(chunk)) | 7 | io.write(convert(chunk)) |
| 8 | if not chunk then break end | 8 | if not chunk then break end |
| 9 | end | 9 | end |
| @@ -2,10 +2,10 @@ local convert | |||
| 2 | arg = arg or {} | 2 | arg = arg or {} |
| 3 | local mode = arg and arg[1] or "-et" | 3 | local mode = arg and arg[1] or "-et" |
| 4 | if mode == "-et" then | 4 | if mode == "-et" then |
| 5 | local canonic = socket.mime.canonic() | 5 | local normalize = socket.mime.normalize() |
| 6 | local qp = socket.mime.encode("quoted-printable") | 6 | local qp = socket.mime.encode("quoted-printable") |
| 7 | local wrap = socket.mime.wrap("quoted-printable") | 7 | local wrap = socket.mime.wrap("quoted-printable") |
| 8 | convert = socket.mime.chain(canonic, qp, wrap) | 8 | convert = socket.mime.chain(normalize, qp, wrap) |
| 9 | elseif mode == "-eb" then | 9 | elseif mode == "-eb" then |
| 10 | local qp = socket.mime.encode("quoted-printable", "binary") | 10 | local qp = socket.mime.encode("quoted-printable", "binary") |
| 11 | local wrap = socket.mime.wrap("quoted-printable") | 11 | local wrap = socket.mime.wrap("quoted-printable") |
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 | ||
diff --git a/src/luasocket.c b/src/luasocket.c index e99fcdf..47696cb 100644 --- a/src/luasocket.c +++ b/src/luasocket.c | |||
| @@ -72,6 +72,7 @@ static int mod_open(lua_State *L, const luaL_reg *mod) | |||
| 72 | { | 72 | { |
| 73 | for (; mod->name; mod++) mod->func(L); | 73 | for (; mod->name; mod++) mod->func(L); |
| 74 | #ifdef LUASOCKET_COMPILED | 74 | #ifdef LUASOCKET_COMPILED |
| 75 | #include "ltn12.lch" | ||
| 75 | #include "auxiliar.lch" | 76 | #include "auxiliar.lch" |
| 76 | #include "concat.lch" | 77 | #include "concat.lch" |
| 77 | #include "url.lch" | 78 | #include "url.lch" |
| @@ -81,6 +82,7 @@ static int mod_open(lua_State *L, const luaL_reg *mod) | |||
| 81 | #include "ftp.lch" | 82 | #include "ftp.lch" |
| 82 | #include "http.lch" | 83 | #include "http.lch" |
| 83 | #else | 84 | #else |
| 85 | lua_dofile(L, "ltn12.lua"); | ||
| 84 | lua_dofile(L, "auxiliar.lua"); | 86 | lua_dofile(L, "auxiliar.lua"); |
| 85 | lua_dofile(L, "concat.lua"); | 87 | lua_dofile(L, "concat.lua"); |
| 86 | lua_dofile(L, "url.lua"); | 88 | lua_dofile(L, "url.lua"); |
| @@ -9,8 +9,6 @@ | |||
| 9 | #include <lua.h> | 9 | #include <lua.h> |
| 10 | #include <lauxlib.h> | 10 | #include <lauxlib.h> |
| 11 | 11 | ||
| 12 | #include "luasocket.h" | ||
| 13 | #include "auxiliar.h" | ||
| 14 | #include "mime.h" | 12 | #include "mime.h" |
| 15 | 13 | ||
| 16 | /*=========================================================================*\ | 14 | /*=========================================================================*\ |
| @@ -83,12 +81,10 @@ static UC b64unbase[256]; | |||
| 83 | \*-------------------------------------------------------------------------*/ | 81 | \*-------------------------------------------------------------------------*/ |
| 84 | int mime_open(lua_State *L) | 82 | int mime_open(lua_State *L) |
| 85 | { | 83 | { |
| 86 | lua_pushstring(L, LUASOCKET_LIBNAME); | ||
| 87 | lua_gettable(L, LUA_GLOBALSINDEX); | ||
| 88 | lua_pushstring(L, "mime"); | 84 | lua_pushstring(L, "mime"); |
| 89 | lua_newtable(L); | 85 | lua_newtable(L); |
| 90 | luaL_openlib(L, NULL, func, 0); | 86 | luaL_openlib(L, NULL, func, 0); |
| 91 | lua_settable(L, -3); | 87 | lua_settable(L, LUA_GLOBALSINDEX); |
| 92 | lua_pop(L, 1); | 88 | lua_pop(L, 1); |
| 93 | /* initialize lookup tables */ | 89 | /* initialize lookup tables */ |
| 94 | qpsetup(qpclass, qpunbase); | 90 | qpsetup(qpclass, qpunbase); |
| @@ -110,7 +106,7 @@ static int mime_global_wrp(lua_State *L) | |||
| 110 | { | 106 | { |
| 111 | size_t size = 0; | 107 | size_t size = 0; |
| 112 | int left = (int) luaL_checknumber(L, 1); | 108 | int left = (int) luaL_checknumber(L, 1); |
| 113 | const UC *input = (UC *) aux_optlstring(L, 2, NULL, &size); | 109 | const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); |
| 114 | const UC *last = input + size; | 110 | const UC *last = input + size; |
| 115 | int length = (int) luaL_optnumber(L, 3, 76); | 111 | int length = (int) luaL_optnumber(L, 3, 76); |
| 116 | luaL_Buffer buffer; | 112 | luaL_Buffer buffer; |
| @@ -261,7 +257,7 @@ static int mime_global_b64(lua_State *L) | |||
| 261 | luaL_buffinit(L, &buffer); | 257 | luaL_buffinit(L, &buffer); |
| 262 | while (input < last) | 258 | while (input < last) |
| 263 | asize = b64encode(*input++, atom, asize, &buffer); | 259 | asize = b64encode(*input++, atom, asize, &buffer); |
| 264 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); | 260 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); |
| 265 | if (input) { | 261 | if (input) { |
| 266 | last = input + isize; | 262 | last = input + isize; |
| 267 | while (input < last) | 263 | while (input < last) |
| @@ -289,7 +285,7 @@ static int mime_global_unb64(lua_State *L) | |||
| 289 | luaL_buffinit(L, &buffer); | 285 | luaL_buffinit(L, &buffer); |
| 290 | while (input < last) | 286 | while (input < last) |
| 291 | asize = b64decode(*input++, atom, asize, &buffer); | 287 | asize = b64decode(*input++, atom, asize, &buffer); |
| 292 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); | 288 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); |
| 293 | if (input) { | 289 | if (input) { |
| 294 | last = input + isize; | 290 | last = input + isize; |
| 295 | while (input < last) | 291 | while (input < last) |
| @@ -426,14 +422,14 @@ static int mime_global_qp(lua_State *L) | |||
| 426 | 422 | ||
| 427 | size_t asize = 0, isize = 0; | 423 | size_t asize = 0, isize = 0; |
| 428 | UC atom[3]; | 424 | UC atom[3]; |
| 429 | const UC *input = (UC *) aux_optlstring(L, 1, NULL, &isize); | 425 | const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); |
| 430 | const UC *last = input + isize; | 426 | const UC *last = input + isize; |
| 431 | const char *marker = luaL_optstring(L, 3, CRLF); | 427 | const char *marker = luaL_optstring(L, 3, CRLF); |
| 432 | luaL_Buffer buffer; | 428 | luaL_Buffer buffer; |
| 433 | luaL_buffinit(L, &buffer); | 429 | luaL_buffinit(L, &buffer); |
| 434 | while (input < last) | 430 | while (input < last) |
| 435 | asize = qpencode(*input++, atom, asize, marker, &buffer); | 431 | asize = qpencode(*input++, atom, asize, marker, &buffer); |
| 436 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); | 432 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); |
| 437 | if (input) { | 433 | if (input) { |
| 438 | last = input + isize; | 434 | last = input + isize; |
| 439 | while (input < last) | 435 | while (input < last) |
| @@ -495,13 +491,13 @@ static int mime_global_unqp(lua_State *L) | |||
| 495 | 491 | ||
| 496 | size_t asize = 0, isize = 0; | 492 | size_t asize = 0, isize = 0; |
| 497 | UC atom[3]; | 493 | UC atom[3]; |
| 498 | const UC *input = (UC *) aux_optlstring(L, 1, NULL, &isize); | 494 | const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); |
| 499 | const UC *last = input + isize; | 495 | const UC *last = input + isize; |
| 500 | luaL_Buffer buffer; | 496 | luaL_Buffer buffer; |
| 501 | luaL_buffinit(L, &buffer); | 497 | luaL_buffinit(L, &buffer); |
| 502 | while (input < last) | 498 | while (input < last) |
| 503 | asize = qpdecode(*input++, atom, asize, &buffer); | 499 | asize = qpdecode(*input++, atom, asize, &buffer); |
| 504 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); | 500 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); |
| 505 | if (input) { | 501 | if (input) { |
| 506 | last = input + isize; | 502 | last = input + isize; |
| 507 | while (input < last) | 503 | while (input < last) |
| @@ -525,7 +521,7 @@ static int mime_global_qpwrp(lua_State *L) | |||
| 525 | { | 521 | { |
| 526 | size_t size = 0; | 522 | size_t size = 0; |
| 527 | int left = (int) luaL_checknumber(L, 1); | 523 | int left = (int) luaL_checknumber(L, 1); |
| 528 | const UC *input = (UC *) aux_optlstring(L, 2, NULL, &size); | 524 | const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); |
| 529 | const UC *last = input + size; | 525 | const UC *last = input + size; |
| 530 | int length = (int) luaL_optnumber(L, 3, 76); | 526 | int length = (int) luaL_optnumber(L, 3, 76); |
| 531 | luaL_Buffer buffer; | 527 | luaL_Buffer buffer; |
| @@ -576,54 +572,52 @@ static int mime_global_qpwrp(lua_State *L) | |||
| 576 | * probably other more obscure conventions. | 572 | * probably other more obscure conventions. |
| 577 | \*-------------------------------------------------------------------------*/ | 573 | \*-------------------------------------------------------------------------*/ |
| 578 | #define eolcandidate(c) (c == CR || c == LF) | 574 | #define eolcandidate(c) (c == CR || c == LF) |
| 579 | static size_t eolconvert(UC c, UC *input, size_t size, | 575 | static size_t eolprocess(int c, int ctx, const char *marker, |
| 580 | const char *marker, luaL_Buffer *buffer) | 576 | luaL_Buffer *buffer) |
| 581 | { | 577 | { |
| 582 | input[size++] = c; | 578 | if (eolcandidate(ctx)) { |
| 583 | /* deal with all characters we can deal */ | ||
| 584 | if (eolcandidate(input[0])) { | ||
| 585 | if (size < 2) return size; | ||
| 586 | luaL_addstring(buffer, marker); | 579 | luaL_addstring(buffer, marker); |
| 587 | if (eolcandidate(input[1])) { | 580 | if (eolcandidate(c)) { |
| 588 | if (input[0] == input[1]) luaL_addstring(buffer, marker); | 581 | if (c == ctx) |
| 589 | } else luaL_putchar(buffer, input[1]); | 582 | luaL_addstring(buffer, marker); |
| 590 | return 0; | 583 | return 0; |
| 584 | } else { | ||
| 585 | luaL_putchar(buffer, c); | ||
| 586 | return 0; | ||
| 587 | } | ||
| 591 | } else { | 588 | } else { |
| 592 | luaL_putchar(buffer, input[0]); | 589 | if (!eolcandidate(c)) { |
| 593 | return 0; | 590 | luaL_putchar(buffer, c); |
| 591 | return 0; | ||
| 592 | } else | ||
| 593 | return c; | ||
| 594 | } | 594 | } |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | /*-------------------------------------------------------------------------*\ | 597 | /*-------------------------------------------------------------------------*\ |
| 598 | * Converts a string to uniform EOL convention. | 598 | * Converts a string to uniform EOL convention. |
| 599 | * A, B = eol(C, D, marker) | 599 | * A, n = eol(o, B, marker) |
| 600 | * A is the converted version of the largest prefix of C .. D that | 600 | * A is the converted version of the largest prefix of B that can be |
| 601 | * can be converted without doubts. | 601 | * converted unambiguously. 'o' is the context returned by the previous |
| 602 | * B has the remaining bytes of C .. D, *without* convertion. | 602 | * call. 'n' is the new context. |
| 603 | \*-------------------------------------------------------------------------*/ | 603 | \*-------------------------------------------------------------------------*/ |
| 604 | static int mime_global_eol(lua_State *L) | 604 | static int mime_global_eol(lua_State *L) |
| 605 | { | 605 | { |
| 606 | size_t asize = 0, isize = 0; | 606 | int ctx = luaL_checkint(L, 1); |
| 607 | UC atom[2]; | 607 | size_t isize = 0; |
| 608 | const UC *input = (UC *) aux_optlstring(L, 1, NULL, &isize); | 608 | const char *input = luaL_optlstring(L, 2, NULL, &isize); |
| 609 | const UC *last = input + isize; | 609 | const char *last = input + isize; |
| 610 | const char *marker = luaL_optstring(L, 3, CRLF); | 610 | const char *marker = luaL_optstring(L, 3, CRLF); |
| 611 | luaL_Buffer buffer; | 611 | luaL_Buffer buffer; |
| 612 | luaL_buffinit(L, &buffer); | 612 | luaL_buffinit(L, &buffer); |
| 613 | while (input < last) | 613 | while (input < last) |
| 614 | asize = eolconvert(*input++, atom, asize, marker, &buffer); | 614 | ctx = eolprocess(*input++, ctx, marker, &buffer); |
| 615 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); | 615 | /* if the last character was a candidate, we output a new line */ |
| 616 | if (input) { | 616 | if (!input) { |
| 617 | last = input + isize; | 617 | if (eolcandidate(ctx)) luaL_addstring(&buffer, marker); |
| 618 | while (input < last) | 618 | ctx = 0; |
| 619 | asize = eolconvert(*input++, atom, asize, marker, &buffer); | ||
| 620 | /* if there is something in atom, it's one character, and it | ||
| 621 | * is a candidate. so we output a new line */ | ||
| 622 | } else if (asize > 0) { | ||
| 623 | luaL_addstring(&buffer, marker); | ||
| 624 | asize = 0; | ||
| 625 | } | 619 | } |
| 626 | luaL_pushresult(&buffer); | 620 | luaL_pushresult(&buffer); |
| 627 | lua_pushlstring(L, (char *) atom, asize); | 621 | lua_pushnumber(L, ctx); |
| 628 | return 2; | 622 | return 2; |
| 629 | } | 623 | } |
diff --git a/src/mime.lua b/src/mime.lua index 369567f..4df0388 100644 --- a/src/mime.lua +++ b/src/mime.lua | |||
| @@ -1,11 +1,6 @@ | |||
| 1 | -- make sure LuaSocket is loaded | 1 | if not ltn12 then error('This module requires LTN12') end |
| 2 | if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end | 2 | -- create mime namespace |
| 3 | -- get LuaSocket namespace | 3 | mime = mime or {} |
| 4 | local socket = _G[LUASOCKET_LIBNAME] | ||
| 5 | if not socket then error('module requires LuaSocket') end | ||
| 6 | -- create code namespace inside LuaSocket namespace | ||
| 7 | local mime = socket.mime or {} | ||
| 8 | socket.mime = mime | ||
| 9 | -- make all module globals fall into mime namespace | 4 | -- make all module globals fall into mime namespace |
| 10 | setmetatable(mime, { __index = _G }) | 5 | setmetatable(mime, { __index = _G }) |
| 11 | setfenv(1, mime) | 6 | setfenv(1, mime) |
| @@ -15,80 +10,61 @@ local et = {} | |||
| 15 | local dt = {} | 10 | local dt = {} |
| 16 | local wt = {} | 11 | local wt = {} |
| 17 | 12 | ||
| 18 | -- creates a function that chooses a filter from a given table | 13 | -- creates a function that chooses a filter by name from a given table |
| 19 | local function choose(table) | 14 | local function choose(table) |
| 20 | return function(filter, ...) | 15 | return function(name, opt) |
| 21 | local f = table[filter or "nil"] | 16 | local f = table[name or "nil"] |
| 22 | if not f then error("unknown filter (" .. tostring(filter) .. ")", 3) | 17 | if not f then error("unknown filter (" .. tostring(name) .. ")", 3) |
| 23 | else return f(unpack(arg)) end | 18 | else return f(opt) end |
| 24 | end | 19 | end |
| 25 | end | 20 | end |
| 26 | 21 | ||
| 27 | -- define the encoding filters | 22 | -- define the encoding filters |
| 28 | et['base64'] = function() | 23 | et['base64'] = function() |
| 29 | return socket.cicle(b64, "") | 24 | return ltn12.filter.cycle(b64, "") |
| 30 | end | 25 | end |
| 31 | 26 | ||
| 32 | et['quoted-printable'] = function(mode) | 27 | et['quoted-printable'] = function(mode) |
| 33 | return socket.cicle(qp, "", (mode == "binary") and "=0D=0A" or "\13\10") | 28 | return ltn12.filter.cycle(qp, "", |
| 29 | (mode == "binary") and "=0D=0A" or "\13\10") | ||
| 34 | end | 30 | end |
| 35 | 31 | ||
| 36 | -- define the decoding filters | 32 | -- define the decoding filters |
| 37 | dt['base64'] = function() | 33 | dt['base64'] = function() |
| 38 | return socket.cicle(unb64, "") | 34 | return ltn12.filter.cycle(unb64, "") |
| 39 | end | 35 | end |
| 40 | 36 | ||
| 41 | dt['quoted-printable'] = function() | 37 | dt['quoted-printable'] = function() |
| 42 | return socket.cicle(unqp, "") | 38 | return ltn12.filter.cycle(unqp, "") |
| 43 | end | 39 | end |
| 44 | 40 | ||
| 45 | -- define the line-wrap filters | 41 | -- define the line-wrap filters |
| 46 | wt['text'] = function(length) | 42 | wt['text'] = function(length) |
| 47 | length = length or 76 | 43 | length = length or 76 |
| 48 | return socket.cicle(wrp, length, length) | 44 | return ltn12.filter.cycle(wrp, length, length) |
| 49 | end | 45 | end |
| 50 | wt['base64'] = wt['text'] | 46 | wt['base64'] = wt['text'] |
| 51 | 47 | ||
| 52 | wt['quoted-printable'] = function() | 48 | wt['quoted-printable'] = function() |
| 53 | return socket.cicle(qpwrp, 76, 76) | 49 | return ltn12.filter.cycle(qpwrp, 76, 76) |
| 54 | end | 50 | end |
| 55 | 51 | ||
| 56 | -- function that choose the encoding, decoding or wrap algorithm | 52 | -- function that choose the encoding, decoding or wrap algorithm |
| 57 | encode = choose(et) | 53 | encode = choose(et) |
| 58 | decode = choose(dt) | 54 | decode = choose(dt) |
| 59 | -- there is a default wrap filter | 55 | -- there is different because there is a default wrap filter |
| 60 | local cwt = choose(wt) | 56 | local cwt = choose(wt) |
| 61 | function wrap(...) | 57 | function wrap(mode_or_length, length) |
| 62 | if type(arg[1]) ~= "string" then table.insert(arg, 1, "text") end | 58 | if type(mode_or_length) ~= "string" then |
| 63 | return cwt(unpack(arg)) | 59 | length = mode_or_length |
| 64 | end | 60 | mode_or_length = "text" |
| 65 | 61 | end | |
| 66 | -- define the end-of-line translation filter | 62 | return cwt(mode_or_length, length) |
| 67 | function canonic(marker) | ||
| 68 | return socket.cicle(eol, "", marker) | ||
| 69 | end | 63 | end |
| 70 | 64 | ||
| 71 | -- chains several filters together | 65 | -- define the end-of-line normalization filter |
| 72 | function chain(...) | 66 | function normalize(marker) |
| 73 | local layers = table.getn(arg) | 67 | return ltn12.filter.cycle(eol, 0, marker) |
| 74 | return function (chunk) | ||
| 75 | if not chunk then | ||
| 76 | local parts = {} | ||
| 77 | for i = 1, layers do | ||
| 78 | for j = i, layers do | ||
| 79 | chunk = arg[j](chunk) | ||
| 80 | end | ||
| 81 | table.insert(parts, chunk) | ||
| 82 | chunk = nil | ||
| 83 | end | ||
| 84 | return table.concat(parts) | ||
| 85 | else | ||
| 86 | for j = 1, layers do | ||
| 87 | chunk = arg[j](chunk) | ||
| 88 | end | ||
| 89 | return chunk | ||
| 90 | end | ||
| 91 | end | ||
| 92 | end | 68 | end |
| 93 | 69 | ||
| 94 | return mime | 70 | return mime |
diff --git a/src/wsocket.c b/src/wsocket.c index fcd2fff..2993c35 100644 --- a/src/wsocket.c +++ b/src/wsocket.c | |||
| @@ -191,7 +191,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 191 | int timeout) | 191 | int timeout) |
| 192 | { | 192 | { |
| 193 | t_sock sock = *ps; | 193 | t_sock sock = *ps; |
| 194 | ssize_t put; | 194 | int put; |
| 195 | int ret; | 195 | int ret; |
| 196 | /* avoid making system calls on closed sockets */ | 196 | /* avoid making system calls on closed sockets */ |
| 197 | if (sock == SOCK_INVALID) return IO_CLOSED; | 197 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| @@ -227,7 +227,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 227 | SA *addr, socklen_t addr_len, int timeout) | 227 | SA *addr, socklen_t addr_len, int timeout) |
| 228 | { | 228 | { |
| 229 | t_sock sock = *ps; | 229 | t_sock sock = *ps; |
| 230 | ssize_t put; | 230 | int put; |
| 231 | int ret; | 231 | int ret; |
| 232 | /* avoid making system calls on closed sockets */ | 232 | /* avoid making system calls on closed sockets */ |
| 233 | if (sock == SOCK_INVALID) return IO_CLOSED; | 233 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| @@ -262,7 +262,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
| 262 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 262 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
| 263 | { | 263 | { |
| 264 | t_sock sock = *ps; | 264 | t_sock sock = *ps; |
| 265 | ssize_t taken; | 265 | int taken; |
| 266 | if (sock == SOCK_INVALID) return IO_CLOSED; | 266 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 267 | taken = recv(sock, data, (int) count, 0); | 267 | taken = recv(sock, data, (int) count, 0); |
| 268 | if (taken <= 0) { | 268 | if (taken <= 0) { |
| @@ -288,7 +288,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
| 288 | SA *addr, socklen_t *addr_len, int timeout) | 288 | SA *addr, socklen_t *addr_len, int timeout) |
| 289 | { | 289 | { |
| 290 | t_sock sock = *ps; | 290 | t_sock sock = *ps; |
| 291 | ssize_t taken; | 291 | int taken; |
| 292 | if (sock == SOCK_INVALID) return IO_CLOSED; | 292 | if (sock == SOCK_INVALID) return IO_CLOSED; |
| 293 | taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); | 293 | taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); |
| 294 | if (taken <= 0) { | 294 | if (taken <= 0) { |
diff --git a/src/wsocket.h b/src/wsocket.h index d77841e..c048c58 100644 --- a/src/wsocket.h +++ b/src/wsocket.h | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <winsock.h> | 13 | #include <winsock.h> |
| 14 | 14 | ||
| 15 | typedef int socklen_t; | 15 | typedef int socklen_t; |
| 16 | typedef int ssize_t; | ||
| 17 | typedef SOCKET t_sock; | 16 | typedef SOCKET t_sock; |
| 18 | typedef t_sock *p_sock; | 17 | typedef t_sock *p_sock; |
| 19 | 18 | ||
diff --git a/test/ltn12test.lua b/test/ltn12test.lua new file mode 100644 index 0000000..1c1f3f2 --- /dev/null +++ b/test/ltn12test.lua | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | sink = ltn12.sink.file(io.open("lixo", "w")) | ||
| 2 | source = ltn12.source.file(io.open("luasocket", "r")) | ||
| 3 | ltn12.pump(source, sink) | ||
diff --git a/test/mimetest.lua b/test/mimetest.lua index 5a461fa..1a7e427 100644 --- a/test/mimetest.lua +++ b/test/mimetest.lua | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | dofile("noglobals.lua") | 1 | dofile("testsupport.lua") |
| 2 | 2 | ||
| 3 | local qptest = "qptest.bin" | 3 | local qptest = "qptest.bin" |
| 4 | local eqptest = "qptest.bin2" | 4 | local eqptest = "qptest.bin2" |
| @@ -31,26 +31,13 @@ local mao = [[ | |||
| 31 | assim, nem tudo o que dava exprimia grande confiança. | 31 | assim, nem tudo o que dava exprimia grande confiança. |
| 32 | ]] | 32 | ]] |
| 33 | 33 | ||
| 34 | local fail = function(s) | ||
| 35 | s = s or "failed" | ||
| 36 | assert(nil, s) | ||
| 37 | end | ||
| 38 | |||
| 39 | local readfile = function(name) | ||
| 40 | local f = io.open(name, "r") | ||
| 41 | if not f then return nil end | ||
| 42 | local s = f:read("*a") | ||
| 43 | f:close() | ||
| 44 | return s | ||
| 45 | end | ||
| 46 | |||
| 47 | local function transform(input, output, filter) | 34 | local function transform(input, output, filter) |
| 48 | local fi, err = io.open(input, "rb") | 35 | local fi, err = io.open(input, "rb") |
| 49 | if not fi then fail(err) end | 36 | if not fi then fail(err) end |
| 50 | local fo, err = io.open(output, "wb") | 37 | local fo, err = io.open(output, "wb") |
| 51 | if not fo then fail(err) end | 38 | if not fo then fail(err) end |
| 52 | while 1 do | 39 | while 1 do |
| 53 | local chunk = fi:read(math.random(0, 256)) | 40 | local chunk = fi:read(math.random(0, 1024)) |
| 54 | fo:write(filter(chunk)) | 41 | fo:write(filter(chunk)) |
| 55 | if not chunk then break end | 42 | if not chunk then break end |
| 56 | end | 43 | end |
| @@ -58,17 +45,10 @@ local function transform(input, output, filter) | |||
| 58 | fo:close() | 45 | fo:close() |
| 59 | end | 46 | end |
| 60 | 47 | ||
| 61 | local function compare(input, output) | ||
| 62 | local original = readfile(input) | ||
| 63 | local recovered = readfile(output) | ||
| 64 | if original ~= recovered then fail("recovering failed") | ||
| 65 | else print("ok") end | ||
| 66 | end | ||
| 67 | |||
| 68 | local function encode_qptest(mode) | 48 | local function encode_qptest(mode) |
| 69 | local encode = socket.mime.encode("quoted-printable", mode) | 49 | local encode = mime.encode("quoted-printable", mode) |
| 70 | local split = socket.mime.wrap("quoted-printable") | 50 | local split = mime.wrap("quoted-printable") |
| 71 | local chain = socket.mime.chain(encode, split) | 51 | local chain = ltn12.filter.chain(encode, split) |
| 72 | transform(qptest, eqptest, chain) | 52 | transform(qptest, eqptest, chain) |
| 73 | end | 53 | end |
| 74 | 54 | ||
| @@ -77,7 +57,7 @@ local function compare_qptest() | |||
| 77 | end | 57 | end |
| 78 | 58 | ||
| 79 | local function decode_qptest() | 59 | local function decode_qptest() |
| 80 | local decode = socket.mime.decode("quoted-printable") | 60 | local decode = mime.decode("quoted-printable") |
| 81 | transform(eqptest, dqptest, decode) | 61 | transform(eqptest, dqptest, decode) |
| 82 | end | 62 | end |
| 83 | 63 | ||
| @@ -151,24 +131,24 @@ local function cleanup_qptest() | |||
| 151 | end | 131 | end |
| 152 | 132 | ||
| 153 | local function encode_b64test() | 133 | local function encode_b64test() |
| 154 | local e1 = socket.mime.encode("base64") | 134 | local e1 = mime.encode("base64") |
| 155 | local e2 = socket.mime.encode("base64") | 135 | local e2 = mime.encode("base64") |
| 156 | local e3 = socket.mime.encode("base64") | 136 | local e3 = mime.encode("base64") |
| 157 | local e4 = socket.mime.encode("base64") | 137 | local e4 = mime.encode("base64") |
| 158 | local sp4 = socket.mime.wrap() | 138 | local sp4 = mime.wrap() |
| 159 | local sp3 = socket.mime.wrap(59) | 139 | local sp3 = mime.wrap(59) |
| 160 | local sp2 = socket.mime.wrap("base64", 30) | 140 | local sp2 = mime.wrap("base64", 30) |
| 161 | local sp1 = socket.mime.wrap(27) | 141 | local sp1 = mime.wrap(27) |
| 162 | local chain = socket.mime.chain(e1, sp1, e2, sp2, e3, sp3, e4, sp4) | 142 | local chain = ltn12.filter.chain(e1, sp1, e2, sp2, e3, sp3, e4, sp4) |
| 163 | transform(b64test, eb64test, chain) | 143 | transform(b64test, eb64test, chain) |
| 164 | end | 144 | end |
| 165 | 145 | ||
| 166 | local function decode_b64test() | 146 | local function decode_b64test() |
| 167 | local d1 = socket.mime.decode("base64") | 147 | local d1 = mime.decode("base64") |
| 168 | local d2 = socket.mime.decode("base64") | 148 | local d2 = mime.decode("base64") |
| 169 | local d3 = socket.mime.decode("base64") | 149 | local d3 = mime.decode("base64") |
| 170 | local d4 = socket.mime.decode("base64") | 150 | local d4 = mime.decode("base64") |
| 171 | local chain = socket.mime.chain(d1, d2, d3, d4) | 151 | local chain = ltn12.filter.chain(d1, d2, d3, d4) |
| 172 | transform(eb64test, db64test, chain) | 152 | transform(eb64test, db64test, chain) |
| 173 | end | 153 | end |
| 174 | 154 | ||
| @@ -182,11 +162,11 @@ local function compare_b64test() | |||
| 182 | end | 162 | end |
| 183 | 163 | ||
| 184 | local function identity_test() | 164 | local function identity_test() |
| 185 | local chain = socket.mime.chain( | 165 | local chain = ltn12.filter.chain( |
| 186 | socket.mime.encode("quoted-printable"), | 166 | mime.encode("quoted-printable"), |
| 187 | socket.mime.encode("base64"), | 167 | mime.encode("base64"), |
| 188 | socket.mime.decode("base64"), | 168 | mime.decode("base64"), |
| 189 | socket.mime.decode("quoted-printable") | 169 | mime.decode("quoted-printable") |
| 190 | ) | 170 | ) |
| 191 | transform(b64test, eb64test, chain) | 171 | transform(b64test, eb64test, chain) |
| 192 | compare(b64test, eb64test) | 172 | compare(b64test, eb64test) |
| @@ -195,8 +175,8 @@ end | |||
| 195 | 175 | ||
| 196 | 176 | ||
| 197 | local function padcheck(original, encoded) | 177 | local function padcheck(original, encoded) |
| 198 | local e = (socket.mime.b64(original)) | 178 | local e = (mime.b64(original)) |
| 199 | local d = (socket.mime.unb64(encoded)) | 179 | local d = (mime.unb64(encoded)) |
| 200 | if e ~= encoded then fail("encoding failed") end | 180 | if e ~= encoded then fail("encoding failed") end |
| 201 | if d ~= original then fail("decoding failed") end | 181 | if d ~= original then fail("decoding failed") end |
| 202 | end | 182 | end |
| @@ -206,8 +186,8 @@ local function chunkcheck(original, encoded) | |||
| 206 | for i = 0, len do | 186 | for i = 0, len do |
| 207 | local a = string.sub(original, 1, i) | 187 | local a = string.sub(original, 1, i) |
| 208 | local b = string.sub(original, i+1) | 188 | local b = string.sub(original, i+1) |
| 209 | local e, r = socket.mime.b64(a, b) | 189 | local e, r = mime.b64(a, b) |
| 210 | local f = (socket.mime.b64(r)) | 190 | local f = (mime.b64(r)) |
| 211 | if (e .. f ~= encoded) then fail(e .. f) end | 191 | if (e .. f ~= encoded) then fail(e .. f) end |
| 212 | end | 192 | end |
| 213 | end | 193 | end |
| @@ -231,6 +211,13 @@ end | |||
| 231 | 211 | ||
| 232 | local t = socket.time() | 212 | local t = socket.time() |
| 233 | 213 | ||
| 214 | identity_test() | ||
| 215 | encode_b64test() | ||
| 216 | decode_b64test() | ||
| 217 | compare_b64test() | ||
| 218 | cleanup_b64test() | ||
| 219 | padding_b64test() | ||
| 220 | |||
| 234 | create_qptest() | 221 | create_qptest() |
| 235 | encode_qptest() | 222 | encode_qptest() |
| 236 | decode_qptest() | 223 | decode_qptest() |
| @@ -240,12 +227,4 @@ decode_qptest() | |||
| 240 | compare_qptest() | 227 | compare_qptest() |
| 241 | cleanup_qptest() | 228 | cleanup_qptest() |
| 242 | 229 | ||
| 243 | encode_b64test() | ||
| 244 | decode_b64test() | ||
| 245 | compare_b64test() | ||
| 246 | cleanup_b64test() | ||
| 247 | padding_b64test() | ||
| 248 | |||
| 249 | identity_test() | ||
| 250 | |||
| 251 | print(string.format("done in %.2fs", socket.time() - t)) | 230 | print(string.format("done in %.2fs", socket.time() - t)) |
