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