summaryrefslogtreecommitdiff
path: root/src/lib_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_io.c')
-rw-r--r--src/lib_io.c538
1 files changed, 538 insertions, 0 deletions
diff --git a/src/lib_io.c b/src/lib_io.c
new file mode 100644
index 00000000..01623258
--- /dev/null
+++ b/src/lib_io.c
@@ -0,0 +1,538 @@
1/*
2** I/O library.
3** Copyright (C) 2005-2009 Mike Pall. See Copyright Notice in luajit.h
4**
5** Major portions taken verbatim or adapted from the Lua interpreter.
6** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7*/
8
9#include <errno.h>
10#include <stdio.h>
11
12#define lib_io_c
13#define LUA_LIB
14
15#include "lua.h"
16#include "lauxlib.h"
17#include "lualib.h"
18
19#include "lj_obj.h"
20#include "lj_err.h"
21#include "lj_gc.h"
22#include "lj_ff.h"
23#include "lj_lib.h"
24
25/* Index of standard handles in function environment. */
26#define IO_INPUT 1
27#define IO_OUTPUT 2
28
29/* -- Error handling ------------------------------------------------------ */
30
31static int io_pushresult(lua_State *L, int ok, const char *fname)
32{
33 if (ok) {
34 setboolV(L->top++, 1);
35 return 1;
36 } else {
37 int en = errno; /* Lua API calls may change this value. */
38 lua_pushnil(L);
39 if (fname)
40 lua_pushfstring(L, "%s: %s", fname, strerror(en));
41 else
42 lua_pushfstring(L, "%s", strerror(en));
43 lua_pushinteger(L, en);
44 return 3;
45 }
46}
47
48static void io_file_error(lua_State *L, int arg, const char *fname)
49{
50 lua_pushfstring(L, "%s: %s", fname, strerror(errno));
51 luaL_argerror(L, arg, lua_tostring(L, -1));
52}
53
54/* -- Open helpers -------------------------------------------------------- */
55
56#define io_tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
57
58static FILE *io_tofile(lua_State *L)
59{
60 FILE **f = io_tofilep(L);
61 if (*f == NULL)
62 lj_err_caller(L, LJ_ERR_IOCLFL);
63 return *f;
64}
65
66static FILE **io_file_new(lua_State *L)
67{
68 FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
69 *pf = NULL;
70 luaL_getmetatable(L, LUA_FILEHANDLE);
71 lua_setmetatable(L, -2);
72 return pf;
73}
74
75/* -- Close helpers ------------------------------------------------------- */
76
77static int lj_cf_io_std_close(lua_State *L)
78{
79 lua_pushnil(L);
80 lua_pushliteral(L, "cannot close standard file");
81 return 2;
82}
83
84static int lj_cf_io_pipe_close(lua_State *L)
85{
86 FILE **p = io_tofilep(L);
87#if defined(LUA_USE_POSIX)
88 int ok = (pclose(*p) != -1);
89#elif defined(LUA_USE_WIN)
90 int ok = (_pclose(*p) != -1);
91#else
92 int ok = 0;
93#endif
94 *p = NULL;
95 return io_pushresult(L, ok, NULL);
96}
97
98static int lj_cf_io_file_close(lua_State *L)
99{
100 FILE **p = io_tofilep(L);
101 int ok = (fclose(*p) == 0);
102 *p = NULL;
103 return io_pushresult(L, ok, NULL);
104}
105
106static int io_file_close(lua_State *L)
107{
108 lua_getfenv(L, 1);
109 lua_getfield(L, -1, "__close");
110 return (lua_tocfunction(L, -1))(L);
111}
112
113/* -- Read/write helpers -------------------------------------------------- */
114
115static int io_file_readnum(lua_State *L, FILE *fp)
116{
117 lua_Number d;
118 if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) {
119 lua_pushnumber(L, d);
120 return 1;
121 } else {
122 return 0; /* read fails */
123 }
124}
125
126static int test_eof(lua_State *L, FILE *fp)
127{
128 int c = getc(fp);
129 ungetc(c, fp);
130 lua_pushlstring(L, NULL, 0);
131 return (c != EOF);
132}
133
134static int io_file_readline(lua_State *L, FILE *fp)
135{
136 luaL_Buffer b;
137 luaL_buffinit(L, &b);
138 for (;;) {
139 size_t len;
140 char *p = luaL_prepbuffer(&b);
141 if (fgets(p, LUAL_BUFFERSIZE, fp) == NULL) { /* EOF? */
142 luaL_pushresult(&b);
143 return (strV(L->top-1)->len > 0); /* Anything read? */
144 }
145 len = strlen(p);
146 if (len == 0 || p[len-1] != '\n') { /* Partial line? */
147 luaL_addsize(&b, len);
148 } else {
149 luaL_addsize(&b, len - 1); /* Don't include EOL. */
150 luaL_pushresult(&b);
151 return 1; /* Got at least an EOL. */
152 }
153 }
154}
155
156static int io_file_readchars(lua_State *L, FILE *fp, size_t n)
157{
158 size_t rlen; /* how much to read */
159 size_t nr; /* number of chars actually read */
160 luaL_Buffer b;
161 luaL_buffinit(L, &b);
162 rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
163 do {
164 char *p = luaL_prepbuffer(&b);
165 if (rlen > n) rlen = n; /* cannot read more than asked */
166 nr = fread(p, 1, rlen, fp);
167 luaL_addsize(&b, nr);
168 n -= nr; /* still have to read `n' chars */
169 } while (n > 0 && nr == rlen); /* until end of count or eof */
170 luaL_pushresult(&b); /* close buffer */
171 return (n == 0 || lua_objlen(L, -1) > 0);
172}
173
174static int io_file_read(lua_State *L, FILE *fp, int start)
175{
176 int ok, n, nargs = (L->top - L->base) - start;
177 clearerr(fp);
178 if (nargs == 0) {
179 ok = io_file_readline(L, fp);
180 n = start+1; /* Return 1 result. */
181 } else {
182 /* The results plus the buffers go on top of the args. */
183 luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
184 ok = 1;
185 for (n = start; nargs-- && ok; n++) {
186 if (tvisstr(L->base+n)) {
187 const char *p = strVdata(L->base+n);
188 if (p[0] != '*')
189 lj_err_arg(L, n+1, LJ_ERR_INVOPT);
190 if (p[1] == 'n')
191 ok = io_file_readnum(L, fp);
192 else if (p[1] == 'l')
193 ok = io_file_readline(L, fp);
194 else if (p[1] == 'a')
195 io_file_readchars(L, fp, ~((size_t)0));
196 else
197 lj_err_arg(L, n+1, LJ_ERR_INVFMT);
198 } else if (tvisnum(L->base+n)) {
199 size_t len = (size_t)lj_lib_checkint(L, n+1);
200 ok = len ? io_file_readchars(L, fp, len) : test_eof(L, fp);
201 } else {
202 lj_err_arg(L, n+1, LJ_ERR_INVOPT);
203 }
204 }
205 }
206 if (ferror(fp))
207 return io_pushresult(L, 0, NULL);
208 if (!ok)
209 setnilV(L->top-1); /* Replace last result with nil. */
210 return n - start;
211}
212
213static int io_file_write(lua_State *L, FILE *fp, int start)
214{
215 cTValue *tv;
216 int status = 1;
217 for (tv = L->base+start; tv < L->top; tv++) {
218 if (tvisstr(tv)) {
219 MSize len = strV(tv)->len;
220 status = status && (fwrite(strVdata(tv), 1, len, fp) == len);
221 } else if (tvisnum(tv)) {
222 status = status && (fprintf(fp, LUA_NUMBER_FMT, numV(tv)) > 0);
223 } else {
224 lj_lib_checkstr(L, tv-L->base+1);
225 }
226 }
227 return io_pushresult(L, status, NULL);
228}
229
230/* -- I/O file methods ---------------------------------------------------- */
231
232#define LJLIB_MODULE_io_method
233
234LJLIB_CF(io_method_close)
235{
236 if (lua_isnone(L, 1))
237 lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
238 io_tofile(L);
239 return io_file_close(L);
240}
241
242LJLIB_CF(io_method_read)
243{
244 return io_file_read(L, io_tofile(L), 1);
245}
246
247LJLIB_CF(io_method_write)
248{
249 return io_file_write(L, io_tofile(L), 1);
250}
251
252LJLIB_CF(io_method_flush)
253{
254 return io_pushresult(L, fflush(io_tofile(L)) == 0, NULL);
255}
256
257LJLIB_CF(io_method_seek)
258{
259 FILE *fp = io_tofile(L);
260 int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end");
261 lua_Number ofs;
262 int res;
263 if (opt == 0) opt = SEEK_SET;
264 else if (opt == 1) opt = SEEK_CUR;
265 else if (opt == 2) opt = SEEK_END;
266 lj_lib_opt(L, 3,
267 ofs = lj_lib_checknum(L, 3);
268 ,
269 ofs = 0;
270 )
271#if defined(LUA_USE_POSIX)
272 res = fseeko(fp, (int64_t)ofs, opt);
273#elif _MSC_VER >= 1400
274 res = _fseeki64(fp, (int64_t)ofs, opt);
275#elif defined(__MINGW32__)
276 res = fseeko64(fp, (int64_t)ofs, opt);
277#else
278 res = fseek(fp, (long)ofs, opt);
279#endif
280 if (res)
281 return io_pushresult(L, 0, NULL);
282#if defined(LUA_USE_POSIX)
283 ofs = cast_num(ftello(fp));
284#elif _MSC_VER >= 1400
285 ofs = cast_num(_ftelli64(fp));
286#elif defined(__MINGW32__)
287 ofs = cast_num(ftello64(fp));
288#else
289 ofs = cast_num(ftell(fp));
290#endif
291 setnumV(L->top-1, ofs);
292 return 1;
293}
294
295LJLIB_CF(io_method_setvbuf)
296{
297 FILE *fp = io_tofile(L);
298 int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no");
299 size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE);
300 if (opt == 0) opt = _IOFBF;
301 else if (opt == 1) opt = _IOLBF;
302 else if (opt == 2) opt = _IONBF;
303 return io_pushresult(L, (setvbuf(fp, NULL, opt, sz) == 0), NULL);
304}
305
306/* Forward declaration. */
307static void io_file_lines(lua_State *L, int idx, int toclose);
308
309LJLIB_CF(io_method_lines)
310{
311 io_tofile(L);
312 io_file_lines(L, 1, 0);
313 return 1;
314}
315
316LJLIB_CF(io_method___gc)
317{
318 FILE *fp = *io_tofilep(L);
319 if (fp != NULL) io_file_close(L);
320 return 0;
321}
322
323LJLIB_CF(io_method___tostring)
324{
325 FILE *fp = *io_tofilep(L);
326 if (fp == NULL)
327 lua_pushliteral(L, "file (closed)");
328 else
329 lua_pushfstring(L, "file (%p)", fp);
330 return 1;
331}
332
333LJLIB_PUSH(top-1) LJLIB_SET(__index)
334
335#include "lj_libdef.h"
336
337/* -- I/O library functions ----------------------------------------------- */
338
339#define LJLIB_MODULE_io
340
341LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
342
343static FILE *io_file_get(lua_State *L, int findex)
344{
345 GCtab *fenv = tabref(curr_func(L)->c.env);
346 GCudata *ud = udataV(&tvref(fenv->array)[findex]);
347 FILE *fp = *(FILE **)uddata(ud);
348 if (fp == NULL)
349 lj_err_caller(L, LJ_ERR_IOSTDCL);
350 return fp;
351}
352
353LJLIB_CF(io_open)
354{
355 const char *fname = luaL_checkstring(L, 1);
356 const char *mode = luaL_optstring(L, 2, "r");
357 FILE **pf = io_file_new(L);
358 *pf = fopen(fname, mode);
359 return (*pf == NULL) ? io_pushresult(L, 0, fname) : 1;
360}
361
362LJLIB_CF(io_tmpfile)
363{
364 FILE **pf = io_file_new(L);
365 *pf = tmpfile();
366 return (*pf == NULL) ? io_pushresult(L, 0, NULL) : 1;
367}
368
369LJLIB_CF(io_close)
370{
371 return lj_cf_io_method_close(L);
372}
373
374LJLIB_CF(io_read)
375{
376 return io_file_read(L, io_file_get(L, IO_INPUT), 0);
377}
378
379LJLIB_CF(io_write)
380{
381 return io_file_write(L, io_file_get(L, IO_OUTPUT), 0);
382}
383
384LJLIB_CF(io_flush)
385{
386 return io_pushresult(L, fflush(io_file_get(L, IO_OUTPUT)) == 0, NULL);
387}
388
389LJLIB_NOREG LJLIB_CF(io_lines_iter)
390{
391 FILE *fp = *(FILE **)uddata(udataV(lj_lib_upvalue(L, 1)));
392 int ok;
393 if (fp == NULL)
394 lj_err_caller(L, LJ_ERR_IOCLFL);
395 ok = io_file_readline(L, fp);
396 if (ferror(fp))
397 return luaL_error(L, "%s", strerror(errno));
398 if (ok)
399 return 1;
400 if (tvistrue(lj_lib_upvalue(L, 2))) { /* Need to close file? */
401 L->top = L->base+1;
402 setudataV(L, L->base, udataV(lj_lib_upvalue(L, 1)));
403 io_file_close(L);
404 }
405 return 0;
406}
407
408static void io_file_lines(lua_State *L, int idx, int toclose)
409{
410 lua_pushvalue(L, idx);
411 lua_pushboolean(L, toclose);
412 lua_pushcclosure(L, lj_cf_io_lines_iter, 2);
413 funcV(L->top-1)->c.ffid = FF_io_lines_iter;
414}
415
416LJLIB_CF(io_lines)
417{
418 if (lua_isnoneornil(L, 1)) { /* no arguments? */
419 /* will iterate over default input */
420 lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
421 return lj_cf_io_method_lines(L);
422 } else {
423 const char *fname = luaL_checkstring(L, 1);
424 FILE **pf = io_file_new(L);
425 *pf = fopen(fname, "r");
426 if (*pf == NULL)
427 io_file_error(L, 1, fname);
428 io_file_lines(L, lua_gettop(L), 1);
429 return 1;
430 }
431}
432
433static int io_std_get(lua_State *L, int fp, const char *mode)
434{
435 if (!lua_isnoneornil(L, 1)) {
436 const char *fname = lua_tostring(L, 1);
437 if (fname) {
438 FILE **pf = io_file_new(L);
439 *pf = fopen(fname, mode);
440 if (*pf == NULL)
441 io_file_error(L, 1, fname);
442 } else {
443 io_tofile(L); /* check that it's a valid file handle */
444 lua_pushvalue(L, 1);
445 }
446 lua_rawseti(L, LUA_ENVIRONINDEX, fp);
447 }
448 /* return current value */
449 lua_rawgeti(L, LUA_ENVIRONINDEX, fp);
450 return 1;
451}
452
453LJLIB_CF(io_input)
454{
455 return io_std_get(L, IO_INPUT, "r");
456}
457
458LJLIB_CF(io_output)
459{
460 return io_std_get(L, IO_OUTPUT, "w");
461}
462
463LJLIB_CF(io_type)
464{
465 void *ud;
466 luaL_checkany(L, 1);
467 ud = lua_touserdata(L, 1);
468 lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
469 if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
470 lua_pushnil(L); /* not a file */
471 else if (*((FILE **)ud) == NULL)
472 lua_pushliteral(L, "closed file");
473 else
474 lua_pushliteral(L, "file");
475 return 1;
476}
477
478LJLIB_PUSH(top-3) LJLIB_SET(!) /* Set environment. */
479
480LJLIB_CF(io_popen)
481{
482#if defined(LUA_USE_POSIX) || defined(LUA_USE_WIN)
483 const char *fname = luaL_checkstring(L, 1);
484 const char *mode = luaL_optstring(L, 2, "r");
485 FILE **pf = io_file_new(L);
486#ifdef LUA_USE_POSIX
487 fflush(NULL);
488 *pf = popen(fname, mode);
489#else
490 *pf = _popen(fname, mode);
491#endif
492 return (*pf == NULL) ? io_pushresult(L, 0, fname) : 1;
493#else
494 luaL_error(L, LUA_QL("popen") " not supported");
495#endif
496}
497
498#include "lj_libdef.h"
499
500/* ------------------------------------------------------------------------ */
501
502static void io_std_new(lua_State *L, FILE *fp, int k, const char *fname)
503{
504 FILE **pf = io_file_new(L);
505 GCudata *ud = udataV(L->top-1);
506 GCtab *envt = tabV(L->top-2);
507 *pf = fp;
508 setgcref(ud->env, obj2gco(envt));
509 lj_gc_objbarrier(L, obj2gco(ud), envt);
510 if (k > 0) {
511 lua_pushvalue(L, -1);
512 lua_rawseti(L, -5, k);
513 }
514 lua_setfield(L, -3, fname);
515}
516
517static void io_fenv_new(lua_State *L, int narr, lua_CFunction cls)
518{
519 lua_createtable(L, narr, 1);
520 lua_pushcfunction(L, cls);
521 lua_setfield(L, -2, "__close");
522}
523
524LUALIB_API int luaopen_io(lua_State *L)
525{
526 LJ_LIB_REG_(L, NULL, io_method);
527 lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
528 io_fenv_new(L, 0, lj_cf_io_pipe_close); /* top-3 */
529 io_fenv_new(L, 2, lj_cf_io_file_close); /* top-2 */
530 LJ_LIB_REG(L, io);
531 io_fenv_new(L, 0, lj_cf_io_std_close);
532 io_std_new(L, stdin, IO_INPUT, "stdin");
533 io_std_new(L, stdout, IO_OUTPUT, "stdout");
534 io_std_new(L, stderr, 0, "stderr");
535 lua_pop(L, 1);
536 return 1;
537}
538