diff options
Diffstat (limited to 'src/lib_io.c')
-rw-r--r-- | src/lib_io.c | 405 |
1 files changed, 190 insertions, 215 deletions
diff --git a/src/lib_io.c b/src/lib_io.c index aefe4213..d69b99a4 100644 --- a/src/lib_io.c +++ b/src/lib_io.c | |||
@@ -17,14 +17,28 @@ | |||
17 | #include "lualib.h" | 17 | #include "lualib.h" |
18 | 18 | ||
19 | #include "lj_obj.h" | 19 | #include "lj_obj.h" |
20 | #include "lj_err.h" | ||
21 | #include "lj_gc.h" | 20 | #include "lj_gc.h" |
21 | #include "lj_err.h" | ||
22 | #include "lj_str.h" | ||
22 | #include "lj_ff.h" | 23 | #include "lj_ff.h" |
24 | #include "lj_trace.h" | ||
23 | #include "lj_lib.h" | 25 | #include "lj_lib.h" |
24 | 26 | ||
25 | /* Index of standard handles in function environment. */ | 27 | /* Userdata payload for I/O file. */ |
26 | #define IO_INPUT 1 | 28 | typedef struct IOFileUD { |
27 | #define IO_OUTPUT 2 | 29 | FILE *fp; /* File handle. */ |
30 | uint32_t type; /* File type. */ | ||
31 | } IOFileUD; | ||
32 | |||
33 | #define IOFILE_TYPE_FILE 0 /* Regular file. */ | ||
34 | #define IOFILE_TYPE_PIPE 1 /* Pipe. */ | ||
35 | #define IOFILE_TYPE_STDF 2 /* Standard file handle. */ | ||
36 | #define IOFILE_TYPE_MASK 3 | ||
37 | |||
38 | #define IOFILE_FLAG_CLOSE 4 /* Close after io.lines() iterator. */ | ||
39 | |||
40 | #define IOSTDF_UD(L, id) (&gcref(G(L)->gcroot[(id)])->ud) | ||
41 | #define IOSTDF_IOF(L, id) ((IOFileUD *)uddata(IOSTDF_UD(L, (id)))) | ||
28 | 42 | ||
29 | /* -- Error handling ------------------------------------------------------ */ | 43 | /* -- Error handling ------------------------------------------------------ */ |
30 | 44 | ||
@@ -35,95 +49,102 @@ static int io_pushresult(lua_State *L, int ok, const char *fname) | |||
35 | return 1; | 49 | return 1; |
36 | } else { | 50 | } else { |
37 | int en = errno; /* Lua API calls may change this value. */ | 51 | int en = errno; /* Lua API calls may change this value. */ |
38 | lua_pushnil(L); | 52 | setnilV(L->top++); |
39 | if (fname) | 53 | if (fname) |
40 | lua_pushfstring(L, "%s: %s", fname, strerror(en)); | 54 | lua_pushfstring(L, "%s: %s", fname, strerror(en)); |
41 | else | 55 | else |
42 | lua_pushfstring(L, "%s", strerror(en)); | 56 | lua_pushfstring(L, "%s", strerror(en)); |
43 | lua_pushinteger(L, en); | 57 | setintV(L->top++, en); |
58 | lj_trace_abort(G(L)); | ||
44 | return 3; | 59 | return 3; |
45 | } | 60 | } |
46 | } | 61 | } |
47 | 62 | ||
48 | static void io_file_error(lua_State *L, int arg, const char *fname) | 63 | /* -- Open/close helpers -------------------------------------------------- */ |
64 | |||
65 | static IOFileUD *io_tofilep(lua_State *L) | ||
49 | { | 66 | { |
50 | lua_pushfstring(L, "%s: %s", fname, strerror(errno)); | 67 | if (!(L->base < L->top && tvisudata(L->base) && |
51 | luaL_argerror(L, arg, lua_tostring(L, -1)); | 68 | udataV(L->base)->udtype == UDTYPE_IO_FILE)) |
69 | lj_err_argtype(L, 1, "FILE*"); | ||
70 | return (IOFileUD *)uddata(udataV(L->base)); | ||
52 | } | 71 | } |
53 | 72 | ||
54 | /* -- Open helpers -------------------------------------------------------- */ | 73 | static IOFileUD *io_tofile(lua_State *L) |
55 | |||
56 | #define io_tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) | ||
57 | |||
58 | static FILE *io_tofile(lua_State *L) | ||
59 | { | 74 | { |
60 | FILE **f = io_tofilep(L); | 75 | IOFileUD *iof = io_tofilep(L); |
61 | if (*f == NULL) | 76 | if (iof->fp == NULL) |
62 | lj_err_caller(L, LJ_ERR_IOCLFL); | 77 | lj_err_caller(L, LJ_ERR_IOCLFL); |
63 | return *f; | 78 | return iof; |
64 | } | 79 | } |
65 | 80 | ||
66 | static FILE **io_file_new(lua_State *L) | 81 | static FILE *io_stdfile(lua_State *L, ptrdiff_t id) |
67 | { | 82 | { |
68 | FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); | 83 | IOFileUD *iof = IOSTDF_IOF(L, id); |
69 | *pf = NULL; | 84 | if (iof->fp == NULL) |
70 | luaL_getmetatable(L, LUA_FILEHANDLE); | 85 | lj_err_caller(L, LJ_ERR_IOSTDCL); |
71 | lua_setmetatable(L, -2); | 86 | return iof->fp; |
72 | return pf; | ||
73 | } | 87 | } |
74 | 88 | ||
75 | /* -- Close helpers ------------------------------------------------------- */ | 89 | static IOFileUD *io_file_new(lua_State *L) |
90 | { | ||
91 | IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); | ||
92 | GCudata *ud = udataV(L->top-1); | ||
93 | ud->udtype = UDTYPE_IO_FILE; | ||
94 | /* NOBARRIER: The GCudata is new (marked white). */ | ||
95 | setgcrefr(ud->metatable, curr_func(L)->c.env); | ||
96 | iof->fp = NULL; | ||
97 | iof->type = IOFILE_TYPE_FILE; | ||
98 | return iof; | ||
99 | } | ||
76 | 100 | ||
77 | static int lj_cf_io_std_close(lua_State *L) | 101 | static IOFileUD *io_file_open(lua_State *L, const char *mode) |
78 | { | 102 | { |
79 | lua_pushnil(L); | 103 | const char *fname = strdata(lj_lib_checkstr(L, 1)); |
80 | lua_pushliteral(L, "cannot close standard file"); | 104 | IOFileUD *iof = io_file_new(L); |
81 | return 2; | 105 | iof->fp = fopen(fname, mode); |
106 | if (iof->fp == NULL) | ||
107 | luaL_argerror(L, 1, lj_str_pushf(L, "%s: %s", fname, strerror(errno))); | ||
108 | return iof; | ||
82 | } | 109 | } |
83 | 110 | ||
84 | static int lj_cf_io_pipe_close(lua_State *L) | 111 | static int io_file_close(lua_State *L, IOFileUD *iof) |
85 | { | 112 | { |
86 | FILE **p = io_tofilep(L); | 113 | int ok; |
114 | if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_FILE) { | ||
115 | ok = (fclose(iof->fp) == 0); | ||
116 | } else if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_PIPE) { | ||
87 | #if defined(LUA_USE_POSIX) | 117 | #if defined(LUA_USE_POSIX) |
88 | int ok = (pclose(*p) != -1); | 118 | ok = (pclose(iof->fp) != -1); |
89 | #elif defined(LUA_USE_WIN) | 119 | #elif defined(LUA_USE_WIN) |
90 | int ok = (_pclose(*p) != -1); | 120 | ok = (_pclose(iof->fp) != -1); |
91 | #else | 121 | #else |
92 | int ok = 0; | 122 | ok = 0; |
93 | #endif | 123 | #endif |
94 | *p = NULL; | 124 | } else { |
95 | return io_pushresult(L, ok, NULL); | 125 | lua_assert((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF); |
96 | } | 126 | setnilV(L->top++); |
97 | 127 | lua_pushliteral(L, "cannot close standard file"); | |
98 | static int lj_cf_io_file_close(lua_State *L) | 128 | return 2; |
99 | { | 129 | } |
100 | FILE **p = io_tofilep(L); | 130 | iof->fp = NULL; |
101 | int ok = (fclose(*p) == 0); | ||
102 | *p = NULL; | ||
103 | return io_pushresult(L, ok, NULL); | 131 | return io_pushresult(L, ok, NULL); |
104 | } | 132 | } |
105 | 133 | ||
106 | static 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 -------------------------------------------------- */ | 134 | /* -- Read/write helpers -------------------------------------------------- */ |
114 | 135 | ||
115 | static int io_file_readnum(lua_State *L, FILE *fp) | 136 | static int io_file_readnum(lua_State *L, FILE *fp) |
116 | { | 137 | { |
117 | lua_Number d; | 138 | lua_Number d; |
118 | if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) { | 139 | if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) { |
119 | lua_pushnumber(L, d); | 140 | setnumV(L->top++, d); |
120 | return 1; | 141 | return 1; |
121 | } else { | 142 | } else { |
122 | return 0; /* read fails */ | 143 | return 0; |
123 | } | 144 | } |
124 | } | 145 | } |
125 | 146 | ||
126 | static int test_eof(lua_State *L, FILE *fp) | 147 | static int io_file_testeof(lua_State *L, FILE *fp) |
127 | { | 148 | { |
128 | int c = getc(fp); | 149 | int c = getc(fp); |
129 | ungetc(c, fp); | 150 | ungetc(c, fp); |
@@ -168,7 +189,7 @@ static int io_file_readchars(lua_State *L, FILE *fp, size_t n) | |||
168 | n -= nr; /* still have to read `n' chars */ | 189 | n -= nr; /* still have to read `n' chars */ |
169 | } while (n > 0 && nr == rlen); /* until end of count or eof */ | 190 | } while (n > 0 && nr == rlen); /* until end of count or eof */ |
170 | luaL_pushresult(&b); /* close buffer */ | 191 | luaL_pushresult(&b); /* close buffer */ |
171 | return (n == 0 || lua_objlen(L, -1) > 0); | 192 | return (n == 0 || strV(L->top-1)->len > 0); |
172 | } | 193 | } |
173 | 194 | ||
174 | static int io_file_read(lua_State *L, FILE *fp, int start) | 195 | static int io_file_read(lua_State *L, FILE *fp, int start) |
@@ -197,7 +218,7 @@ static int io_file_read(lua_State *L, FILE *fp, int start) | |||
197 | lj_err_arg(L, n+1, LJ_ERR_INVFMT); | 218 | lj_err_arg(L, n+1, LJ_ERR_INVFMT); |
198 | } else if (tvisnum(L->base+n)) { | 219 | } else if (tvisnum(L->base+n)) { |
199 | size_t len = (size_t)lj_lib_checkint(L, n+1); | 220 | size_t len = (size_t)lj_lib_checkint(L, n+1); |
200 | ok = len ? io_file_readchars(L, fp, len) : test_eof(L, fp); | 221 | ok = len ? io_file_readchars(L, fp, len) : io_file_testeof(L, fp); |
201 | } else { | 222 | } else { |
202 | lj_err_arg(L, n+1, LJ_ERR_INVOPT); | 223 | lj_err_arg(L, n+1, LJ_ERR_INVOPT); |
203 | } | 224 | } |
@@ -233,30 +254,29 @@ static int io_file_write(lua_State *L, FILE *fp, int start) | |||
233 | 254 | ||
234 | LJLIB_CF(io_method_close) | 255 | LJLIB_CF(io_method_close) |
235 | { | 256 | { |
236 | if (lua_isnone(L, 1)) | 257 | IOFileUD *iof = L->base < L->top ? io_tofile(L) : |
237 | lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); | 258 | IOSTDF_IOF(L, GCROOT_IO_OUTPUT); |
238 | io_tofile(L); | 259 | return io_file_close(L, iof); |
239 | return io_file_close(L); | ||
240 | } | 260 | } |
241 | 261 | ||
242 | LJLIB_CF(io_method_read) | 262 | LJLIB_CF(io_method_read) |
243 | { | 263 | { |
244 | return io_file_read(L, io_tofile(L), 1); | 264 | return io_file_read(L, io_tofile(L)->fp, 1); |
245 | } | 265 | } |
246 | 266 | ||
247 | LJLIB_CF(io_method_write) | 267 | LJLIB_CF(io_method_write) LJLIB_REC(io_write 0) |
248 | { | 268 | { |
249 | return io_file_write(L, io_tofile(L), 1); | 269 | return io_file_write(L, io_tofile(L)->fp, 1); |
250 | } | 270 | } |
251 | 271 | ||
252 | LJLIB_CF(io_method_flush) | 272 | LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0) |
253 | { | 273 | { |
254 | return io_pushresult(L, fflush(io_tofile(L)) == 0, NULL); | 274 | return io_pushresult(L, fflush(io_tofile(L)->fp) == 0, NULL); |
255 | } | 275 | } |
256 | 276 | ||
257 | LJLIB_CF(io_method_seek) | 277 | LJLIB_CF(io_method_seek) |
258 | { | 278 | { |
259 | FILE *fp = io_tofile(L); | 279 | FILE *fp = io_tofile(L)->fp; |
260 | int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end"); | 280 | int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end"); |
261 | lua_Number ofs; | 281 | lua_Number ofs; |
262 | int res; | 282 | int res; |
@@ -294,39 +314,40 @@ LJLIB_CF(io_method_seek) | |||
294 | 314 | ||
295 | LJLIB_CF(io_method_setvbuf) | 315 | LJLIB_CF(io_method_setvbuf) |
296 | { | 316 | { |
297 | FILE *fp = io_tofile(L); | 317 | FILE *fp = io_tofile(L)->fp; |
298 | int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no"); | 318 | int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no"); |
299 | size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE); | 319 | size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE); |
300 | if (opt == 0) opt = _IOFBF; | 320 | if (opt == 0) opt = _IOFBF; |
301 | else if (opt == 1) opt = _IOLBF; | 321 | else if (opt == 1) opt = _IOLBF; |
302 | else if (opt == 2) opt = _IONBF; | 322 | else if (opt == 2) opt = _IONBF; |
303 | return io_pushresult(L, (setvbuf(fp, NULL, opt, sz) == 0), NULL); | 323 | return io_pushresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL); |
304 | } | 324 | } |
305 | 325 | ||
306 | /* Forward declaration. */ | 326 | LJLIB_PUSH(top-2) /* io_lines_iter */ |
307 | static void io_file_lines(lua_State *L, int idx, int toclose); | ||
308 | |||
309 | LJLIB_CF(io_method_lines) | 327 | LJLIB_CF(io_method_lines) |
310 | { | 328 | { |
311 | io_tofile(L); | 329 | io_tofile(L); |
312 | io_file_lines(L, 1, 0); | 330 | setfuncV(L, L->top, funcV(lj_lib_upvalue(L, 1))); |
313 | return 1; | 331 | setudataV(L, L->top+1, udataV(L->base)); |
332 | L->top += 2; | ||
333 | return 2; | ||
314 | } | 334 | } |
315 | 335 | ||
316 | LJLIB_CF(io_method___gc) | 336 | LJLIB_CF(io_method___gc) |
317 | { | 337 | { |
318 | FILE *fp = *io_tofilep(L); | 338 | IOFileUD *iof = io_tofilep(L); |
319 | if (fp != NULL) io_file_close(L); | 339 | if (iof->fp != NULL) |
340 | io_file_close(L, iof); | ||
320 | return 0; | 341 | return 0; |
321 | } | 342 | } |
322 | 343 | ||
323 | LJLIB_CF(io_method___tostring) | 344 | LJLIB_CF(io_method___tostring) |
324 | { | 345 | { |
325 | FILE *fp = *io_tofilep(L); | 346 | IOFileUD *iof = io_tofilep(L); |
326 | if (fp == NULL) | 347 | if (iof->fp != NULL) |
327 | lua_pushliteral(L, "file (closed)"); | 348 | lua_pushfstring(L, "file (%p)", iof->fp); |
328 | else | 349 | else |
329 | lua_pushfstring(L, "file (%p)", fp); | 350 | lua_pushliteral(L, "file (closed)"); |
330 | return 1; | 351 | return 1; |
331 | } | 352 | } |
332 | 353 | ||
@@ -340,30 +361,41 @@ LJLIB_PUSH(top-1) LJLIB_SET(__index) | |||
340 | 361 | ||
341 | LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */ | 362 | LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */ |
342 | 363 | ||
343 | static FILE *io_file_get(lua_State *L, int findex) | 364 | LJLIB_CF(io_open) |
344 | { | 365 | { |
345 | GCtab *fenv = tabref(curr_func(L)->c.env); | 366 | const char *fname = strdata(lj_lib_checkstr(L, 1)); |
346 | GCudata *ud = udataV(&tvref(fenv->array)[findex]); | 367 | GCstr *s = lj_lib_optstr(L, 2); |
347 | FILE *fp = *(FILE **)uddata(ud); | 368 | const char *mode = s ? strdata(s) : "r"; |
348 | if (fp == NULL) | 369 | IOFileUD *iof = io_file_new(L); |
349 | lj_err_caller(L, LJ_ERR_IOSTDCL); | 370 | iof->fp = fopen(fname, mode); |
350 | return fp; | 371 | return iof->fp != NULL ? 1 : io_pushresult(L, 0, fname); |
351 | } | 372 | } |
352 | 373 | ||
353 | LJLIB_CF(io_open) | 374 | LJLIB_CF(io_popen) |
354 | { | 375 | { |
355 | const char *fname = luaL_checkstring(L, 1); | 376 | #if defined(LUA_USE_POSIX) || defined(LUA_USE_WIN) |
356 | const char *mode = luaL_optstring(L, 2, "r"); | 377 | const char *fname = strdata(lj_lib_checkstr(L, 1)); |
357 | FILE **pf = io_file_new(L); | 378 | GCstr *s = lj_lib_optstr(L, 2); |
358 | *pf = fopen(fname, mode); | 379 | const char *mode = s ? strdata(s) : "r"; |
359 | return (*pf == NULL) ? io_pushresult(L, 0, fname) : 1; | 380 | IOFileUD *iof = io_file_new(L); |
381 | iof->type = IOFILE_TYPE_PIPE; | ||
382 | #ifdef LUA_USE_POSIX | ||
383 | fflush(NULL); | ||
384 | iof->fp = popen(fname, mode); | ||
385 | #else | ||
386 | iof->fp = _popen(fname, mode); | ||
387 | #endif | ||
388 | return iof->fp != NULL ? 1 : io_pushresult(L, 0, fname); | ||
389 | #else | ||
390 | luaL_error(L, LUA_QL("popen") " not supported"); | ||
391 | #endif | ||
360 | } | 392 | } |
361 | 393 | ||
362 | LJLIB_CF(io_tmpfile) | 394 | LJLIB_CF(io_tmpfile) |
363 | { | 395 | { |
364 | FILE **pf = io_file_new(L); | 396 | IOFileUD *iof = io_file_new(L); |
365 | *pf = tmpfile(); | 397 | iof->fp = tmpfile(); |
366 | return (*pf == NULL) ? io_pushresult(L, 0, NULL) : 1; | 398 | return iof->fp != NULL ? 1 : io_pushresult(L, 0, NULL); |
367 | } | 399 | } |
368 | 400 | ||
369 | LJLIB_CF(io_close) | 401 | LJLIB_CF(io_close) |
@@ -373,169 +405,112 @@ LJLIB_CF(io_close) | |||
373 | 405 | ||
374 | LJLIB_CF(io_read) | 406 | LJLIB_CF(io_read) |
375 | { | 407 | { |
376 | return io_file_read(L, io_file_get(L, IO_INPUT), 0); | 408 | return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0); |
377 | } | ||
378 | |||
379 | LJLIB_CF(io_write) | ||
380 | { | ||
381 | return io_file_write(L, io_file_get(L, IO_OUTPUT), 0); | ||
382 | } | ||
383 | |||
384 | LJLIB_CF(io_flush) | ||
385 | { | ||
386 | return io_pushresult(L, fflush(io_file_get(L, IO_OUTPUT)) == 0, NULL); | ||
387 | } | 409 | } |
388 | 410 | ||
389 | LJLIB_NOREG LJLIB_CF(io_lines_iter) | 411 | LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT) |
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 | |||
408 | static void io_file_lines(lua_State *L, int idx, int toclose) | ||
409 | { | 412 | { |
410 | lua_pushvalue(L, idx); | 413 | return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0); |
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 | } | 414 | } |
415 | 415 | ||
416 | LJLIB_CF(io_lines) | 416 | LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT) |
417 | { | 417 | { |
418 | if (lua_isnoneornil(L, 1)) { /* no arguments? */ | 418 | return io_pushresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)) == 0, NULL); |
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 | } | 419 | } |
432 | 420 | ||
433 | static int io_std_get(lua_State *L, int fp, const char *mode) | 421 | static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode) |
434 | { | 422 | { |
435 | if (!lua_isnoneornil(L, 1)) { | 423 | if (L->base < L->top && !tvisnil(L->base)) { |
436 | const char *fname = lua_tostring(L, 1); | 424 | if (tvisudata(L->base)) { |
437 | if (fname) { | 425 | io_tofile(L); |
438 | FILE **pf = io_file_new(L); | 426 | L->top = L->base+1; |
439 | *pf = fopen(fname, mode); | ||
440 | if (*pf == NULL) | ||
441 | io_file_error(L, 1, fname); | ||
442 | } else { | 427 | } else { |
443 | io_tofile(L); /* check that it's a valid file handle */ | 428 | io_file_open(L, mode); |
444 | lua_pushvalue(L, 1); | ||
445 | } | 429 | } |
446 | lua_rawseti(L, LUA_ENVIRONINDEX, fp); | 430 | /* NOBARRIER: The standard I/O handles are GC roots. */ |
431 | setgcref(G(L)->gcroot[id], gcV(L->top-1)); | ||
432 | } else { | ||
433 | setudataV(L, L->top++, IOSTDF_UD(L, id)); | ||
447 | } | 434 | } |
448 | /* return current value */ | ||
449 | lua_rawgeti(L, LUA_ENVIRONINDEX, fp); | ||
450 | return 1; | 435 | return 1; |
451 | } | 436 | } |
452 | 437 | ||
453 | LJLIB_CF(io_input) | 438 | LJLIB_CF(io_input) |
454 | { | 439 | { |
455 | return io_std_get(L, IO_INPUT, "r"); | 440 | return io_std_getset(L, GCROOT_IO_INPUT, "r"); |
456 | } | 441 | } |
457 | 442 | ||
458 | LJLIB_CF(io_output) | 443 | LJLIB_CF(io_output) |
459 | { | 444 | { |
460 | return io_std_get(L, IO_OUTPUT, "w"); | 445 | return io_std_getset(L, GCROOT_IO_OUTPUT, "w"); |
461 | } | 446 | } |
462 | 447 | ||
463 | LJLIB_CF(io_type) | 448 | LJLIB_NOREG LJLIB_CF(io_lines_iter) |
464 | { | 449 | { |
465 | void *ud; | 450 | IOFileUD *iof = io_tofile(L); |
466 | luaL_checkany(L, 1); | 451 | int ok = io_file_readline(L, iof->fp); |
467 | ud = lua_touserdata(L, 1); | 452 | if (ferror(iof->fp)) |
468 | lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); | 453 | lj_err_callermsg(L, strerror(errno)); |
469 | if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) | 454 | if (!ok && (iof->type & IOFILE_FLAG_CLOSE)) |
470 | lua_pushnil(L); /* not a file */ | 455 | io_file_close(L, iof); /* Return values are ignored (ok is 0). */ |
471 | else if (*((FILE **)ud) == NULL) | 456 | return ok; |
472 | lua_pushliteral(L, "closed file"); | ||
473 | else | ||
474 | lua_pushliteral(L, "file"); | ||
475 | return 1; | ||
476 | } | 457 | } |
477 | 458 | ||
478 | LJLIB_PUSH(top-3) LJLIB_SET(!) /* Set environment. */ | 459 | LJLIB_PUSH(top-3) /* io_lines_iter */ |
460 | LJLIB_CF(io_lines) | ||
461 | { | ||
462 | if (L->base < L->top && !tvisnil(L->base)) { /* io.lines(fname) */ | ||
463 | IOFileUD *iof = io_file_open(L, "r"); | ||
464 | iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE; | ||
465 | setfuncV(L, L->top-2, funcV(lj_lib_upvalue(L, 1))); | ||
466 | } else { /* io.lines() iterates over stdin. */ | ||
467 | setfuncV(L, L->top, funcV(lj_lib_upvalue(L, 1))); | ||
468 | setudataV(L, L->top+1, IOSTDF_UD(L, GCROOT_IO_INPUT)); | ||
469 | L->top += 2; | ||
470 | } | ||
471 | return 2; | ||
472 | } | ||
479 | 473 | ||
480 | LJLIB_CF(io_popen) | 474 | LJLIB_CF(io_type) |
481 | { | 475 | { |
482 | #if defined(LUA_USE_POSIX) || defined(LUA_USE_WIN) | 476 | cTValue *o = lj_lib_checkany(L, 1); |
483 | const char *fname = luaL_checkstring(L, 1); | 477 | if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE)) |
484 | const char *mode = luaL_optstring(L, 2, "r"); | 478 | setnilV(L->top++); |
485 | FILE **pf = io_file_new(L); | 479 | else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL) |
486 | #ifdef LUA_USE_POSIX | 480 | lua_pushliteral(L, "file"); |
487 | fflush(NULL); | 481 | else |
488 | *pf = popen(fname, mode); | 482 | lua_pushliteral(L, "closed file"); |
489 | #else | 483 | return 1; |
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 | } | 484 | } |
497 | 485 | ||
498 | #include "lj_libdef.h" | 486 | #include "lj_libdef.h" |
499 | 487 | ||
500 | /* ------------------------------------------------------------------------ */ | 488 | /* ------------------------------------------------------------------------ */ |
501 | 489 | ||
502 | static void io_std_new(lua_State *L, FILE *fp, int k, const char *fname) | 490 | static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name) |
503 | { | 491 | { |
504 | FILE **pf = io_file_new(L); | 492 | IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); |
505 | GCudata *ud = udataV(L->top-1); | 493 | GCudata *ud = udataV(L->top-1); |
506 | GCtab *envt = tabV(L->top-2); | 494 | ud->udtype = UDTYPE_IO_FILE; |
507 | *pf = fp; | 495 | /* NOBARRIER: The GCudata is new (marked white). */ |
508 | setgcref(ud->env, obj2gco(envt)); | 496 | setgcref(ud->metatable, gcV(L->top-3)); |
509 | lj_gc_objbarrier(L, obj2gco(ud), envt); | 497 | iof->fp = fp; |
510 | if (k > 0) { | 498 | iof->type = IOFILE_TYPE_STDF; |
511 | lua_pushvalue(L, -1); | 499 | lua_setfield(L, -2, name); |
512 | lua_rawseti(L, -5, k); | 500 | return obj2gco(ud); |
513 | } | ||
514 | lua_setfield(L, -3, fname); | ||
515 | } | ||
516 | |||
517 | static 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 | } | 501 | } |
523 | 502 | ||
524 | LUALIB_API int luaopen_io(lua_State *L) | 503 | LUALIB_API int luaopen_io(lua_State *L) |
525 | { | 504 | { |
526 | lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); | 505 | lua_pushcfunction(L, lj_cf_io_lines_iter); |
527 | if (tvisnil(L->top-1)) { | 506 | funcV(L->top-1)->c.ffid = FF_io_lines_iter; |
528 | LJ_LIB_REG_(L, NULL, io_method); | 507 | LJ_LIB_REG_(L, NULL, io_method); |
529 | lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); | 508 | copyTV(L, L->top, L->top-1); L->top++; |
530 | } | 509 | lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); |
531 | io_fenv_new(L, 0, lj_cf_io_pipe_close); /* top-3 */ | ||
532 | io_fenv_new(L, 2, lj_cf_io_file_close); /* top-2 */ | ||
533 | LJ_LIB_REG(L, io); | 510 | LJ_LIB_REG(L, io); |
534 | io_fenv_new(L, 0, lj_cf_io_std_close); | 511 | setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin")); |
535 | io_std_new(L, stdin, IO_INPUT, "stdin"); | 512 | setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout")); |
536 | io_std_new(L, stdout, IO_OUTPUT, "stdout"); | 513 | io_std_new(L, stderr, "stderr"); |
537 | io_std_new(L, stderr, 0, "stderr"); | ||
538 | L->top--; | ||
539 | return 1; | 514 | return 1; |
540 | } | 515 | } |
541 | 516 | ||