root/lib_io.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. io_tofilep
  2. io_tofile
  3. io_stdfile
  4. io_file_new
  5. io_file_open
  6. io_file_close
  7. io_file_readnum
  8. io_file_readline
  9. io_file_readall
  10. io_file_readlen
  11. io_file_read
  12. io_file_write
  13. io_file_iter
  14. io_file_lines
  15. LJLIB_CF
  16. LJLIB_CF
  17. LJLIB_CF
  18. LJLIB_CF
  19. LJLIB_CF
  20. LJLIB_CF
  21. LJLIB_CF
  22. LJLIB_CF
  23. LJLIB_CF
  24. LJLIB_PUSH
  25. LJLIB_CF
  26. LJLIB_CF
  27. LJLIB_CF
  28. LJLIB_CF
  29. LJLIB_CF
  30. LJLIB_CF
  31. io_std_getset
  32. LJLIB_CF
  33. LJLIB_CF
  34. LJLIB_CF
  35. LJLIB_CF
  36. io_std_new
  37. luaopen_io

   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 #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_52
 109     iof->fp = NULL;
 110     return luaL_execresult(L, stat);
 111 #else
 112     ok = (stat != -1);
 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] == '*') p++;
 207         if (p[0] == 'n')
 208           ok = io_file_readnum(L, fp);
 209         else if ((p[0] & ~0x20) == 'L')
 210           ok = io_file_readline(L, fp, (p[0] == 'l'));
 211         else if (p[0] == 'a')
 212           io_file_readall(L, fp);
 213         else
 214           lj_err_arg(L, n+1, LJ_ERR_INVFMT);
 215       } else if (tvisnumber(L->base+n)) {
 216         ok = io_file_readlen(L, fp, (MSize)lj_lib_checkint(L, n+1));
 217       } else {
 218         lj_err_arg(L, n+1, LJ_ERR_INVOPT);
 219       }
 220     }
 221   }
 222   if (ferror(fp))
 223     return luaL_fileresult(L, 0, NULL);
 224   if (!ok)
 225     setnilV(L->top-1);  /* Replace last result with nil. */
 226   return n - start;
 227 }
 228 
 229 static int io_file_write(lua_State *L, FILE *fp, int start)
 230 {
 231   cTValue *tv;
 232   int status = 1;
 233   for (tv = L->base+start; tv < L->top; tv++) {
 234     MSize len;
 235     const char *p = lj_strfmt_wstrnum(L, tv, &len);
 236     if (!p)
 237       lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING);
 238     status = status && (fwrite(p, 1, len, fp) == len);
 239   }
 240   if (LJ_52 && status) {
 241     L->top = L->base+1;
 242     if (start == 0)
 243       setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_OUTPUT));
 244     return 1;
 245   }
 246   return luaL_fileresult(L, status, NULL);
 247 }
 248 
 249 static int io_file_iter(lua_State *L)
 250 {
 251   GCfunc *fn = curr_func(L);
 252   IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0]));
 253   int n = fn->c.nupvalues - 1;
 254   if (iof->fp == NULL)
 255     lj_err_caller(L, LJ_ERR_IOCLFL);
 256   L->top = L->base;
 257   if (n) {  /* Copy upvalues with options to stack. */
 258     if (n > LUAI_MAXCSTACK)
 259       lj_err_caller(L, LJ_ERR_STKOV);
 260     lj_state_checkstack(L, (MSize)n);
 261     memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue));
 262     L->top += n;
 263   }
 264   n = io_file_read(L, iof->fp, 0);
 265   if (ferror(iof->fp))
 266     lj_err_callermsg(L, strVdata(L->top-2));
 267   if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) {
 268     io_file_close(L, iof);  /* Return values are ignored. */
 269     return 0;
 270   }
 271   return n;
 272 }
 273 
 274 static int io_file_lines(lua_State *L)
 275 {
 276   int n = (int)(L->top - L->base);
 277   if (n > LJ_MAX_UPVAL)
 278     lj_err_caller(L, LJ_ERR_UNPACK);
 279   lua_pushcclosure(L, io_file_iter, n);
 280   return 1;
 281 }
 282 
 283 /* -- I/O file methods ---------------------------------------------------- */
 284 
 285 #define LJLIB_MODULE_io_method
 286 
 287 LJLIB_CF(io_method_close)
 288 {
 289   IOFileUD *iof = L->base < L->top ? io_tofile(L) :
 290                   IOSTDF_IOF(L, GCROOT_IO_OUTPUT);
 291   return io_file_close(L, iof);
 292 }
 293 
 294 LJLIB_CF(io_method_read)
 295 {
 296   return io_file_read(L, io_tofile(L)->fp, 1);
 297 }
 298 
 299 LJLIB_CF(io_method_write)               LJLIB_REC(io_write 0)
 300 {
 301   return io_file_write(L, io_tofile(L)->fp, 1);
 302 }
 303 
 304 LJLIB_CF(io_method_flush)               LJLIB_REC(io_flush 0)
 305 {
 306   return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL);
 307 }
 308 
 309 LJLIB_CF(io_method_seek)
 310 {
 311   FILE *fp = io_tofile(L)->fp;
 312   int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end");
 313   int64_t ofs = 0;
 314   cTValue *o;
 315   int res;
 316   if (opt == 0) opt = SEEK_SET;
 317   else if (opt == 1) opt = SEEK_CUR;
 318   else if (opt == 2) opt = SEEK_END;
 319   o = L->base+2;
 320   if (o < L->top) {
 321     if (tvisint(o))
 322       ofs = (int64_t)intV(o);
 323     else if (tvisnum(o))
 324       ofs = (int64_t)numV(o);
 325     else if (!tvisnil(o))
 326       lj_err_argt(L, 3, LUA_TNUMBER);
 327   }
 328 #if LJ_TARGET_POSIX
 329   res = fseeko(fp, ofs, opt);
 330 #elif _MSC_VER >= 1400
 331   res = _fseeki64(fp, ofs, opt);
 332 #elif defined(__MINGW32__)
 333   res = fseeko64(fp, ofs, opt);
 334 #else
 335   res = fseek(fp, (long)ofs, opt);
 336 #endif
 337   if (res)
 338     return luaL_fileresult(L, 0, NULL);
 339 #if LJ_TARGET_POSIX
 340   ofs = ftello(fp);
 341 #elif _MSC_VER >= 1400
 342   ofs = _ftelli64(fp);
 343 #elif defined(__MINGW32__)
 344   ofs = ftello64(fp);
 345 #else
 346   ofs = (int64_t)ftell(fp);
 347 #endif
 348   setint64V(L->top-1, ofs);
 349   return 1;
 350 }
 351 
 352 LJLIB_CF(io_method_setvbuf)
 353 {
 354   FILE *fp = io_tofile(L)->fp;
 355   int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no");
 356   size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE);
 357   if (opt == 0) opt = _IOFBF;
 358   else if (opt == 1) opt = _IOLBF;
 359   else if (opt == 2) opt = _IONBF;
 360   return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL);
 361 }
 362 
 363 LJLIB_CF(io_method_lines)
 364 {
 365   io_tofile(L);
 366   return io_file_lines(L);
 367 }
 368 
 369 LJLIB_CF(io_method___gc)
 370 {
 371   IOFileUD *iof = io_tofilep(L);
 372   if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF)
 373     io_file_close(L, iof);
 374   return 0;
 375 }
 376 
 377 LJLIB_CF(io_method___tostring)
 378 {
 379   IOFileUD *iof = io_tofilep(L);
 380   if (iof->fp != NULL)
 381     lua_pushfstring(L, "file (%p)", iof->fp);
 382   else
 383     lua_pushliteral(L, "file (closed)");
 384   return 1;
 385 }
 386 
 387 LJLIB_PUSH(top-1) LJLIB_SET(__index)
 388 
 389 #include "lj_libdef.h"
 390 
 391 /* -- I/O library functions ----------------------------------------------- */
 392 
 393 #define LJLIB_MODULE_io
 394 
 395 LJLIB_PUSH(top-2) LJLIB_SET(!)  /* Set environment. */
 396 
 397 LJLIB_CF(io_open)
 398 {
 399   const char *fname = strdata(lj_lib_checkstr(L, 1));
 400   GCstr *s = lj_lib_optstr(L, 2);
 401   const char *mode = s ? strdata(s) : "r";
 402   IOFileUD *iof = io_file_new(L);
 403   iof->fp = fopen(fname, mode);
 404   return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
 405 }
 406 
 407 LJLIB_CF(io_popen)
 408 {
 409 #if LJ_TARGET_POSIX || (LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE)
 410   const char *fname = strdata(lj_lib_checkstr(L, 1));
 411   GCstr *s = lj_lib_optstr(L, 2);
 412   const char *mode = s ? strdata(s) : "r";
 413   IOFileUD *iof = io_file_new(L);
 414   iof->type = IOFILE_TYPE_PIPE;
 415 #if LJ_TARGET_POSIX
 416   fflush(NULL);
 417   iof->fp = popen(fname, mode);
 418 #else
 419   iof->fp = _popen(fname, mode);
 420 #endif
 421   return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
 422 #else
 423   return luaL_error(L, LUA_QL("popen") " not supported");
 424 #endif
 425 }
 426 
 427 LJLIB_CF(io_tmpfile)
 428 {
 429   IOFileUD *iof = io_file_new(L);
 430 #if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PSVITA
 431   iof->fp = NULL; errno = ENOSYS;
 432 #else
 433   iof->fp = tmpfile();
 434 #endif
 435   return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL);
 436 }
 437 
 438 LJLIB_CF(io_close)
 439 {
 440   return lj_cf_io_method_close(L);
 441 }
 442 
 443 LJLIB_CF(io_read)
 444 {
 445   return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0);
 446 }
 447 
 448 LJLIB_CF(io_write)              LJLIB_REC(io_write GCROOT_IO_OUTPUT)
 449 {
 450   return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0);
 451 }
 452 
 453 LJLIB_CF(io_flush)              LJLIB_REC(io_flush GCROOT_IO_OUTPUT)
 454 {
 455   return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)) == 0, NULL);
 456 }
 457 
 458 static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode)
 459 {
 460   if (L->base < L->top && !tvisnil(L->base)) {
 461     if (tvisudata(L->base)) {
 462       io_tofile(L);
 463       L->top = L->base+1;
 464     } else {
 465       io_file_open(L, mode);
 466     }
 467     /* NOBARRIER: The standard I/O handles are GC roots. */
 468     setgcref(G(L)->gcroot[id], gcV(L->top-1));
 469   } else {
 470     setudataV(L, L->top++, IOSTDF_UD(L, id));
 471   }
 472   return 1;
 473 }
 474 
 475 LJLIB_CF(io_input)
 476 {
 477   return io_std_getset(L, GCROOT_IO_INPUT, "r");
 478 }
 479 
 480 LJLIB_CF(io_output)
 481 {
 482   return io_std_getset(L, GCROOT_IO_OUTPUT, "w");
 483 }
 484 
 485 LJLIB_CF(io_lines)
 486 {
 487   if (L->base == L->top) setnilV(L->top++);
 488   if (!tvisnil(L->base)) {  /* io.lines(fname) */
 489     IOFileUD *iof = io_file_open(L, "r");
 490     iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE;
 491     L->top--;
 492     setudataV(L, L->base, udataV(L->top));
 493   } else {  /* io.lines() iterates over stdin. */
 494     setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT));
 495   }
 496   return io_file_lines(L);
 497 }
 498 
 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 
 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 
 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 

/* [<][>][^][v][top][bottom][index][help] */