1/* $NetBSD$ */ 2 3/* 4** Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp 5** Standard I/O (and system) library 6** See Copyright Notice in lua.h 7*/ 8 9 10#include <errno.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14 15#define liolib_c 16#define LUA_LIB 17 18#include "lua.h" 19 20#include "lauxlib.h" 21#include "lualib.h" 22 23 24 25#define IO_INPUT 1 26#define IO_OUTPUT 2 27 28 29static const char *const fnames[] = {"input", "output"}; 30 31 32static int pushresult (lua_State *L, int i, const char *filename) { 33 int en = errno; /* calls to Lua API may change this value */ 34 if (i) { 35 lua_pushboolean(L, 1); 36 return 1; 37 } 38 else { 39 lua_pushnil(L); 40 if (filename) 41 lua_pushfstring(L, "%s: %s", filename, strerror(en)); 42 else 43 lua_pushfstring(L, "%s", strerror(en)); 44 lua_pushinteger(L, en); 45 return 3; 46 } 47} 48 49 50static void fileerror (lua_State *L, int arg, const char *filename) { 51 lua_pushfstring(L, "%s: %s", filename, strerror(errno)); 52 luaL_argerror(L, arg, lua_tostring(L, -1)); 53} 54 55 56#define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) 57 58 59static int io_type (lua_State *L) { 60 void *ud; 61 luaL_checkany(L, 1); 62 ud = lua_touserdata(L, 1); 63 lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); 64 if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) 65 lua_pushnil(L); /* not a file */ 66 else if (*((FILE **)ud) == NULL) 67 lua_pushliteral(L, "closed file"); 68 else 69 lua_pushliteral(L, "file"); 70 return 1; 71} 72 73 74static FILE *tofile (lua_State *L) { 75 FILE **f = tofilep(L); 76 if (*f == NULL) 77 luaL_error(L, "attempt to use a closed file"); 78 return *f; 79} 80 81 82 83/* 84** When creating file handles, always creates a `closed' file handle 85** before opening the actual file; so, if there is a memory error, the 86** file is not left opened. 87*/ 88static FILE **newfile (lua_State *L) { 89 FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); 90 *pf = NULL; /* file handle is currently `closed' */ 91 luaL_getmetatable(L, LUA_FILEHANDLE); 92 lua_setmetatable(L, -2); 93 return pf; 94} 95 96 97/* 98** function to (not) close the standard files stdin, stdout, and stderr 99*/ 100static int io_noclose (lua_State *L) { 101 lua_pushnil(L); 102 lua_pushliteral(L, "cannot close standard file"); 103 return 2; 104} 105 106 107/* 108** function to close 'popen' files 109*/ 110static int io_pclose (lua_State *L) { 111 FILE **p = tofilep(L); 112 int ok = lua_pclose(L, *p); 113 *p = NULL; 114 return pushresult(L, ok, NULL); 115} 116 117 118/* 119** function to close regular files 120*/ 121static int io_fclose (lua_State *L) { 122 FILE **p = tofilep(L); 123 int ok = (fclose(*p) == 0); 124 *p = NULL; 125 return pushresult(L, ok, NULL); 126} 127 128 129static int aux_close (lua_State *L) { 130 lua_getfenv(L, 1); 131 lua_getfield(L, -1, "__close"); 132 return (lua_tocfunction(L, -1))(L); 133} 134 135 136static int io_close (lua_State *L) { 137 if (lua_isnone(L, 1)) 138 lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); 139 tofile(L); /* make sure argument is a file */ 140 return aux_close(L); 141} 142 143 144static int io_gc (lua_State *L) { 145 FILE *f = *tofilep(L); 146 /* ignore closed files */ 147 if (f != NULL) 148 aux_close(L); 149 return 0; 150} 151 152 153static int io_tostring (lua_State *L) { 154 FILE *f = *tofilep(L); 155 if (f == NULL) 156 lua_pushliteral(L, "file (closed)"); 157 else 158 lua_pushfstring(L, "file (%p)", f); 159 return 1; 160} 161 162 163static int io_open (lua_State *L) { 164 const char *filename = luaL_checkstring(L, 1); 165 const char *mode = luaL_optstring(L, 2, "r"); 166 FILE **pf = newfile(L); 167 *pf = fopen(filename, mode); 168 return (*pf == NULL) ? pushresult(L, 0, filename) : 1; 169} 170 171 172/* 173** this function has a separated environment, which defines the 174** correct __close for 'popen' files 175*/ 176static int io_popen (lua_State *L) { 177 const char *filename = luaL_checkstring(L, 1); 178 const char *mode = luaL_optstring(L, 2, "r"); 179 FILE **pf = newfile(L); 180 *pf = lua_popen(L, filename, mode); 181 return (*pf == NULL) ? pushresult(L, 0, filename) : 1; 182} 183 184 185static int io_tmpfile (lua_State *L) { 186 FILE **pf = newfile(L); 187 *pf = tmpfile(); 188 return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; 189} 190 191 192static FILE *getiofile (lua_State *L, int findex) { 193 FILE *f; 194 lua_rawgeti(L, LUA_ENVIRONINDEX, findex); 195 f = *(FILE **)lua_touserdata(L, -1); 196 if (f == NULL) 197 luaL_error(L, "standard %s file is closed", fnames[findex - 1]); 198 return f; 199} 200 201 202static int g_iofile (lua_State *L, int f, const char *mode) { 203 if (!lua_isnoneornil(L, 1)) { 204 const char *filename = lua_tostring(L, 1); 205 if (filename) { 206 FILE **pf = newfile(L); 207 *pf = fopen(filename, mode); 208 if (*pf == NULL) 209 fileerror(L, 1, filename); 210 } 211 else { 212 tofile(L); /* check that it's a valid file handle */ 213 lua_pushvalue(L, 1); 214 } 215 lua_rawseti(L, LUA_ENVIRONINDEX, f); 216 } 217 /* return current value */ 218 lua_rawgeti(L, LUA_ENVIRONINDEX, f); 219 return 1; 220} 221 222 223static int io_input (lua_State *L) { 224 return g_iofile(L, IO_INPUT, "r"); 225} 226 227 228static int io_output (lua_State *L) { 229 return g_iofile(L, IO_OUTPUT, "w"); 230} 231 232 233static int io_readline (lua_State *L); 234 235 236static void aux_lines (lua_State *L, int idx, int toclose) { 237 lua_pushvalue(L, idx); 238 lua_pushboolean(L, toclose); /* close/not close file when finished */ 239 lua_pushcclosure(L, io_readline, 2); 240} 241 242 243static int f_lines (lua_State *L) { 244 tofile(L); /* check that it's a valid file handle */ 245 aux_lines(L, 1, 0); 246 return 1; 247} 248 249 250static int io_lines (lua_State *L) { 251 if (lua_isnoneornil(L, 1)) { /* no arguments? */ 252 /* will iterate over default input */ 253 lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); 254 return f_lines(L); 255 } 256 else { 257 const char *filename = luaL_checkstring(L, 1); 258 FILE **pf = newfile(L); 259 *pf = fopen(filename, "r"); 260 if (*pf == NULL) 261 fileerror(L, 1, filename); 262 aux_lines(L, lua_gettop(L), 1); 263 return 1; 264 } 265} 266 267 268/* 269** {====================================================== 270** READ 271** ======================================================= 272*/ 273 274 275static int read_number (lua_State *L, FILE *f) { 276 lua_Number d; 277 if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { 278 lua_pushnumber(L, d); 279 return 1; 280 } 281 else return 0; /* read fails */ 282} 283 284 285static int test_eof (lua_State *L, FILE *f) { 286 int c = getc(f); 287 ungetc(c, f); 288 lua_pushlstring(L, NULL, 0); 289 return (c != EOF); 290} 291 292 293static int read_line (lua_State *L, FILE *f) { 294 luaL_Buffer b; 295 luaL_buffinit(L, &b); 296 for (;;) { 297 size_t l; 298 char *p = luaL_prepbuffer(&b); 299 if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ 300 luaL_pushresult(&b); /* close buffer */ 301 return (lua_objlen(L, -1) > 0); /* check whether read something */ 302 } 303 l = strlen(p); 304 if (l == 0 || p[l-1] != '\n') 305 luaL_addsize(&b, l); 306 else { 307 luaL_addsize(&b, l - 1); /* do not include `eol' */ 308 luaL_pushresult(&b); /* close buffer */ 309 return 1; /* read at least an `eol' */ 310 } 311 } 312} 313 314 315static int read_chars (lua_State *L, FILE *f, size_t n) { 316 size_t rlen; /* how much to read */ 317 size_t nr; /* number of chars actually read */ 318 luaL_Buffer b; 319 luaL_buffinit(L, &b); 320 rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ 321 do { 322 char *p = luaL_prepbuffer(&b); 323 if (rlen > n) rlen = n; /* cannot read more than asked */ 324 nr = fread(p, sizeof(char), rlen, f); 325 luaL_addsize(&b, nr); 326 n -= nr; /* still have to read `n' chars */ 327 } while (n > 0 && nr == rlen); /* until end of count or eof */ 328 luaL_pushresult(&b); /* close buffer */ 329 return (n == 0 || lua_objlen(L, -1) > 0); 330} 331 332 333static int g_read (lua_State *L, FILE *f, int first) { 334 int nargs = lua_gettop(L) - 1; 335 int success; 336 int n; 337 clearerr(f); 338 if (nargs == 0) { /* no arguments? */ 339 success = read_line(L, f); 340 n = first+1; /* to return 1 result */ 341 } 342 else { /* ensure stack space for all results and for auxlib's buffer */ 343 luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); 344 success = 1; 345 for (n = first; nargs-- && success; n++) { 346 if (lua_type(L, n) == LUA_TNUMBER) { 347 size_t l = (size_t)lua_tointeger(L, n); 348 success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); 349 } 350 else { 351 const char *p = lua_tostring(L, n); 352 luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); 353 switch (p[1]) { 354 case 'n': /* number */ 355 success = read_number(L, f); 356 break; 357 case 'l': /* line */ 358 success = read_line(L, f); 359 break; 360 case 'a': /* file */ 361 read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ 362 success = 1; /* always success */ 363 break; 364 default: 365 return luaL_argerror(L, n, "invalid format"); 366 } 367 } 368 } 369 } 370 if (ferror(f)) 371 return pushresult(L, 0, NULL); 372 if (!success) { 373 lua_pop(L, 1); /* remove last result */ 374 lua_pushnil(L); /* push nil instead */ 375 } 376 return n - first; 377} 378 379 380static int io_read (lua_State *L) { 381 return g_read(L, getiofile(L, IO_INPUT), 1); 382} 383 384 385static int f_read (lua_State *L) { 386 return g_read(L, tofile(L), 2); 387} 388 389 390static int io_readline (lua_State *L) { 391 FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); 392 int sucess; 393 if (f == NULL) /* file is already closed? */ 394 luaL_error(L, "file is already closed"); 395 sucess = read_line(L, f); 396 if (ferror(f)) 397 return luaL_error(L, "%s", strerror(errno)); 398 if (sucess) return 1; 399 else { /* EOF */ 400 if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ 401 lua_settop(L, 0); 402 lua_pushvalue(L, lua_upvalueindex(1)); 403 aux_close(L); /* close it */ 404 } 405 return 0; 406 } 407} 408 409/* }====================================================== */ 410 411 412static int g_write (lua_State *L, FILE *f, int arg) { 413 int nargs = lua_gettop(L) - 1; 414 int status = 1; 415 for (; nargs--; arg++) { 416 if (lua_type(L, arg) == LUA_TNUMBER) { 417 /* optimization: could be done exactly as for strings */ 418 status = status && 419 fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; 420 } 421 else { 422 size_t l; 423 const char *s = luaL_checklstring(L, arg, &l); 424 status = status && (fwrite(s, sizeof(char), l, f) == l); 425 } 426 } 427 return pushresult(L, status, NULL); 428} 429 430 431static int io_write (lua_State *L) { 432 return g_write(L, getiofile(L, IO_OUTPUT), 1); 433} 434 435 436static int f_write (lua_State *L) { 437 return g_write(L, tofile(L), 2); 438} 439 440 441static int f_seek (lua_State *L) { 442 static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; 443 static const char *const modenames[] = {"set", "cur", "end", NULL}; 444 FILE *f = tofile(L); 445 int op = luaL_checkoption(L, 2, "cur", modenames); 446 long offset = luaL_optlong(L, 3, 0); 447 op = fseek(f, offset, mode[op]); 448 if (op) 449 return pushresult(L, 0, NULL); /* error */ 450 else { 451 lua_pushinteger(L, ftell(f)); 452 return 1; 453 } 454} 455 456 457static int f_setvbuf (lua_State *L) { 458 static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; 459 static const char *const modenames[] = {"no", "full", "line", NULL}; 460 FILE *f = tofile(L); 461 int op = luaL_checkoption(L, 2, NULL, modenames); 462 lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); 463 int res = setvbuf(f, NULL, mode[op], sz); 464 return pushresult(L, res == 0, NULL); 465} 466 467 468 469static int io_flush (lua_State *L) { 470 return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); 471} 472 473 474static int f_flush (lua_State *L) { 475 return pushresult(L, fflush(tofile(L)) == 0, NULL); 476} 477 478 479static const luaL_Reg iolib[] = { 480 {"close", io_close}, 481 {"flush", io_flush}, 482 {"input", io_input}, 483 {"lines", io_lines}, 484 {"open", io_open}, 485 {"output", io_output}, 486 {"popen", io_popen}, 487 {"read", io_read}, 488 {"tmpfile", io_tmpfile}, 489 {"type", io_type}, 490 {"write", io_write}, 491 {NULL, NULL} 492}; 493 494 495static const luaL_Reg flib[] = { 496 {"close", io_close}, 497 {"flush", f_flush}, 498 {"lines", f_lines}, 499 {"read", f_read}, 500 {"seek", f_seek}, 501 {"setvbuf", f_setvbuf}, 502 {"write", f_write}, 503 {"__gc", io_gc}, 504 {"__tostring", io_tostring}, 505 {NULL, NULL} 506}; 507 508 509static void createmeta (lua_State *L) { 510 luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ 511 lua_pushvalue(L, -1); /* push metatable */ 512 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ 513 luaL_register(L, NULL, flib); /* file methods */ 514} 515 516 517static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { 518 *newfile(L) = f; 519 if (k > 0) { 520 lua_pushvalue(L, -1); 521 lua_rawseti(L, LUA_ENVIRONINDEX, k); 522 } 523 lua_pushvalue(L, -2); /* copy environment */ 524 lua_setfenv(L, -2); /* set it */ 525 lua_setfield(L, -3, fname); 526} 527 528 529static void newfenv (lua_State *L, lua_CFunction cls) { 530 lua_createtable(L, 0, 1); 531 lua_pushcfunction(L, cls); 532 lua_setfield(L, -2, "__close"); 533} 534 535 536LUALIB_API int luaopen_io (lua_State *L) { 537 createmeta(L); 538 /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ 539 newfenv(L, io_fclose); 540 lua_replace(L, LUA_ENVIRONINDEX); 541 /* open library */ 542 luaL_register(L, LUA_IOLIBNAME, iolib); 543 /* create (and set) default files */ 544 newfenv(L, io_noclose); /* close function for default files */ 545 createstdfile(L, stdin, IO_INPUT, "stdin"); 546 createstdfile(L, stdout, IO_OUTPUT, "stdout"); 547 createstdfile(L, stderr, 0, "stderr"); 548 lua_pop(L, 1); /* pop environment for default files */ 549 lua_getfield(L, -1, "popen"); 550 newfenv(L, io_pclose); /* create environment for 'popen' */ 551 lua_setfenv(L, -2); /* set fenv for 'popen' */ 552 lua_pop(L, 1); /* pop 'popen' */ 553 return 1; 554} 555 556