00001
00002
00003
00004
00005
00006
00007
00008 #include <errno.h>
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012
00013 #define liolib_c
00014 #define LUA_LIB
00015
00016 #include "lua.h"
00017
00018 #include "lauxlib.h"
00019 #include "lualib.h"
00020
00021
00022
00023 #define IO_INPUT 1
00024 #define IO_OUTPUT 2
00025
00026
00027 static const char *const fnames[] = {"input", "output"};
00028
00029
00030 static int pushresult (lua_State *L, int i, const char *filename) {
00031 int en = errno;
00032 if (i) {
00033 lua_pushboolean(L, 1);
00034 return 1;
00035 }
00036 else {
00037 lua_pushnil(L);
00038 if (filename)
00039 lua_pushfstring(L, "%s: %s", filename, strerror(en));
00040 else
00041 lua_pushfstring(L, "%s", strerror(en));
00042 lua_pushinteger(L, en);
00043 return 3;
00044 }
00045 }
00046
00047
00048 static void fileerror (lua_State *L, int arg, const char *filename) {
00049 lua_pushfstring(L, "%s: %s", filename, strerror(errno));
00050 luaL_argerror(L, arg, lua_tostring(L, -1));
00051 }
00052
00053
00054 #define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
00055
00056
00057 static int io_type (lua_State *L) {
00058 void *ud;
00059 luaL_checkany(L, 1);
00060 ud = lua_touserdata(L, 1);
00061 lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
00062 if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
00063 lua_pushnil(L);
00064 else if (*((FILE **)ud) == NULL)
00065 lua_pushliteral(L, "closed file");
00066 else
00067 lua_pushliteral(L, "file");
00068 return 1;
00069 }
00070
00071
00072 static FILE *tofile (lua_State *L) {
00073 FILE **f = topfile(L);
00074 if (*f == NULL)
00075 luaL_error(L, "attempt to use a closed file");
00076 return *f;
00077 }
00078
00079
00080
00081
00082
00083
00084
00085
00086 static FILE **newfile (lua_State *L) {
00087 FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
00088 *pf = NULL;
00089 luaL_getmetatable(L, LUA_FILEHANDLE);
00090 lua_setmetatable(L, -2);
00091 return pf;
00092 }
00093
00094
00095
00096
00097
00098
00099 static int io_pclose (lua_State *L) {
00100 FILE **p = topfile(L);
00101 int ok = lua_pclose(L, *p);
00102 *p = NULL;
00103 return pushresult(L, ok, NULL);
00104 }
00105
00106
00107 static int io_fclose (lua_State *L) {
00108 FILE **p = topfile(L);
00109 int ok = (fclose(*p) == 0);
00110 *p = NULL;
00111 return pushresult(L, ok, NULL);
00112 }
00113
00114
00115 static int aux_close (lua_State *L) {
00116 lua_getfenv(L, 1);
00117 lua_getfield(L, -1, "__close");
00118 return (lua_tocfunction(L, -1))(L);
00119 }
00120
00121
00122 static int io_close (lua_State *L) {
00123 if (lua_isnone(L, 1))
00124 lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
00125 tofile(L);
00126 return aux_close(L);
00127 }
00128
00129
00130 static int io_gc (lua_State *L) {
00131 FILE *f = *topfile(L);
00132
00133 if (f != NULL && f != stdin && f != stdout && f != stderr)
00134 aux_close(L);
00135 return 0;
00136 }
00137
00138
00139 static int io_tostring (lua_State *L) {
00140 FILE *f = *topfile(L);
00141 if (f == NULL)
00142 lua_pushstring(L, "file (closed)");
00143 else
00144 lua_pushfstring(L, "file (%p)", f);
00145 return 1;
00146 }
00147
00148
00149 static int io_open (lua_State *L) {
00150 const char *filename = luaL_checkstring(L, 1);
00151 const char *mode = luaL_optstring(L, 2, "r");
00152 FILE **pf = newfile(L);
00153 *pf = fopen(filename, mode);
00154 return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
00155 }
00156
00157
00158 static int io_popen (lua_State *L) {
00159 const char *filename = luaL_checkstring(L, 1);
00160 const char *mode = luaL_optstring(L, 2, "r");
00161 FILE **pf = newfile(L);
00162 *pf = lua_popen(L, filename, mode);
00163 return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
00164 }
00165
00166
00167 static int io_tmpfile (lua_State *L) {
00168 FILE **pf = newfile(L);
00169 *pf = tmpfile();
00170 return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
00171 }
00172
00173
00174 static FILE *getiofile (lua_State *L, int findex) {
00175 FILE *f;
00176 lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
00177 f = *(FILE **)lua_touserdata(L, -1);
00178 if (f == NULL)
00179 luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
00180 return f;
00181 }
00182
00183
00184 static int g_iofile (lua_State *L, int f, const char *mode) {
00185 if (!lua_isnoneornil(L, 1)) {
00186 const char *filename = lua_tostring(L, 1);
00187 if (filename) {
00188 FILE **pf = newfile(L);
00189 *pf = fopen(filename, mode);
00190 if (*pf == NULL)
00191 fileerror(L, 1, filename);
00192 }
00193 else {
00194 tofile(L);
00195 lua_pushvalue(L, 1);
00196 }
00197 lua_rawseti(L, LUA_ENVIRONINDEX, f);
00198 }
00199
00200 lua_rawgeti(L, LUA_ENVIRONINDEX, f);
00201 return 1;
00202 }
00203
00204
00205 static int io_input (lua_State *L) {
00206 return g_iofile(L, IO_INPUT, "r");
00207 }
00208
00209
00210 static int io_output (lua_State *L) {
00211 return g_iofile(L, IO_OUTPUT, "w");
00212 }
00213
00214
00215 static int io_readline (lua_State *L);
00216
00217
00218 static void aux_lines (lua_State *L, int idx, int toclose) {
00219 lua_pushvalue(L, idx);
00220 lua_pushboolean(L, toclose);
00221 lua_pushcclosure(L, io_readline, 2);
00222 }
00223
00224
00225 static int f_lines (lua_State *L) {
00226 tofile(L);
00227 aux_lines(L, 1, 0);
00228 return 1;
00229 }
00230
00231
00232 static int io_lines (lua_State *L) {
00233 if (lua_isnoneornil(L, 1)) {
00234
00235 lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
00236 return f_lines(L);
00237 }
00238 else {
00239 const char *filename = luaL_checkstring(L, 1);
00240 FILE **pf = newfile(L);
00241 *pf = fopen(filename, "r");
00242 if (*pf == NULL)
00243 fileerror(L, 1, filename);
00244 aux_lines(L, lua_gettop(L), 1);
00245 return 1;
00246 }
00247 }
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 static int read_number (lua_State *L, FILE *f) {
00258
00259 char number[20];
00260 if (fscanf(f, "%s", number) == 1) {
00261
00262
00263
00264 fixed fn(number);
00265
00266 lua_pushnumber(L, fn.getInternal());
00267 return 1;
00268 }
00269 else return 0;
00270 }
00271
00272
00273 static int test_eof (lua_State *L, FILE *f) {
00274 int c = getc(f);
00275 ungetc(c, f);
00276 lua_pushlstring(L, NULL, 0);
00277 return (c != EOF);
00278 }
00279
00280
00281 static int read_line (lua_State *L, FILE *f) {
00282 luaL_Buffer b;
00283 luaL_buffinit(L, &b);
00284 for (;;) {
00285 size_t l;
00286 char *p = luaL_prepbuffer(&b);
00287 if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {
00288 luaL_pushresult(&b);
00289 return (lua_strlen(L, -1) > 0);
00290 }
00291 l = strlen(p);
00292 if (l == 0 || p[l-1] != '\n')
00293 luaL_addsize(&b, l);
00294 else {
00295 luaL_addsize(&b, l - 1);
00296 luaL_pushresult(&b);
00297 return 1;
00298 }
00299 }
00300 }
00301
00302
00303 static int read_chars (lua_State *L, FILE *f, size_t n) {
00304 size_t rlen;
00305 size_t nr;
00306 luaL_Buffer b;
00307 luaL_buffinit(L, &b);
00308 rlen = LUAL_BUFFERSIZE;
00309 do {
00310 char *p = luaL_prepbuffer(&b);
00311 if (rlen > n) rlen = n;
00312 nr = fread(p, sizeof(char), rlen, f);
00313 luaL_addsize(&b, nr);
00314 n -= nr;
00315 } while (n > 0 && nr == rlen);
00316 luaL_pushresult(&b);
00317 return (n == 0 || lua_strlen(L, -1) > 0);
00318 }
00319
00320
00321 static int g_read (lua_State *L, FILE *f, int first) {
00322 int nargs = lua_gettop(L) - 1;
00323 int success;
00324 int n;
00325 clearerr(f);
00326 if (nargs == 0) {
00327 success = read_line(L, f);
00328 n = first+1;
00329 }
00330 else {
00331 luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
00332 success = 1;
00333 for (n = first; nargs-- && success; n++) {
00334 if (lua_type(L, n) == LUA_TNUMBER) {
00335 size_t l = (size_t)lua_tointeger(L, n);
00336 success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
00337 }
00338 else {
00339 const char *p = lua_tostring(L, n);
00340 luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
00341 switch (p[1]) {
00342 case 'n':
00343 success = read_number(L, f);
00344 break;
00345 case 'l':
00346 success = read_line(L, f);
00347 break;
00348 case 'a':
00349 read_chars(L, f, ~((size_t)0));
00350 success = 1;
00351 break;
00352 default:
00353 return luaL_argerror(L, n, "invalid format");
00354 }
00355 }
00356 }
00357 }
00358 if (ferror(f))
00359 return pushresult(L, 0, NULL);
00360 if (!success) {
00361 lua_pop(L, 1);
00362 lua_pushnil(L);
00363 }
00364 return n - first;
00365 }
00366
00367
00368 static int io_read (lua_State *L) {
00369 return g_read(L, getiofile(L, IO_INPUT), 1);
00370 }
00371
00372
00373 static int f_read (lua_State *L) {
00374 return g_read(L, tofile(L), 2);
00375 }
00376
00377
00378 static int io_readline (lua_State *L) {
00379 FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
00380 int sucess;
00381 if (f == NULL)
00382 luaL_error(L, "file is already closed");
00383 sucess = read_line(L, f);
00384 if (ferror(f))
00385 return luaL_error(L, "%s", strerror(errno));
00386 if (sucess) return 1;
00387 else {
00388 if (lua_toboolean(L, lua_upvalueindex(2))) {
00389 lua_settop(L, 0);
00390 lua_pushvalue(L, lua_upvalueindex(1));
00391 aux_close(L);
00392 }
00393 return 0;
00394 }
00395 }
00396
00397
00398
00399
00400 static int g_write (lua_State *L, FILE *f, int arg) {
00401 int nargs = lua_gettop(L) - 1;
00402 int status = 1;
00403 for (; nargs--; arg++) {
00404 if (lua_type(L, arg) == LUA_TNUMBER) {
00405
00406 fixed fn(true, lua_tonumber(L, arg));
00407
00408 status = status &&
00409 fprintf(f, "%s", fn.asString()) > 0;
00410 }
00411 else {
00412 size_t l;
00413 const char *s = luaL_checklstring(L, arg, &l);
00414 status = status && (fwrite(s, sizeof(char), l, f) == l);
00415 }
00416 }
00417 return pushresult(L, status, NULL);
00418 }
00419
00420
00421 static int io_write (lua_State *L) {
00422 return g_write(L, getiofile(L, IO_OUTPUT), 1);
00423 }
00424
00425
00426 static int f_write (lua_State *L) {
00427 return g_write(L, tofile(L), 2);
00428 }
00429
00430
00431 static int f_seek (lua_State *L) {
00432 static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
00433 static const char *const modenames[] = {"set", "cur", "end", NULL};
00434 FILE *f = tofile(L);
00435 int op = luaL_checkoption(L, 2, "cur", modenames);
00436 long offset = luaL_optlong(L, 3, 0);
00437 op = fseek(f, offset, mode[op]);
00438 if (op)
00439 return pushresult(L, 0, NULL);
00440 else {
00441 lua_pushinteger(L, ftell(f));
00442 return 1;
00443 }
00444 }
00445
00446
00447 static int f_setvbuf (lua_State *L) {
00448 static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
00449 static const char *const modenames[] = {"no", "full", "line", NULL};
00450 FILE *f = tofile(L);
00451 int op = luaL_checkoption(L, 2, NULL, modenames);
00452 lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
00453 int res = setvbuf(f, NULL, mode[op], sz);
00454 return pushresult(L, res == 0, NULL);
00455 }
00456
00457
00458
00459 static int io_flush (lua_State *L) {
00460 return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
00461 }
00462
00463
00464 static int f_flush (lua_State *L) {
00465 return pushresult(L, fflush(tofile(L)) == 0, NULL);
00466 }
00467
00468
00469 static const luaL_Reg iolib[] = {
00470 {"close", io_close},
00471 {"flush", io_flush},
00472 {"input", io_input},
00473 {"lines", io_lines},
00474 {"open", io_open},
00475 {"output", io_output},
00476 {"popen", io_popen},
00477 {"read", io_read},
00478 {"tmpfile", io_tmpfile},
00479 {"type", io_type},
00480 {"write", io_write},
00481 {NULL, NULL}
00482 };
00483
00484
00485 static const luaL_Reg flib[] = {
00486 {"close", io_close},
00487 {"flush", f_flush},
00488 {"lines", f_lines},
00489 {"read", f_read},
00490 {"seek", f_seek},
00491 {"setvbuf", f_setvbuf},
00492 {"write", f_write},
00493 {"__gc", io_gc},
00494 {"__tostring", io_tostring},
00495 {NULL, NULL}
00496 };
00497
00498
00499 static void createmeta (lua_State *L) {
00500 luaL_newmetatable(L, LUA_FILEHANDLE);
00501 lua_pushvalue(L, -1);
00502 lua_setfield(L, -2, "__index");
00503 luaL_register(L, NULL, flib);
00504 }
00505
00506
00507 static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
00508 *newfile(L) = f;
00509 if (k > 0) {
00510 lua_pushvalue(L, -1);
00511 lua_rawseti(L, LUA_ENVIRONINDEX, k);
00512 }
00513 lua_setfield(L, -2, fname);
00514 }
00515
00516
00517 LUALIB_API int luaopen_io (lua_State *L) {
00518 createmeta(L);
00519
00520 lua_createtable(L, 2, 1);
00521 lua_replace(L, LUA_ENVIRONINDEX);
00522
00523 luaL_register(L, LUA_IOLIBNAME, iolib);
00524
00525 createstdfile(L, stdin, IO_INPUT, "stdin");
00526 createstdfile(L, stdout, IO_OUTPUT, "stdout");
00527 createstdfile(L, stderr, 0, "stderr");
00528
00529 lua_getfield(L, -1, "popen");
00530 lua_createtable(L, 0, 1);
00531 lua_pushcfunction(L, io_pclose);
00532 lua_setfield(L, -2, "__close");
00533 lua_setfenv(L, -2);
00534 lua_pop(L, 1);
00535
00536 lua_pushcfunction(L, io_fclose);
00537 lua_setfield(L, LUA_ENVIRONINDEX, "__close");
00538 return 1;
00539 }
00540