ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

lib_io.c (13437B)


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