diff options
-rw-r--r-- | liolib.c | 99 |
1 files changed, 66 insertions, 33 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: liolib.c,v 2.60 2005/05/16 21:19:00 roberto Exp roberto $ | 2 | ** $Id: liolib.c,v 2.61 2005/05/25 13:21:26 roberto Exp roberto $ |
3 | ** Standard I/O (and system) library | 3 | ** Standard I/O (and system) library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -20,8 +20,8 @@ | |||
20 | 20 | ||
21 | 21 | ||
22 | 22 | ||
23 | #define IO_INPUT 1 | 23 | #define IO_INPUT 1 |
24 | #define IO_OUTPUT 2 | 24 | #define IO_OUTPUT 2 |
25 | 25 | ||
26 | 26 | ||
27 | static const char *const fnames[] = {"input", "output"}; | 27 | static const char *const fnames[] = {"input", "output"}; |
@@ -91,29 +91,45 @@ static FILE **newfile (lua_State *L) { | |||
91 | } | 91 | } |
92 | 92 | ||
93 | 93 | ||
94 | /* | ||
95 | ** this function has a separated environment, which defines the | ||
96 | ** correct __close for 'popen' files | ||
97 | */ | ||
98 | static int io_pclose (lua_State *L) { | ||
99 | FILE **p = topfile(L); | ||
100 | int ok = lua_pclose(L, *p); | ||
101 | if (ok) *p = NULL; | ||
102 | return pushresult(L, ok, NULL); | ||
103 | } | ||
104 | |||
105 | |||
106 | static int io_fclose (lua_State *L) { | ||
107 | FILE **p = topfile(L); | ||
108 | int ok = (fclose(*p) == 0); | ||
109 | if (ok) *p = NULL; | ||
110 | return pushresult(L, ok, NULL); | ||
111 | } | ||
112 | |||
113 | |||
94 | static int aux_close (lua_State *L) { | 114 | static int aux_close (lua_State *L) { |
95 | FILE *f = tofile(L); | 115 | lua_getfenv(L, 1); |
96 | if (f == stdin || f == stdout || f == stderr) | 116 | lua_getfield(L, -1, "__close"); |
97 | return 0; /* file cannot be closed */ | 117 | return (lua_tocfunction(L, -1))(L); |
98 | else { | ||
99 | int ok = (fclose(f) == 0); | ||
100 | if (ok) | ||
101 | *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ | ||
102 | return ok; | ||
103 | } | ||
104 | } | 118 | } |
105 | 119 | ||
106 | 120 | ||
107 | static int io_close (lua_State *L) { | 121 | static int io_close (lua_State *L) { |
108 | if (lua_isnone(L, 1)) | 122 | if (lua_isnone(L, 1)) |
109 | lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); | 123 | lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); |
110 | return pushresult(L, aux_close(L), NULL); | 124 | tofile(L); /* make sure argument is a file */ |
125 | return aux_close(L); | ||
111 | } | 126 | } |
112 | 127 | ||
113 | 128 | ||
114 | static int io_gc (lua_State *L) { | 129 | static int io_gc (lua_State *L) { |
115 | FILE **f = topfile(L); | 130 | FILE *f = *topfile(L); |
116 | if (*f != NULL) /* ignore closed files */ | 131 | /* ignore closed files and standard files */ |
132 | if (f != NULL && f != stdin && f != stdout && f != stderr) | ||
117 | aux_close(L); | 133 | aux_close(L); |
118 | return 0; | 134 | return 0; |
119 | } | 135 | } |
@@ -138,6 +154,15 @@ static int io_open (lua_State *L) { | |||
138 | } | 154 | } |
139 | 155 | ||
140 | 156 | ||
157 | static int io_popen (lua_State *L) { | ||
158 | const char *filename = luaL_checkstring(L, 1); | ||
159 | const char *mode = luaL_optstring(L, 2, "r"); | ||
160 | FILE **pf = newfile(L); | ||
161 | *pf = lua_popen(L, filename, mode); | ||
162 | return (*pf == NULL) ? pushresult(L, 0, filename) : 1; | ||
163 | } | ||
164 | |||
165 | |||
141 | static int io_tmpfile (lua_State *L) { | 166 | static int io_tmpfile (lua_State *L) { |
142 | FILE **pf = newfile(L); | 167 | FILE **pf = newfile(L); |
143 | *pf = tmpfile(); | 168 | *pf = tmpfile(); |
@@ -352,7 +377,7 @@ static int io_readline (lua_State *L) { | |||
352 | luaL_error(L, "file is already closed"); | 377 | luaL_error(L, "file is already closed"); |
353 | sucess = read_line(L, f); | 378 | sucess = read_line(L, f); |
354 | if (ferror(f)) | 379 | if (ferror(f)) |
355 | luaL_error(L, "%s", strerror(errno)); | 380 | return luaL_error(L, "%s", strerror(errno)); |
356 | if (sucess) return 1; | 381 | if (sucess) return 1; |
357 | else { /* EOF */ | 382 | else { /* EOF */ |
358 | if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ | 383 | if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ |
@@ -439,6 +464,7 @@ static const luaL_reg iolib[] = { | |||
439 | {"close", io_close}, | 464 | {"close", io_close}, |
440 | {"flush", io_flush}, | 465 | {"flush", io_flush}, |
441 | {"open", io_open}, | 466 | {"open", io_open}, |
467 | {"popen", io_popen}, | ||
442 | {"read", io_read}, | 468 | {"read", io_read}, |
443 | {"tmpfile", io_tmpfile}, | 469 | {"tmpfile", io_tmpfile}, |
444 | {"type", io_type}, | 470 | {"type", io_type}, |
@@ -469,30 +495,37 @@ static void createmeta (lua_State *L) { | |||
469 | } | 495 | } |
470 | 496 | ||
471 | 497 | ||
472 | static void createupval (lua_State *L) { | 498 | static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { |
473 | lua_newtable(L); | 499 | *newfile(L) = f; |
474 | /* create (and set) default files */ | 500 | if (k > 0) { |
475 | *newfile(L) = stdin; | 501 | lua_pushvalue(L, -1); |
476 | lua_rawseti(L, -2, IO_INPUT); | 502 | lua_rawseti(L, LUA_ENVIRONINDEX, k); |
477 | *newfile(L) = stdout; | 503 | } |
478 | lua_rawseti(L, -2, IO_OUTPUT); | 504 | lua_setfield(L, -2, fname); |
479 | } | 505 | } |
480 | 506 | ||
481 | 507 | ||
482 | |||
483 | LUALIB_API int luaopen_io (lua_State *L) { | 508 | LUALIB_API int luaopen_io (lua_State *L) { |
484 | createmeta(L); | 509 | createmeta(L); |
485 | createupval(L); | 510 | /* create new (private) environment */ |
486 | lua_pushvalue(L, -1); | 511 | lua_newtable(L); |
487 | lua_replace(L, LUA_ENVIRONINDEX); | 512 | lua_replace(L, LUA_ENVIRONINDEX); |
513 | /* open library */ | ||
488 | luaL_openlib(L, LUA_IOLIBNAME, iolib, 0); | 514 | luaL_openlib(L, LUA_IOLIBNAME, iolib, 0); |
489 | /* put predefined file handles into `io' table */ | 515 | /* create (and set) default files */ |
490 | lua_rawgeti(L, -2, IO_INPUT); /* get current input from upval */ | 516 | createstdfile(L, stdin, IO_INPUT, "stdin"); |
491 | lua_setfield(L, -2, "stdin"); /* io.stdin = upval[IO_INPUT] */ | 517 | createstdfile(L, stdout, IO_OUTPUT, "stdout"); |
492 | lua_rawgeti(L, -2, IO_OUTPUT); /* get current output from upval */ | 518 | createstdfile(L, stderr, 0, "stderr"); |
493 | lua_setfield(L, -2, "stdout"); /* io.stdout = upval[IO_OUTPUT] */ | 519 | /* create environment for 'popen' */ |
494 | *newfile(L) = stderr; | 520 | lua_getfield(L, -1, "popen"); |
495 | lua_setfield(L, -2, "stderr"); /* io.stderr = newfile(stderr) */ | 521 | lua_newtable(L); |
522 | lua_pushcfunction(L, io_pclose); | ||
523 | lua_setfield(L, -2, "__close"); | ||
524 | lua_setfenv(L, -2); | ||
525 | lua_pop(L, 1); /* pop 'popen' */ | ||
526 | /* set default close function */ | ||
527 | lua_pushcfunction(L, io_fclose); | ||
528 | lua_setfield(L, LUA_ENVIRONINDEX, "__close"); | ||
496 | return 1; | 529 | return 1; |
497 | } | 530 | } |
498 | 531 | ||