aboutsummaryrefslogtreecommitdiff
path: root/src/mime.c
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-19 05:41:30 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-01-19 05:41:30 +0000
commit5b8d7dec541a618b4ca7f2205470a28cde2e3e25 (patch)
tree209ad0c80c9a938068401fc5b8fa51942972418f /src/mime.c
parent6ac82d50eecdf9bf55f4234ed3a5449afd7a2992 (diff)
downloadluasocket-5b8d7dec541a618b4ca7f2205470a28cde2e3e25.tar.gz
luasocket-5b8d7dec541a618b4ca7f2205470a28cde2e3e25.tar.bz2
luasocket-5b8d7dec541a618b4ca7f2205470a28cde2e3e25.zip
Updated some of the callbacks in callback.lua.
Update get.lua to use the new callbacks. The old "code" module is now the "mime" module. Updated all modules that depended on it. Updated url.lua to use the new namespace scheme, and moved the escape and unescape functions that used to be in the code.lua module to it, since these are specific to urls. Updated the callback entries in the manual.
Diffstat (limited to 'src/mime.c')
-rw-r--r--src/mime.c614
1 files changed, 614 insertions, 0 deletions
diff --git a/src/mime.c b/src/mime.c
new file mode 100644
index 0000000..6807af5
--- /dev/null
+++ b/src/mime.c
@@ -0,0 +1,614 @@
1/*=========================================================================*\
2* Encoding support functions
3* LuaSocket toolkit
4*
5* RCS ID: $Id$
6\*=========================================================================*/
7#include <string.h>
8
9#include <lua.h>
10#include <lauxlib.h>
11
12#include "luasocket.h"
13#include "mime.h"
14
15/*=========================================================================*\
16* Don't want to trust escape character constants
17\*=========================================================================*/
18#define CR 0x0D
19#define LF 0x0A
20#define HT 0x09
21#define SP 0x20
22
23typedef unsigned char UC;
24static const UC CRLF[2] = {CR, LF};
25static const UC EQCRLF[3] = {'=', CR, LF};
26
27/*=========================================================================*\
28* Internal function prototypes.
29\*=========================================================================*/
30static int mime_global_fmt(lua_State *L);
31static int mime_global_b64(lua_State *L);
32static int mime_global_unb64(lua_State *L);
33static int mime_global_qp(lua_State *L);
34static int mime_global_unqp(lua_State *L);
35static int mime_global_qpfmt(lua_State *L);
36static int mime_global_eol(lua_State *L);
37
38static void b64fill(UC *b64unbase);
39static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
40static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
41static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
42
43static void qpfill(UC *qpclass, UC *qpunbase);
44static void qpquote(UC c, luaL_Buffer *buffer);
45static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
46static size_t qpencode(UC c, UC *input, size_t size,
47 const UC *marker, luaL_Buffer *buffer);
48
49/* code support functions */
50static luaL_reg func[] = {
51 { "eol", mime_global_eol },
52 { "qp", mime_global_qp },
53 { "unqp", mime_global_unqp },
54 { "qpfmt", mime_global_qpfmt },
55 { "b64", mime_global_b64 },
56 { "unb64", mime_global_unb64 },
57 { "fmt", mime_global_fmt },
58 { NULL, NULL }
59};
60
61/*-------------------------------------------------------------------------*\
62* Quoted-printable globals
63\*-------------------------------------------------------------------------*/
64static UC qpclass[256];
65static UC qpbase[] = "0123456789ABCDEF";
66static UC qpunbase[256];
67enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
68
69/*-------------------------------------------------------------------------*\
70* Base64 globals
71\*-------------------------------------------------------------------------*/
72static const UC b64base[] =
73 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
74static UC b64unbase[256];
75
76/*=========================================================================*\
77* Exported functions
78\*=========================================================================*/
79/*-------------------------------------------------------------------------*\
80* Initializes module
81\*-------------------------------------------------------------------------*/
82void mime_open(lua_State *L)
83{
84 lua_pushstring(L, LUASOCKET_LIBNAME);
85 lua_gettable(L, LUA_GLOBALSINDEX);
86 if (lua_isnil(L, -1)) {
87 lua_pop(L, 1);
88 lua_newtable(L);
89 lua_pushstring(L, LUASOCKET_LIBNAME);
90 lua_pushvalue(L, -2);
91 lua_settable(L, LUA_GLOBALSINDEX);
92 }
93 lua_pushstring(L, "mime");
94 lua_newtable(L);
95 luaL_openlib(L, NULL, func, 0);
96 lua_settable(L, -3);
97 lua_pop(L, 1);
98 /* initialize lookup tables */
99 qpfill(qpclass, qpunbase);
100 b64fill(b64unbase);
101}
102
103/*=========================================================================*\
104* Global Lua functions
105\*=========================================================================*/
106/*-------------------------------------------------------------------------*\
107* Incrementaly breaks a string into lines
108* A, n = fmt(B, length, left)
109* A is a copy of B, broken into lines of at most 'length' bytes.
110* Left is how many bytes are left in the first line of B. 'n' is the number
111* of bytes left in the last line of A.
112\*-------------------------------------------------------------------------*/
113static int mime_global_fmt(lua_State *L)
114{
115 size_t size = 0;
116 const UC *input = lua_isnil(L, 1)? NULL: luaL_checklstring(L, 1, &size);
117 const UC *last = input + size;
118 int length = (int) luaL_checknumber(L, 2);
119 int left = (int) luaL_optnumber(L, 3, length);
120 const UC *marker = luaL_optstring(L, 4, CRLF);
121 luaL_Buffer buffer;
122 luaL_buffinit(L, &buffer);
123 while (input < last) {
124 luaL_putchar(&buffer, *input++);
125 if (--left <= 0) {
126 luaL_addstring(&buffer, marker);
127 left = length;
128 }
129 }
130 if (!input && left < length) {
131 luaL_addstring(&buffer, marker);
132 left = length;
133 }
134 luaL_pushresult(&buffer);
135 lua_pushnumber(L, left);
136 return 2;
137}
138
139/*-------------------------------------------------------------------------*\
140* Fill base64 decode map.
141\*-------------------------------------------------------------------------*/
142static void b64fill(UC *b64unbase)
143{
144 int i;
145 for (i = 0; i < 255; i++) b64unbase[i] = 255;
146 for (i = 0; i < 64; i++) b64unbase[b64base[i]] = i;
147 b64unbase['='] = 0;
148}
149
150/*-------------------------------------------------------------------------*\
151* Acumulates bytes in input buffer until 3 bytes are available.
152* Translate the 3 bytes into Base64 form and append to buffer.
153* Returns new number of bytes in buffer.
154\*-------------------------------------------------------------------------*/
155static size_t b64encode(UC c, UC *input, size_t size,
156 luaL_Buffer *buffer)
157{
158 input[size++] = c;
159 if (size == 3) {
160 UC code[4];
161 unsigned long value = 0;
162 value += input[0]; value <<= 8;
163 value += input[1]; value <<= 8;
164 value += input[2];
165 code[3] = b64base[value & 0x3f]; value >>= 6;
166 code[2] = b64base[value & 0x3f]; value >>= 6;
167 code[1] = b64base[value & 0x3f]; value >>= 6;
168 code[0] = b64base[value];
169 luaL_addlstring(buffer, code, 4);
170 size = 0;
171 }
172 return size;
173}
174
175/*-------------------------------------------------------------------------*\
176* Encodes the Base64 last 1 or 2 bytes and adds padding '='
177* Result, if any, is appended to buffer.
178* Returns 0.
179\*-------------------------------------------------------------------------*/
180static size_t b64pad(const UC *input, size_t size,
181 luaL_Buffer *buffer)
182{
183 unsigned long value = 0;
184 UC code[4] = "====";
185 switch (size) {
186 case 1:
187 value = input[0] << 4;
188 code[1] = b64base[value & 0x3f]; value >>= 6;
189 code[0] = b64base[value];
190 luaL_addlstring(buffer, code, 4);
191 break;
192 case 2:
193 value = input[0]; value <<= 8;
194 value |= input[1]; value <<= 2;
195 code[2] = b64base[value & 0x3f]; value >>= 6;
196 code[1] = b64base[value & 0x3f]; value >>= 6;
197 code[0] = b64base[value];
198 luaL_addlstring(buffer, code, 4);
199 break;
200 case 0: /* fall through */
201 default:
202 break;
203 }
204 return 0;
205}
206
207/*-------------------------------------------------------------------------*\
208* Acumulates bytes in input buffer until 4 bytes are available.
209* Translate the 4 bytes from Base64 form and append to buffer.
210* Returns new number of bytes in buffer.
211\*-------------------------------------------------------------------------*/
212static size_t b64decode(UC c, UC *input, size_t size,
213 luaL_Buffer *buffer)
214{
215
216 /* ignore invalid characters */
217 if (b64unbase[c] > 64) return size;
218 input[size++] = c;
219 /* decode atom */
220 if (size == 4) {
221 UC decoded[3];
222 int valid, value = 0;
223 value = b64unbase[input[0]]; value <<= 6;
224 value |= b64unbase[input[1]]; value <<= 6;
225 value |= b64unbase[input[2]]; value <<= 6;
226 value |= b64unbase[input[3]];
227 decoded[2] = (UC) (value & 0xff); value >>= 8;
228 decoded[1] = (UC) (value & 0xff); value >>= 8;
229 decoded[0] = (UC) value;
230 /* take care of paddding */
231 valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
232 luaL_addlstring(buffer, decoded, valid);
233 return 0;
234 /* need more data */
235 } else return size;
236}
237
238/*-------------------------------------------------------------------------*\
239* Incrementally applies the Base64 transfer content encoding to a string
240* A, B = b64(C, D)
241* A is the encoded version of the largest prefix of C .. D that is
242* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
243* The easiest thing would be to concatenate the two strings and
244* encode the result, but we can't afford that or Lua would dupplicate
245* every chunk we received.
246\*-------------------------------------------------------------------------*/
247static int mime_global_b64(lua_State *L)
248{
249 UC atom[3];
250 size_t isize = 0, asize = 0;
251 const UC *input = luaL_checklstring(L, 1, &isize);
252 const UC *last = input + isize;
253 luaL_Buffer buffer;
254 luaL_buffinit(L, &buffer);
255 while (input < last)
256 asize = b64encode(*input++, atom, asize, &buffer);
257 input = luaL_optlstring(L, 2, NULL, &isize);
258 if (input) {
259 last = input + isize;
260 while (input < last)
261 asize = b64encode(*input++, atom, asize, &buffer);
262 } else
263 asize = b64pad(atom, asize, &buffer);
264 luaL_pushresult(&buffer);
265 lua_pushlstring(L, atom, asize);
266 return 2;
267}
268
269/*-------------------------------------------------------------------------*\
270* Incrementally removes the Base64 transfer content encoding from a string
271* A, B = b64(C, D)
272* A is the encoded version of the largest prefix of C .. D that is
273* divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
274\*-------------------------------------------------------------------------*/
275static int mime_global_unb64(lua_State *L)
276{
277 UC atom[4];
278 size_t isize = 0, asize = 0;
279 const UC *input = luaL_checklstring(L, 1, &isize);
280 const UC *last = input + isize;
281 luaL_Buffer buffer;
282 luaL_buffinit(L, &buffer);
283 while (input < last)
284 asize = b64decode(*input++, atom, asize, &buffer);
285 input = luaL_optlstring(L, 2, NULL, &isize);
286 if (input) {
287 last = input + isize;
288 while (input < last)
289 asize = b64decode(*input++, atom, asize, &buffer);
290 }
291 luaL_pushresult(&buffer);
292 lua_pushlstring(L, atom, asize);
293 return 2;
294}
295
296/*-------------------------------------------------------------------------*\
297* Quoted-printable encoding scheme
298* all (except CRLF in text) can be =XX
299* CLRL in not text must be =XX=XX
300* 33 through 60 inclusive can be plain
301* 62 through 120 inclusive can be plain
302* 9 and 32 can be plain, unless in the end of a line, where must be =XX
303* encoded lines must be no longer than 76 not counting CRLF
304* soft line-break are =CRLF
305* !"#$@[\]^`{|}~ should be =XX for EBCDIC compatibility
306* To encode one byte, we need to see the next two.
307* Worst case is when we see a space, and wonder if a CRLF is comming
308\*-------------------------------------------------------------------------*/
309/*-------------------------------------------------------------------------*\
310* Split quoted-printable characters into classes
311* Precompute reverse map for encoding
312\*-------------------------------------------------------------------------*/
313static void qpfill(UC *qpclass, UC *qpunbase)
314{
315 int i;
316 for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED;
317 for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN;
318 for (i = 62; i <= 120; i++) qpclass[i] = QP_PLAIN;
319 qpclass[HT] = QP_IF_LAST; qpclass[SP] = QP_IF_LAST;
320 qpclass['!'] = QP_QUOTED; qpclass['"'] = QP_QUOTED;
321 qpclass['#'] = QP_QUOTED; qpclass['$'] = QP_QUOTED;
322 qpclass['@'] = QP_QUOTED; qpclass['['] = QP_QUOTED;
323 qpclass['\\'] = QP_QUOTED; qpclass[']'] = QP_QUOTED;
324 qpclass['^'] = QP_QUOTED; qpclass['`'] = QP_QUOTED;
325 qpclass['{'] = QP_QUOTED; qpclass['|'] = QP_QUOTED;
326 qpclass['}'] = QP_QUOTED; qpclass['~'] = QP_QUOTED;
327 qpclass['}'] = QP_QUOTED; qpclass[CR] = QP_CR;
328 for (i = 0; i < 256; i++) qpunbase[i] = 255;
329 qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2;
330 qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5;
331 qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8;
332 qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10;
333 qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12;
334 qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13;
335 qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15;
336 qpunbase['f'] = 15;
337}
338
339/*-------------------------------------------------------------------------*\
340* Output one character in form =XX
341\*-------------------------------------------------------------------------*/
342static void qpquote(UC c, luaL_Buffer *buffer)
343{
344 luaL_putchar(buffer, '=');
345 luaL_putchar(buffer, qpbase[c >> 4]);
346 luaL_putchar(buffer, qpbase[c & 0x0F]);
347}
348
349/*-------------------------------------------------------------------------*\
350* Accumulate characters until we are sure about how to deal with them.
351* Once we are sure, output the to the buffer, in the correct form.
352\*-------------------------------------------------------------------------*/
353static size_t qpencode(UC c, UC *input, size_t size,
354 const UC *marker, luaL_Buffer *buffer)
355{
356 input[size++] = c;
357 /* deal with all characters we can have */
358 while (size > 0) {
359 switch (qpclass[input[0]]) {
360 /* might be the CR of a CRLF sequence */
361 case QP_CR:
362 if (size < 2) return size;
363 if (input[1] == LF) {
364 luaL_addstring(buffer, marker);
365 return 0;
366 } else qpquote(input[0], buffer);
367 break;
368 /* might be a space and that has to be quoted if last in line */
369 case QP_IF_LAST:
370 if (size < 3) return size;
371 /* if it is the last, quote it and we are done */
372 if (input[1] == CR && input[2] == LF) {
373 qpquote(input[0], buffer);
374 luaL_addstring(buffer, marker);
375 return 0;
376 } else luaL_putchar(buffer, input[0]);
377 break;
378 /* might have to be quoted always */
379 case QP_QUOTED:
380 qpquote(input[0], buffer);
381 break;
382 /* might never have to be quoted */
383 default:
384 luaL_putchar(buffer, input[0]);
385 break;
386 }
387 input[0] = input[1]; input[1] = input[2];
388 size--;
389 }
390 return 0;
391}
392
393/*-------------------------------------------------------------------------*\
394* Deal with the final characters
395\*-------------------------------------------------------------------------*/
396static void qppad(UC *input, size_t size, luaL_Buffer *buffer)
397{
398 size_t i;
399 for (i = 0; i < size; i++) {
400 if (qpclass[input[i]] == QP_PLAIN) luaL_putchar(buffer, input[i]);
401 else qpquote(input[i], buffer);
402 }
403 luaL_addstring(buffer, EQCRLF);
404}
405
406/*-------------------------------------------------------------------------*\
407* Incrementally converts a string to quoted-printable
408* A, B = qp(C, D, marker)
409* Crlf is the text to be used to replace CRLF sequences found in A.
410* A is the encoded version of the largest prefix of C .. D that
411* can be encoded without doubts.
412* B has the remaining bytes of C .. D, *without* encoding.
413\*-------------------------------------------------------------------------*/
414static int mime_global_qp(lua_State *L)
415{
416
417 size_t asize = 0, isize = 0;
418 UC atom[3];
419 const UC *input = lua_isnil(L, 1) ? NULL: luaL_checklstring(L, 1, &isize);
420 const UC *last = input + isize;
421 const UC *marker = luaL_optstring(L, 3, CRLF);
422 luaL_Buffer buffer;
423 luaL_buffinit(L, &buffer);
424 while (input < last)
425 asize = qpencode(*input++, atom, asize, marker, &buffer);
426 input = luaL_optlstring(L, 2, NULL, &isize);
427 if (input) {
428 last = input + isize;
429 while (input < last)
430 asize = qpencode(*input++, atom, asize, marker, &buffer);
431 } else qppad(atom, asize, &buffer);
432 luaL_pushresult(&buffer);
433 lua_pushlstring(L, atom, asize);
434 return 2;
435}
436
437/*-------------------------------------------------------------------------*\
438* Accumulate characters until we are sure about how to deal with them.
439* Once we are sure, output the to the buffer, in the correct form.
440\*-------------------------------------------------------------------------*/
441static size_t qpdecode(UC c, UC *input, size_t size,
442 luaL_Buffer *buffer)
443{
444 input[size++] = c;
445 /* deal with all characters we can deal */
446 while (size > 0) {
447 int c, d;
448 switch (input[0]) {
449 /* if we have an escape character */
450 case '=':
451 if (size < 3) return size;
452 /* eliminate soft line break */
453 if (input[1] == CR && input[2] == LF) return 0;
454 /* decode quoted representation */
455 c = qpunbase[input[1]]; d = qpunbase[input[2]];
456 /* if it is an invalid, do not decode */
457 if (c > 15 || d > 15) luaL_addlstring(buffer, input, 3);
458 else luaL_putchar(buffer, (c << 4) + d);
459 return 0;
460 case CR:
461 if (size < 2) return size;
462 if (input[1] == LF) luaL_addlstring(buffer, input, 2);
463 return 0;
464 default:
465 if (input[0] == HT || (input[0] > 31 && input[0] < 127))
466 luaL_putchar(buffer, input[0]);
467 return 0;
468 }
469 input[0] = input[1]; input[1] = input[2];
470 size--;
471 }
472 return 0;
473}
474
475/*-------------------------------------------------------------------------*\
476* Incrementally decodes a string in quoted-printable
477* A, B = qp(C, D)
478* A is the decoded version of the largest prefix of C .. D that
479* can be decoded without doubts.
480* B has the remaining bytes of C .. D, *without* decoding.
481\*-------------------------------------------------------------------------*/
482static int mime_global_unqp(lua_State *L)
483{
484
485 size_t asize = 0, isize = 0;
486 UC atom[3];
487 const UC *input = lua_isnil(L, 1) ? NULL: luaL_checklstring(L, 1, &isize);
488 const UC *last = input + isize;
489 luaL_Buffer buffer;
490 luaL_buffinit(L, &buffer);
491 while (input < last)
492 asize = qpdecode(*input++, atom, asize, &buffer);
493 input = luaL_optlstring(L, 2, NULL, &isize);
494 if (input) {
495 last = input + isize;
496 while (input < last)
497 asize = qpdecode(*input++, atom, asize, &buffer);
498 }
499 luaL_pushresult(&buffer);
500 lua_pushlstring(L, atom, asize);
501 return 2;
502}
503
504/*-------------------------------------------------------------------------*\
505* Incrementally breaks a quoted-printed string into lines
506* A, n = qpfmt(B, length, left)
507* A is a copy of B, broken into lines of at most 'length' bytes.
508* Left is how many bytes are left in the first line of B. 'n' is the number
509* of bytes left in the last line of A.
510* There are two complications: lines can't be broken in the middle
511* of an encoded =XX, and there might be line breaks already
512\*-------------------------------------------------------------------------*/
513static int mime_global_qpfmt(lua_State *L)
514{
515 size_t size = 0;
516 const UC *input = lua_isnil(L, 1)? NULL: luaL_checklstring(L, 1, &size);
517 const UC *last = input + size;
518 int length = (int) luaL_checknumber(L, 2);
519 int left = (int) luaL_optnumber(L, 3, length);
520 luaL_Buffer buffer;
521 luaL_buffinit(L, &buffer);
522 while (input < last) {
523 left--;
524 switch (*input) {
525 case '=':
526 /* if there's no room in this line for the quoted char,
527 * output a soft line break now */
528 if (left <= 3) {
529 luaL_addstring(&buffer, EQCRLF);
530 left = length;
531 }
532 break;
533 /* \r\n starts a new line */
534 case CR:
535 break;
536 case LF:
537 left = length;
538 break;
539 default:
540 /* if in last column, output a soft line break */
541 if (left <= 1) {
542 luaL_addstring(&buffer, EQCRLF);
543 left = length;
544 }
545 }
546 luaL_putchar(&buffer, *input);
547 input++;
548 }
549 if (!input && left < length) {
550 luaL_addstring(&buffer, EQCRLF);
551 left = length;
552 }
553 luaL_pushresult(&buffer);
554 lua_pushnumber(L, left);
555 return 2;
556}
557
558/*-------------------------------------------------------------------------*\
559* Here is what we do: \n, \r and \f are considered candidates for line
560* break. We issue *one* new line marker if any of them is seen alone, or
561* followed by a different one. That is, \n\n, \r\r and \f\f will issue two
562* end of line markers each, but \r\n, \n\r, \r\f etc will only issue *one*
563* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
564* probably other more obscure conventions.
565\*-------------------------------------------------------------------------*/
566#define eolcandidate(c) (c == CR || c == LF)
567static size_t eolconvert(UC c, UC *input, size_t size,
568 const UC *marker, luaL_Buffer *buffer)
569{
570 input[size++] = c;
571 /* deal with all characters we can deal */
572 if (eolcandidate(input[0])) {
573 if (size < 2) return size;
574 luaL_addstring(buffer, marker);
575 if (eolcandidate(input[1])) {
576 if (input[0] == input[1]) luaL_addstring(buffer, marker);
577 } else luaL_putchar(buffer, input[1]);
578 return 0;
579 } else {
580 luaL_putchar(buffer, input[0]);
581 return 0;
582 }
583}
584
585/*-------------------------------------------------------------------------*\
586* Converts a string to uniform EOL convention.
587* A, B = eol(C, D, marker)
588* A is the converted version of the largest prefix of C .. D that
589* can be converted without doubts.
590* B has the remaining bytes of C .. D, *without* convertion.
591\*-------------------------------------------------------------------------*/
592static int mime_global_eol(lua_State *L)
593{
594 size_t asize = 0, isize = 0;
595 UC atom[2];
596 const UC *input = lua_isnil(L, 1)? NULL: luaL_checklstring(L, 1, &isize);
597 const UC *last = input + isize;
598 const UC *marker = luaL_optstring(L, 3, CRLF);
599 luaL_Buffer buffer;
600 luaL_buffinit(L, &buffer);
601 while (input < last)
602 asize = eolconvert(*input++, atom, asize, marker, &buffer);
603 input = luaL_optlstring(L, 2, NULL, &isize);
604 if (input) {
605 last = input + isize;
606 while (input < last)
607 asize = eolconvert(*input++, atom, asize, marker, &buffer);
608 /* if there is something in atom, it's one character, and it
609 * is a candidate. so we output a new line */
610 } else if (asize > 0) luaL_addstring(&buffer, marker);
611 luaL_pushresult(&buffer);
612 lua_pushlstring(L, atom, asize);
613 return 2;
614}