/src/tarantool/third_party/luajit/src/lib_io.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** I/O library. |
3 | | ** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h |
4 | | ** |
5 | | ** Major portions taken verbatim or adapted from the Lua interpreter. |
6 | | ** Copyright (C) 1994-2011 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_gc.h" |
21 | | #include "lj_err.h" |
22 | | #include "lj_buf.h" |
23 | | #include "lj_str.h" |
24 | | #include "lj_state.h" |
25 | | #include "lj_strfmt.h" |
26 | | #include "lj_ff.h" |
27 | | #include "lj_lib.h" |
28 | | |
29 | | /* Userdata payload for I/O file. */ |
30 | | typedef struct IOFileUD { |
31 | | FILE *fp; /* File handle. */ |
32 | | uint32_t type; /* File type. */ |
33 | | } IOFileUD; |
34 | | |
35 | 0 | #define IOFILE_TYPE_FILE 0 /* Regular file. */ |
36 | 0 | #define IOFILE_TYPE_PIPE 1 /* Pipe. */ |
37 | 18.3k | #define IOFILE_TYPE_STDF 2 /* Standard file handle. */ |
38 | 9.19k | #define IOFILE_TYPE_MASK 3 |
39 | | |
40 | 0 | #define IOFILE_FLAG_CLOSE 4 /* Close after io.lines() iterator. */ |
41 | | |
42 | 0 | #define IOSTDF_UD(L, id) (&gcref(G(L)->gcroot[(id)])->ud) |
43 | 0 | #define IOSTDF_IOF(L, id) ((IOFileUD *)uddata(IOSTDF_UD(L, (id)))) |
44 | | |
45 | | /* -- Open/close helpers -------------------------------------------------- */ |
46 | | |
47 | | static IOFileUD *io_tofilep(lua_State *L) |
48 | 9.19k | { |
49 | 9.19k | if (!(L->base < L->top && tvisudata(L->base) && |
50 | 9.19k | udataV(L->base)->udtype == UDTYPE_IO_FILE)) |
51 | 0 | lj_err_argtype(L, 1, "FILE*"); |
52 | 9.19k | return (IOFileUD *)uddata(udataV(L->base)); |
53 | 9.19k | } |
54 | | |
55 | | static IOFileUD *io_tofile(lua_State *L) |
56 | 0 | { |
57 | 0 | IOFileUD *iof = io_tofilep(L); |
58 | 0 | if (iof->fp == NULL) |
59 | 0 | lj_err_caller(L, LJ_ERR_IOCLFL); |
60 | 0 | return iof; |
61 | 0 | } |
62 | | |
63 | | static IOFileUD *io_stdfile(lua_State *L, ptrdiff_t id) |
64 | 0 | { |
65 | 0 | IOFileUD *iof = IOSTDF_IOF(L, id); |
66 | 0 | if (iof->fp == NULL) |
67 | 0 | lj_err_caller(L, LJ_ERR_IOSTDCL); |
68 | 0 | return iof; |
69 | 0 | } |
70 | | |
71 | | static IOFileUD *io_file_new(lua_State *L) |
72 | 0 | { |
73 | 0 | IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); |
74 | 0 | GCudata *ud = udataV(L->top-1); |
75 | 0 | ud->udtype = UDTYPE_IO_FILE; |
76 | | /* NOBARRIER: The GCudata is new (marked white). */ |
77 | 0 | setgcrefr(ud->metatable, curr_func(L)->c.env); |
78 | 0 | iof->fp = NULL; |
79 | 0 | iof->type = IOFILE_TYPE_FILE; |
80 | 0 | return iof; |
81 | 0 | } |
82 | | |
83 | | static IOFileUD *io_file_open(lua_State *L, const char *mode) |
84 | 0 | { |
85 | 0 | const char *fname = strdata(lj_lib_checkstr(L, 1)); |
86 | 0 | IOFileUD *iof = io_file_new(L); |
87 | 0 | iof->fp = fopen(fname, mode); |
88 | 0 | if (iof->fp == NULL) |
89 | 0 | luaL_argerror(L, 1, lj_strfmt_pushf(L, "%s: %s", fname, strerror(errno))); |
90 | 0 | return iof; |
91 | 0 | } |
92 | | |
93 | | static int io_file_close(lua_State *L, IOFileUD *iof) |
94 | 0 | { |
95 | 0 | int ok; |
96 | 0 | if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_FILE) { |
97 | 0 | ok = (fclose(iof->fp) == 0); |
98 | 0 | } else if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_PIPE) { |
99 | 0 | int stat = -1; |
100 | 0 | #if LJ_TARGET_POSIX |
101 | 0 | stat = pclose(iof->fp); |
102 | | #elif LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP |
103 | | stat = _pclose(iof->fp); |
104 | | #endif |
105 | | #if LJ_52 |
106 | | iof->fp = NULL; |
107 | | return luaL_execresult(L, stat); |
108 | | #else |
109 | 0 | ok = (stat != -1); |
110 | 0 | #endif |
111 | 0 | } else { |
112 | 0 | lj_assertL((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF, |
113 | 0 | "close of unknown FILE* type"); |
114 | 0 | setnilV(L->top++); |
115 | 0 | lua_pushliteral(L, "cannot close standard file"); |
116 | 0 | return 2; |
117 | 0 | } |
118 | 0 | iof->fp = NULL; |
119 | 0 | return luaL_fileresult(L, ok, NULL); |
120 | 0 | } |
121 | | |
122 | | /* -- Read/write helpers -------------------------------------------------- */ |
123 | | |
124 | | static int io_file_readnum(lua_State *L, FILE *fp) |
125 | 0 | { |
126 | 0 | lua_Number d; |
127 | 0 | if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) { |
128 | 0 | if (LJ_DUALNUM) { |
129 | 0 | int32_t i = lj_num2int(d); |
130 | 0 | if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) { |
131 | 0 | setintV(L->top++, i); |
132 | 0 | return 1; |
133 | 0 | } |
134 | 0 | } |
135 | 0 | setnumV(L->top++, d); |
136 | 0 | return 1; |
137 | 0 | } else { |
138 | 0 | setnilV(L->top++); |
139 | 0 | return 0; |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | | static int io_file_readline(lua_State *L, FILE *fp, MSize chop) |
144 | 0 | { |
145 | 0 | MSize m = LUAL_BUFFERSIZE, n = 0, ok = 0; |
146 | 0 | char *buf; |
147 | 0 | for (;;) { |
148 | 0 | buf = lj_buf_tmp(L, m); |
149 | 0 | if (fgets(buf+n, m-n, fp) == NULL) break; |
150 | 0 | n += (MSize)strlen(buf+n); |
151 | 0 | ok |= n; |
152 | 0 | if (n && buf[n-1] == '\n') { n -= chop; break; } |
153 | 0 | if (n >= m - 64) m += m; |
154 | 0 | } |
155 | 0 | setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n)); |
156 | 0 | lj_gc_check(L); |
157 | 0 | return (int)ok; |
158 | 0 | } |
159 | | |
160 | | static void io_file_readall(lua_State *L, FILE *fp) |
161 | 0 | { |
162 | 0 | MSize m, n; |
163 | 0 | for (m = LUAL_BUFFERSIZE, n = 0; ; m += m) { |
164 | 0 | char *buf = lj_buf_tmp(L, m); |
165 | 0 | n += (MSize)fread(buf+n, 1, m-n, fp); |
166 | 0 | if (n != m) { |
167 | 0 | setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n)); |
168 | 0 | lj_gc_check(L); |
169 | 0 | return; |
170 | 0 | } |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | | static int io_file_readlen(lua_State *L, FILE *fp, MSize m) |
175 | 0 | { |
176 | 0 | if (m) { |
177 | 0 | char *buf = lj_buf_tmp(L, m); |
178 | 0 | MSize n = (MSize)fread(buf, 1, m, fp); |
179 | 0 | setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n)); |
180 | 0 | lj_gc_check(L); |
181 | 0 | return (n > 0 || m == 0); |
182 | 0 | } else { |
183 | 0 | int c = getc(fp); |
184 | 0 | ungetc(c, fp); |
185 | 0 | setstrV(L, L->top++, &G(L)->strempty); |
186 | 0 | return (c != EOF); |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | | static int io_file_read(lua_State *L, IOFileUD *iof, int start) |
191 | 0 | { |
192 | 0 | FILE *fp = iof->fp; |
193 | 0 | int ok, n, nargs = (int)(L->top - L->base) - start; |
194 | 0 | clearerr(fp); |
195 | 0 | if (nargs == 0) { |
196 | 0 | ok = io_file_readline(L, fp, 1); |
197 | 0 | n = start+1; /* Return 1 result. */ |
198 | 0 | } else { |
199 | | /* The results plus the buffers go on top of the args. */ |
200 | 0 | luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); |
201 | 0 | ok = 1; |
202 | 0 | for (n = start; nargs-- && ok; n++) { |
203 | 0 | if (tvisstr(L->base+n)) { |
204 | 0 | const char *p = strVdata(L->base+n); |
205 | 0 | if (p[0] == '*') p++; |
206 | 0 | if (p[0] == 'n') |
207 | 0 | ok = io_file_readnum(L, fp); |
208 | 0 | else if ((p[0] & ~0x20) == 'L') |
209 | 0 | ok = io_file_readline(L, fp, (p[0] == 'l')); |
210 | 0 | else if (p[0] == 'a') |
211 | 0 | io_file_readall(L, fp); |
212 | 0 | else |
213 | 0 | lj_err_arg(L, n+1, LJ_ERR_INVFMT); |
214 | 0 | } else if (tvisnumber(L->base+n)) { |
215 | 0 | ok = io_file_readlen(L, fp, (MSize)lj_lib_checkint(L, n+1)); |
216 | 0 | } else { |
217 | 0 | lj_err_arg(L, n+1, LJ_ERR_INVOPT); |
218 | 0 | } |
219 | 0 | } |
220 | 0 | } |
221 | 0 | if (ferror(fp)) |
222 | 0 | return luaL_fileresult(L, 0, NULL); |
223 | 0 | if (!ok) |
224 | 0 | setnilV(L->top-1); /* Replace last result with nil. */ |
225 | 0 | return n - start; |
226 | 0 | } |
227 | | |
228 | | static int io_file_write(lua_State *L, IOFileUD *iof, int start) |
229 | 0 | { |
230 | 0 | FILE *fp = iof->fp; |
231 | 0 | cTValue *tv; |
232 | 0 | int status = 1; |
233 | 0 | for (tv = L->base+start; tv < L->top; tv++) { |
234 | 0 | MSize len; |
235 | 0 | const char *p = lj_strfmt_wstrnum(L, tv, &len); |
236 | 0 | if (!p) |
237 | 0 | lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING); |
238 | 0 | status = status && (fwrite(p, 1, len, fp) == len); |
239 | 0 | } |
240 | 0 | if (LJ_52 && status) { |
241 | 0 | L->top = L->base+1; |
242 | 0 | if (start == 0) |
243 | 0 | setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_OUTPUT)); |
244 | 0 | return 1; |
245 | 0 | } |
246 | 0 | return luaL_fileresult(L, status, NULL); |
247 | 0 | } |
248 | | |
249 | | static int io_file_iter(lua_State *L) |
250 | 0 | { |
251 | 0 | GCfunc *fn = curr_func(L); |
252 | 0 | IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0])); |
253 | 0 | int n = fn->c.nupvalues - 1; |
254 | 0 | if (iof->fp == NULL) |
255 | 0 | lj_err_caller(L, LJ_ERR_IOCLFL); |
256 | 0 | L->top = L->base; |
257 | 0 | if (n) { /* Copy upvalues with options to stack. */ |
258 | 0 | if (n > LUAI_MAXCSTACK) |
259 | 0 | lj_err_caller(L, LJ_ERR_STKOV); |
260 | 0 | lj_state_checkstack(L, (MSize)n); |
261 | 0 | memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue)); |
262 | 0 | L->top += n; |
263 | 0 | } |
264 | 0 | n = io_file_read(L, iof, 0); |
265 | 0 | if (ferror(iof->fp)) |
266 | 0 | lj_err_callermsg(L, strVdata(L->top-2)); |
267 | 0 | if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) { |
268 | 0 | io_file_close(L, iof); /* Return values are ignored. */ |
269 | 0 | return 0; |
270 | 0 | } |
271 | 0 | return n; |
272 | 0 | } |
273 | | |
274 | | static int io_file_lines(lua_State *L) |
275 | 0 | { |
276 | 0 | int n = (int)(L->top - L->base); |
277 | 0 | if (n > LJ_MAX_UPVAL) |
278 | 0 | lj_err_caller(L, LJ_ERR_UNPACK); |
279 | 0 | lua_pushcclosure(L, io_file_iter, n); |
280 | 0 | return 1; |
281 | 0 | } |
282 | | |
283 | | /* -- I/O file methods ---------------------------------------------------- */ |
284 | | |
285 | | #define LJLIB_MODULE_io_method |
286 | | |
287 | | LJLIB_CF(io_method_close) |
288 | 0 | { |
289 | 0 | IOFileUD *iof; |
290 | 0 | if (L->base < L->top) { |
291 | 0 | iof = io_tofile(L); |
292 | 0 | } else { |
293 | 0 | iof = IOSTDF_IOF(L, GCROOT_IO_OUTPUT); |
294 | 0 | if (iof->fp == NULL) |
295 | 0 | lj_err_caller(L, LJ_ERR_IOCLFL); |
296 | 0 | } |
297 | 0 | return io_file_close(L, iof); |
298 | 0 | } |
299 | | |
300 | | LJLIB_CF(io_method_read) |
301 | 0 | { |
302 | 0 | return io_file_read(L, io_tofile(L), 1); |
303 | 0 | } |
304 | | |
305 | | LJLIB_CF(io_method_write) LJLIB_REC(io_write 0) |
306 | 0 | { |
307 | 0 | return io_file_write(L, io_tofile(L), 1); |
308 | 0 | } |
309 | | |
310 | | LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0) |
311 | 0 | { |
312 | 0 | return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL); |
313 | 0 | } |
314 | | |
315 | | LJLIB_CF(io_method_seek) |
316 | 0 | { |
317 | 0 | FILE *fp = io_tofile(L)->fp; |
318 | 0 | int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end"); |
319 | 0 | int64_t ofs = 0; |
320 | 0 | cTValue *o; |
321 | 0 | int res; |
322 | 0 | if (opt == 0) opt = SEEK_SET; |
323 | 0 | else if (opt == 1) opt = SEEK_CUR; |
324 | 0 | else if (opt == 2) opt = SEEK_END; |
325 | 0 | o = L->base+2; |
326 | 0 | if (o < L->top) { |
327 | 0 | if (tvisint(o)) |
328 | 0 | ofs = (int64_t)intV(o); |
329 | 0 | else if (tvisnum(o)) |
330 | 0 | ofs = (int64_t)numV(o); |
331 | 0 | else if (!tvisnil(o)) |
332 | 0 | lj_err_argt(L, 3, LUA_TNUMBER); |
333 | 0 | } |
334 | 0 | #if LJ_TARGET_POSIX |
335 | 0 | res = fseeko(fp, ofs, opt); |
336 | | #elif _MSC_VER >= 1400 |
337 | | res = _fseeki64(fp, ofs, opt); |
338 | | #elif defined(__MINGW32__) |
339 | | res = fseeko64(fp, ofs, opt); |
340 | | #else |
341 | | res = fseek(fp, (long)ofs, opt); |
342 | | #endif |
343 | 0 | if (res) |
344 | 0 | return luaL_fileresult(L, 0, NULL); |
345 | 0 | #if LJ_TARGET_POSIX |
346 | 0 | ofs = ftello(fp); |
347 | | #elif _MSC_VER >= 1400 |
348 | | ofs = _ftelli64(fp); |
349 | | #elif defined(__MINGW32__) |
350 | | ofs = ftello64(fp); |
351 | | #else |
352 | | ofs = (int64_t)ftell(fp); |
353 | | #endif |
354 | 0 | setint64V(L->top-1, ofs); |
355 | 0 | return 1; |
356 | 0 | } |
357 | | |
358 | | LJLIB_CF(io_method_setvbuf) |
359 | 0 | { |
360 | 0 | FILE *fp = io_tofile(L)->fp; |
361 | 0 | int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no"); |
362 | 0 | size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE); |
363 | 0 | if (opt == 0) opt = _IOFBF; |
364 | 0 | else if (opt == 1) opt = _IOLBF; |
365 | 0 | else if (opt == 2) opt = _IONBF; |
366 | 0 | return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL); |
367 | 0 | } |
368 | | |
369 | | LJLIB_CF(io_method_lines) |
370 | 0 | { |
371 | 0 | io_tofile(L); |
372 | 0 | return io_file_lines(L); |
373 | 0 | } |
374 | | |
375 | | LJLIB_CF(io_method___gc) |
376 | 9.19k | { |
377 | 9.19k | IOFileUD *iof = io_tofilep(L); |
378 | 9.19k | if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF) |
379 | 0 | io_file_close(L, iof); |
380 | 9.19k | return 0; |
381 | 9.19k | } |
382 | | |
383 | | LJLIB_CF(io_method___tostring) |
384 | 0 | { |
385 | 0 | IOFileUD *iof = io_tofilep(L); |
386 | 0 | if (iof->fp != NULL) |
387 | 0 | lua_pushfstring(L, "file (%p)", iof->fp); |
388 | 0 | else |
389 | 0 | lua_pushliteral(L, "file (closed)"); |
390 | 0 | return 1; |
391 | 0 | } |
392 | | |
393 | | LJLIB_PUSH(top-1) LJLIB_SET(__index) |
394 | | |
395 | | #include "lj_libdef.h" |
396 | | |
397 | | /* -- I/O library functions ----------------------------------------------- */ |
398 | | |
399 | | #define LJLIB_MODULE_io |
400 | | |
401 | | LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */ |
402 | | |
403 | | LJLIB_CF(io_open) |
404 | 0 | { |
405 | 0 | const char *fname = strdata(lj_lib_checkstr(L, 1)); |
406 | 0 | GCstr *s = lj_lib_optstr(L, 2); |
407 | 0 | const char *mode = s ? strdata(s) : "r"; |
408 | 0 | IOFileUD *iof = io_file_new(L); |
409 | 0 | iof->fp = fopen(fname, mode); |
410 | 0 | return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); |
411 | 0 | } |
412 | | |
413 | | LJLIB_CF(io_popen) |
414 | 0 | { |
415 | 0 | #if LJ_TARGET_POSIX || (LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP) |
416 | 0 | const char *fname = strdata(lj_lib_checkstr(L, 1)); |
417 | 0 | GCstr *s = lj_lib_optstr(L, 2); |
418 | 0 | const char *mode = s ? strdata(s) : "r"; |
419 | 0 | IOFileUD *iof = io_file_new(L); |
420 | 0 | iof->type = IOFILE_TYPE_PIPE; |
421 | 0 | #if LJ_TARGET_POSIX |
422 | 0 | fflush(NULL); |
423 | 0 | iof->fp = popen(fname, mode); |
424 | | #else |
425 | | iof->fp = _popen(fname, mode); |
426 | | #endif |
427 | 0 | return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); |
428 | | #else |
429 | | return luaL_error(L, LUA_QL("popen") " not supported"); |
430 | | #endif |
431 | 0 | } |
432 | | |
433 | | LJLIB_CF(io_tmpfile) |
434 | 0 | { |
435 | 0 | IOFileUD *iof = io_file_new(L); |
436 | | #if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PSVITA |
437 | | iof->fp = NULL; errno = ENOSYS; |
438 | | #else |
439 | 0 | iof->fp = tmpfile(); |
440 | 0 | #endif |
441 | 0 | return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL); |
442 | 0 | } |
443 | | |
444 | | LJLIB_CF(io_close) |
445 | 0 | { |
446 | 0 | return lj_cf_io_method_close(L); |
447 | 0 | } |
448 | | |
449 | | LJLIB_CF(io_read) |
450 | 0 | { |
451 | 0 | return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0); |
452 | 0 | } |
453 | | |
454 | | LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT) |
455 | 0 | { |
456 | 0 | return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0); |
457 | 0 | } |
458 | | |
459 | | LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT) |
460 | 0 | { |
461 | 0 | return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)->fp) == 0, NULL); |
462 | 0 | } |
463 | | |
464 | | static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode) |
465 | 0 | { |
466 | 0 | if (L->base < L->top && !tvisnil(L->base)) { |
467 | 0 | if (tvisudata(L->base)) { |
468 | 0 | io_tofile(L); |
469 | 0 | L->top = L->base+1; |
470 | 0 | } else { |
471 | 0 | io_file_open(L, mode); |
472 | 0 | } |
473 | | /* NOBARRIER: The standard I/O handles are GC roots. */ |
474 | 0 | setgcref(G(L)->gcroot[id], gcV(L->top-1)); |
475 | 0 | } else { |
476 | 0 | setudataV(L, L->top++, IOSTDF_UD(L, id)); |
477 | 0 | } |
478 | 0 | return 1; |
479 | 0 | } |
480 | | |
481 | | LJLIB_CF(io_input) |
482 | 0 | { |
483 | 0 | return io_std_getset(L, GCROOT_IO_INPUT, "r"); |
484 | 0 | } |
485 | | |
486 | | LJLIB_CF(io_output) |
487 | 0 | { |
488 | 0 | return io_std_getset(L, GCROOT_IO_OUTPUT, "w"); |
489 | 0 | } |
490 | | |
491 | | LJLIB_CF(io_lines) |
492 | 0 | { |
493 | 0 | if (L->base == L->top) setnilV(L->top++); |
494 | 0 | if (!tvisnil(L->base)) { /* io.lines(fname) */ |
495 | 0 | IOFileUD *iof = io_file_open(L, "r"); |
496 | 0 | iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE; |
497 | 0 | L->top--; |
498 | 0 | setudataV(L, L->base, udataV(L->top)); |
499 | 0 | } else { /* io.lines() iterates over stdin. */ |
500 | 0 | setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT)); |
501 | 0 | } |
502 | 0 | return io_file_lines(L); |
503 | 0 | } |
504 | | |
505 | | LJLIB_CF(io_type) |
506 | 0 | { |
507 | 0 | cTValue *o = lj_lib_checkany(L, 1); |
508 | 0 | if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE)) |
509 | 0 | setnilV(L->top++); |
510 | 0 | else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL) |
511 | 0 | lua_pushliteral(L, "file"); |
512 | 0 | else |
513 | 0 | lua_pushliteral(L, "closed file"); |
514 | 0 | return 1; |
515 | 0 | } |
516 | | |
517 | | #include "lj_libdef.h" |
518 | | |
519 | | /* ------------------------------------------------------------------------ */ |
520 | | |
521 | | static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name) |
522 | 9.19k | { |
523 | 9.19k | IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); |
524 | 9.19k | GCudata *ud = udataV(L->top-1); |
525 | 0 | ud->udtype = UDTYPE_IO_FILE; |
526 | | /* NOBARRIER: The GCudata is new (marked white). */ |
527 | 9.19k | setgcref(ud->metatable, gcV(L->top-3)); |
528 | 0 | iof->fp = fp; |
529 | 9.19k | iof->type = IOFILE_TYPE_STDF; |
530 | 9.19k | lua_setfield(L, -2, name); |
531 | 9.19k | return obj2gco(ud); |
532 | 9.19k | } |
533 | | |
534 | | LUALIB_API int luaopen_io(lua_State *L) |
535 | 3.06k | { |
536 | 3.06k | LJ_LIB_REG(L, NULL, io_method); |
537 | 3.06k | copyTV(L, L->top, L->top-1); L->top++; |
538 | 3.06k | lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); |
539 | 3.06k | LJ_LIB_REG(L, LUA_IOLIBNAME, io); |
540 | 3.06k | setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin")); |
541 | 3.06k | setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout")); |
542 | 3.06k | io_std_new(L, stderr, "stderr"); |
543 | 3.06k | return 1; |
544 | 3.06k | } |
545 | | |