Mercurial
comparison third_party/luajit/src/lib_io.c @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 /* | |
| 2 ** I/O library. | |
| 3 ** Copyright (C) 2005-2023 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 IOFileUD *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; | |
| 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 && !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 ok = (stat != -1); | |
| 110 #endif | |
| 111 } else { | |
| 112 lj_assertL((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF, | |
| 113 "close of unknown FILE* type"); | |
| 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 | |
| 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 | |
| 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_buf_tmp(L, 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 | |
| 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_buf_tmp(L, 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 | |
| 174 static int io_file_readlen(lua_State *L, FILE *fp, MSize m) | |
| 175 { | |
| 176 if (m) { | |
| 177 char *buf = lj_buf_tmp(L, 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; | |
| 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 | |
| 190 static int io_file_read(lua_State *L, IOFileUD *iof, int start) | |
| 191 { | |
| 192 FILE *fp = iof->fp; | |
| 193 int ok, n, nargs = (int)(L->top - L->base) - start; | |
| 194 clearerr(fp); | |
| 195 if (nargs == 0) { | |
| 196 ok = io_file_readline(L, fp, 1); | |
| 197 n = start+1; /* Return 1 result. */ | |
| 198 } else { | |
| 199 /* The results plus the buffers go on top of the args. */ | |
| 200 luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); | |
| 201 ok = 1; | |
| 202 for (n = start; nargs-- && ok; n++) { | |
| 203 if (tvisstr(L->base+n)) { | |
| 204 const char *p = strVdata(L->base+n); | |
| 205 if (p[0] == '*') p++; | |
| 206 if (p[0] == 'n') | |
| 207 ok = io_file_readnum(L, fp); | |
| 208 else if ((p[0] & ~0x20) == 'L') | |
| 209 ok = io_file_readline(L, fp, (p[0] == 'l')); | |
| 210 else if (p[0] == '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 | |
| 228 static int io_file_write(lua_State *L, IOFileUD *iof, int start) | |
| 229 { | |
| 230 FILE *fp = iof->fp; | |
| 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 lj_state_checkstack(L, (MSize)n); | |
| 259 memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue)); | |
| 260 L->top += n; | |
| 261 } | |
| 262 n = io_file_read(L, iof, 0); | |
| 263 if (ferror(iof->fp)) | |
| 264 lj_err_callermsg(L, strVdata(L->top-2)); | |
| 265 if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) { | |
| 266 io_file_close(L, iof); /* Return values are ignored. */ | |
| 267 return 0; | |
| 268 } | |
| 269 return n; | |
| 270 } | |
| 271 | |
| 272 static int io_file_lines(lua_State *L) | |
| 273 { | |
| 274 int n = (int)(L->top - L->base); | |
| 275 if (n > LJ_MAX_UPVAL) | |
| 276 lj_err_caller(L, LJ_ERR_UNPACK); | |
| 277 lua_pushcclosure(L, io_file_iter, n); | |
| 278 return 1; | |
| 279 } | |
| 280 | |
| 281 /* -- I/O file methods ---------------------------------------------------- */ | |
| 282 | |
| 283 #define LJLIB_MODULE_io_method | |
| 284 | |
| 285 LJLIB_CF(io_method_close) | |
| 286 { | |
| 287 IOFileUD *iof; | |
| 288 if (L->base < L->top) { | |
| 289 iof = io_tofile(L); | |
| 290 } else { | |
| 291 iof = IOSTDF_IOF(L, GCROOT_IO_OUTPUT); | |
| 292 if (iof->fp == NULL) | |
| 293 lj_err_caller(L, LJ_ERR_IOCLFL); | |
| 294 } | |
| 295 return io_file_close(L, iof); | |
| 296 } | |
| 297 | |
| 298 LJLIB_CF(io_method_read) | |
| 299 { | |
| 300 return io_file_read(L, io_tofile(L), 1); | |
| 301 } | |
| 302 | |
| 303 LJLIB_CF(io_method_write) LJLIB_REC(io_write 0) | |
| 304 { | |
| 305 return io_file_write(L, io_tofile(L), 1); | |
| 306 } | |
| 307 | |
| 308 LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0) | |
| 309 { | |
| 310 return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL); | |
| 311 } | |
| 312 | |
| 313 #if LJ_32 && defined(__ANDROID__) && __ANDROID_API__ < 24 | |
| 314 /* The Android NDK is such an unmatched marvel of engineering. */ | |
| 315 extern int fseeko32(FILE *, long int, int) __asm__("fseeko"); | |
| 316 extern long int ftello32(FILE *) __asm__("ftello"); | |
| 317 #define fseeko(fp, pos, whence) (fseeko32((fp), (pos), (whence))) | |
| 318 #define ftello(fp) (ftello32((fp))) | |
| 319 #endif | |
| 320 | |
| 321 LJLIB_CF(io_method_seek) | |
| 322 { | |
| 323 FILE *fp = io_tofile(L)->fp; | |
| 324 int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end"); | |
| 325 int64_t ofs = 0; | |
| 326 cTValue *o; | |
| 327 int res; | |
| 328 if (opt == 0) opt = SEEK_SET; | |
| 329 else if (opt == 1) opt = SEEK_CUR; | |
| 330 else if (opt == 2) opt = SEEK_END; | |
| 331 o = L->base+2; | |
| 332 if (o < L->top) { | |
| 333 if (tvisint(o)) | |
| 334 ofs = (int64_t)intV(o); | |
| 335 else if (tvisnum(o)) | |
| 336 ofs = (int64_t)numV(o); | |
| 337 else if (!tvisnil(o)) | |
| 338 lj_err_argt(L, 3, LUA_TNUMBER); | |
| 339 } | |
| 340 #if LJ_TARGET_POSIX | |
| 341 res = fseeko(fp, ofs, opt); | |
| 342 #elif _MSC_VER >= 1400 | |
| 343 res = _fseeki64(fp, ofs, opt); | |
| 344 #elif defined(__MINGW32__) | |
| 345 res = fseeko64(fp, ofs, opt); | |
| 346 #else | |
| 347 res = fseek(fp, (long)ofs, opt); | |
| 348 #endif | |
| 349 if (res) | |
| 350 return luaL_fileresult(L, 0, NULL); | |
| 351 #if LJ_TARGET_POSIX | |
| 352 ofs = ftello(fp); | |
| 353 #elif _MSC_VER >= 1400 | |
| 354 ofs = _ftelli64(fp); | |
| 355 #elif defined(__MINGW32__) | |
| 356 ofs = ftello64(fp); | |
| 357 #else | |
| 358 ofs = (int64_t)ftell(fp); | |
| 359 #endif | |
| 360 setint64V(L->top-1, ofs); | |
| 361 return 1; | |
| 362 } | |
| 363 | |
| 364 LJLIB_CF(io_method_setvbuf) | |
| 365 { | |
| 366 FILE *fp = io_tofile(L)->fp; | |
| 367 int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no"); | |
| 368 size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE); | |
| 369 if (opt == 0) opt = _IOFBF; | |
| 370 else if (opt == 1) opt = _IOLBF; | |
| 371 else if (opt == 2) opt = _IONBF; | |
| 372 return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL); | |
| 373 } | |
| 374 | |
| 375 LJLIB_CF(io_method_lines) | |
| 376 { | |
| 377 io_tofile(L); | |
| 378 return io_file_lines(L); | |
| 379 } | |
| 380 | |
| 381 LJLIB_CF(io_method___gc) | |
| 382 { | |
| 383 IOFileUD *iof = io_tofilep(L); | |
| 384 if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF) | |
| 385 io_file_close(L, iof); | |
| 386 return 0; | |
| 387 } | |
| 388 | |
| 389 LJLIB_CF(io_method___tostring) | |
| 390 { | |
| 391 IOFileUD *iof = io_tofilep(L); | |
| 392 if (iof->fp != NULL) | |
| 393 lua_pushfstring(L, "file (%p)", iof->fp); | |
| 394 else | |
| 395 lua_pushliteral(L, "file (closed)"); | |
| 396 return 1; | |
| 397 } | |
| 398 | |
| 399 LJLIB_PUSH(top-1) LJLIB_SET(__index) | |
| 400 | |
| 401 #include "lj_libdef.h" | |
| 402 | |
| 403 /* -- I/O library functions ----------------------------------------------- */ | |
| 404 | |
| 405 #define LJLIB_MODULE_io | |
| 406 | |
| 407 LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */ | |
| 408 | |
| 409 LJLIB_CF(io_open) | |
| 410 { | |
| 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->fp = fopen(fname, mode); | |
| 416 return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); | |
| 417 } | |
| 418 | |
| 419 LJLIB_CF(io_popen) | |
| 420 { | |
| 421 #if LJ_TARGET_POSIX || (LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP) | |
| 422 const char *fname = strdata(lj_lib_checkstr(L, 1)); | |
| 423 GCstr *s = lj_lib_optstr(L, 2); | |
| 424 const char *mode = s ? strdata(s) : "r"; | |
| 425 IOFileUD *iof = io_file_new(L); | |
| 426 iof->type = IOFILE_TYPE_PIPE; | |
| 427 #if LJ_TARGET_POSIX | |
| 428 fflush(NULL); | |
| 429 iof->fp = popen(fname, mode); | |
| 430 #else | |
| 431 iof->fp = _popen(fname, mode); | |
| 432 #endif | |
| 433 return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); | |
| 434 #else | |
| 435 return luaL_error(L, LUA_QL("popen") " not supported"); | |
| 436 #endif | |
| 437 } | |
| 438 | |
| 439 LJLIB_CF(io_tmpfile) | |
| 440 { | |
| 441 IOFileUD *iof = io_file_new(L); | |
| 442 #if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA || LJ_TARGET_NX | |
| 443 iof->fp = NULL; errno = ENOSYS; | |
| 444 #else | |
| 445 iof->fp = tmpfile(); | |
| 446 #endif | |
| 447 return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL); | |
| 448 } | |
| 449 | |
| 450 LJLIB_CF(io_close) | |
| 451 { | |
| 452 return lj_cf_io_method_close(L); | |
| 453 } | |
| 454 | |
| 455 LJLIB_CF(io_read) | |
| 456 { | |
| 457 return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0); | |
| 458 } | |
| 459 | |
| 460 LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT) | |
| 461 { | |
| 462 return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0); | |
| 463 } | |
| 464 | |
| 465 LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT) | |
| 466 { | |
| 467 return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)->fp) == 0, NULL); | |
| 468 } | |
| 469 | |
| 470 static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode) | |
| 471 { | |
| 472 if (L->base < L->top && !tvisnil(L->base)) { | |
| 473 if (tvisudata(L->base)) { | |
| 474 io_tofile(L); | |
| 475 L->top = L->base+1; | |
| 476 } else { | |
| 477 io_file_open(L, mode); | |
| 478 } | |
| 479 /* NOBARRIER: The standard I/O handles are GC roots. */ | |
| 480 setgcref(G(L)->gcroot[id], gcV(L->top-1)); | |
| 481 } else { | |
| 482 setudataV(L, L->top++, IOSTDF_UD(L, id)); | |
| 483 } | |
| 484 return 1; | |
| 485 } | |
| 486 | |
| 487 LJLIB_CF(io_input) | |
| 488 { | |
| 489 return io_std_getset(L, GCROOT_IO_INPUT, "r"); | |
| 490 } | |
| 491 | |
| 492 LJLIB_CF(io_output) | |
| 493 { | |
| 494 return io_std_getset(L, GCROOT_IO_OUTPUT, "w"); | |
| 495 } | |
| 496 | |
| 497 LJLIB_CF(io_lines) | |
| 498 { | |
| 499 if (L->base == L->top) setnilV(L->top++); | |
| 500 if (!tvisnil(L->base)) { /* io.lines(fname) */ | |
| 501 IOFileUD *iof = io_file_open(L, "r"); | |
| 502 iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE; | |
| 503 L->top--; | |
| 504 setudataV(L, L->base, udataV(L->top)); | |
| 505 } else { /* io.lines() iterates over stdin. */ | |
| 506 setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT)); | |
| 507 } | |
| 508 return io_file_lines(L); | |
| 509 } | |
| 510 | |
| 511 LJLIB_CF(io_type) | |
| 512 { | |
| 513 cTValue *o = lj_lib_checkany(L, 1); | |
| 514 if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE)) | |
| 515 setnilV(L->top++); | |
| 516 else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL) | |
| 517 lua_pushliteral(L, "file"); | |
| 518 else | |
| 519 lua_pushliteral(L, "closed file"); | |
| 520 return 1; | |
| 521 } | |
| 522 | |
| 523 #include "lj_libdef.h" | |
| 524 | |
| 525 /* ------------------------------------------------------------------------ */ | |
| 526 | |
| 527 static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name) | |
| 528 { | |
| 529 IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD)); | |
| 530 GCudata *ud = udataV(L->top-1); | |
| 531 ud->udtype = UDTYPE_IO_FILE; | |
| 532 /* NOBARRIER: The GCudata is new (marked white). */ | |
| 533 setgcref(ud->metatable, gcV(L->top-3)); | |
| 534 iof->fp = fp; | |
| 535 iof->type = IOFILE_TYPE_STDF; | |
| 536 lua_setfield(L, -2, name); | |
| 537 return obj2gco(ud); | |
| 538 } | |
| 539 | |
| 540 LUALIB_API int luaopen_io(lua_State *L) | |
| 541 { | |
| 542 LJ_LIB_REG(L, NULL, io_method); | |
| 543 copyTV(L, L->top, L->top-1); L->top++; | |
| 544 lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); | |
| 545 LJ_LIB_REG(L, LUA_IOLIBNAME, io); | |
| 546 setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin")); | |
| 547 setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout")); | |
| 548 io_std_new(L, stderr, "stderr"); | |
| 549 return 1; | |
| 550 } | |
| 551 |