diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-06-21 10:43:48 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-06-21 10:43:48 -0300 |
| commit | 801f43f09a3c95a2ec4011a0dc8558ba25a0cc72 (patch) | |
| tree | cf17e31d416bba8ddb7ca1d0342bc2fe1b40ee10 | |
| parent | 719c01359f797e3933a7a69b541d7e57e149d061 (diff) | |
| download | lua-801f43f09a3c95a2ec4011a0dc8558ba25a0cc72.tar.gz lua-801f43f09a3c95a2ec4011a0dc8558ba25a0cc72.tar.bz2 lua-801f43f09a3c95a2ec4011a0dc8558ba25a0cc72.zip | |
change in the representation of file handles
| -rw-r--r-- | liolib.c | 267 |
1 files changed, 128 insertions, 139 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: liolib.c,v 2.98 2011/02/21 19:12:54 roberto Exp roberto $ | 2 | ** $Id: liolib.c,v 2.99 2011/03/03 16:34:46 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 | */ |
| @@ -19,8 +19,6 @@ | |||
| 19 | #include "lualib.h" | 19 | #include "lualib.h" |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | #define MAX_SIZE_T (~(size_t)0) | ||
| 23 | |||
| 24 | 22 | ||
| 25 | /* | 23 | /* |
| 26 | ** lua_popen spawns a new process connected to the current one through | 24 | ** lua_popen spawns a new process connected to the current one through |
| @@ -51,11 +49,15 @@ | |||
| 51 | #endif /* } */ | 49 | #endif /* } */ |
| 52 | 50 | ||
| 53 | 51 | ||
| 54 | #define IO_INPUT 1 | 52 | #define IO_PREFIX "lua_io_" |
| 55 | #define IO_OUTPUT 2 | 53 | #define IO_INPUT (IO_PREFIX "input") |
| 54 | #define IO_OUTPUT (IO_PREFIX "output") | ||
| 56 | 55 | ||
| 57 | 56 | ||
| 58 | static const char *const fnames[] = {"input", "output"}; | 57 | typedef struct LStream { |
| 58 | FILE *f; /* stream */ | ||
| 59 | lua_CFunction closef; /* to close stream (NULL for closed streams) */ | ||
| 60 | } LStream; | ||
| 59 | 61 | ||
| 60 | 62 | ||
| 61 | static void fileerror (lua_State *L, int arg, const char *filename) { | 63 | static void fileerror (lua_State *L, int arg, const char *filename) { |
| @@ -64,16 +66,18 @@ static void fileerror (lua_State *L, int arg, const char *filename) { | |||
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | 68 | ||
| 67 | #define tofilep(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) | 69 | #define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) |
| 70 | |||
| 71 | #define isclosed(p) ((p)->closef == NULL) | ||
| 68 | 72 | ||
| 69 | 73 | ||
| 70 | static int io_type (lua_State *L) { | 74 | static int io_type (lua_State *L) { |
| 71 | void *ud; | 75 | LStream *p; |
| 72 | luaL_checkany(L, 1); | 76 | luaL_checkany(L, 1); |
| 73 | ud = luaL_testudata(L, 1, LUA_FILEHANDLE); | 77 | p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); |
| 74 | if (ud == NULL) | 78 | if (p == NULL) |
| 75 | lua_pushnil(L); /* not a file */ | 79 | lua_pushnil(L); /* not a file */ |
| 76 | else if (*((FILE **)ud) == NULL) | 80 | else if (isclosed(p)) |
| 77 | lua_pushliteral(L, "closed file"); | 81 | lua_pushliteral(L, "closed file"); |
| 78 | else | 82 | else |
| 79 | lua_pushliteral(L, "file"); | 83 | lua_pushliteral(L, "file"); |
| @@ -81,11 +85,22 @@ static int io_type (lua_State *L) { | |||
| 81 | } | 85 | } |
| 82 | 86 | ||
| 83 | 87 | ||
| 88 | static int f_tostring (lua_State *L) { | ||
| 89 | LStream *p = tolstream(L); | ||
| 90 | if (isclosed(p)) | ||
| 91 | lua_pushliteral(L, "file (closed)"); | ||
| 92 | else | ||
| 93 | lua_pushfstring(L, "file (%p)", p->f); | ||
| 94 | return 1; | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 84 | static FILE *tofile (lua_State *L) { | 98 | static FILE *tofile (lua_State *L) { |
| 85 | FILE **f = tofilep(L); | 99 | LStream *p = tolstream(L); |
| 86 | if (*f == NULL) | 100 | if (isclosed(p)) |
| 87 | luaL_error(L, "attempt to use a closed file"); | 101 | luaL_error(L, "attempt to use a closed file"); |
| 88 | return *f; | 102 | lua_assert(p->f); |
| 103 | return p->f; | ||
| 89 | } | 104 | } |
| 90 | 105 | ||
| 91 | 106 | ||
| @@ -94,40 +109,35 @@ static FILE *tofile (lua_State *L) { | |||
| 94 | ** before opening the actual file; so, if there is a memory error, the | 109 | ** before opening the actual file; so, if there is a memory error, the |
| 95 | ** file is not left opened. | 110 | ** file is not left opened. |
| 96 | */ | 111 | */ |
| 97 | static FILE **newprefile (lua_State *L) { | 112 | static LStream *newprefile (lua_State *L) { |
| 98 | FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); | 113 | LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); |
| 99 | *pf = NULL; /* file handle is currently `closed' */ | 114 | p->closef = NULL; /* mark file handle as 'closed' */ |
| 100 | luaL_setmetatable(L, LUA_FILEHANDLE); | 115 | luaL_setmetatable(L, LUA_FILEHANDLE); |
| 101 | return pf; | 116 | return p; |
| 102 | } | 117 | } |
| 103 | 118 | ||
| 104 | 119 | ||
| 105 | static FILE **newfile (lua_State *L) { | 120 | static int aux_close (lua_State *L) { |
| 106 | FILE **pf = newprefile(L); | 121 | LStream *p = tolstream(L); |
| 107 | lua_pushvalue(L, lua_upvalueindex(1)); /* set upvalue... */ | 122 | lua_CFunction cf = p->closef; |
| 108 | lua_setuservalue(L, -2); /* ... as environment for new file */ | 123 | p->closef = NULL; /* mark stream as closed */ |
| 109 | return pf; | 124 | return (*cf)(L); /* close it */ |
| 110 | } | 125 | } |
| 111 | 126 | ||
| 112 | 127 | ||
| 113 | /* | 128 | static int io_close (lua_State *L) { |
| 114 | ** function to (not) close the standard files stdin, stdout, and stderr | 129 | if (lua_isnone(L, 1)) /* no argument? */ |
| 115 | */ | 130 | lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ |
| 116 | static int io_noclose (lua_State *L) { | 131 | tofile(L); /* make sure argument is an open stream */ |
| 117 | lua_pushnil(L); | 132 | return aux_close(L); |
| 118 | lua_pushliteral(L, "cannot close standard file"); | ||
| 119 | return 2; | ||
| 120 | } | 133 | } |
| 121 | 134 | ||
| 122 | 135 | ||
| 123 | /* | 136 | static int f_gc (lua_State *L) { |
| 124 | ** function to close 'popen' files | 137 | LStream *p = tolstream(L); |
| 125 | */ | 138 | if (!isclosed(p) && p->f != NULL) |
| 126 | static int io_pclose (lua_State *L) { | 139 | aux_close(L); /* ignore closed and incompletely open files */ |
| 127 | FILE **p = tofilep(L); | 140 | return 0; |
| 128 | int stat = lua_pclose(L, *p); | ||
| 129 | *p = NULL; /* mark stream as closed (for GC) */ | ||
| 130 | return luaL_execresult(L, stat); | ||
| 131 | } | 141 | } |
| 132 | 142 | ||
| 133 | 143 | ||
| @@ -135,111 +145,90 @@ static int io_pclose (lua_State *L) { | |||
| 135 | ** function to close regular files | 145 | ** function to close regular files |
| 136 | */ | 146 | */ |
| 137 | static int io_fclose (lua_State *L) { | 147 | static int io_fclose (lua_State *L) { |
| 138 | FILE **p = tofilep(L); | 148 | LStream *p = tolstream(L); |
| 139 | int ok = (fclose(*p) == 0); | 149 | int res = fclose(p->f); |
| 140 | *p = NULL; /* mark stream as closed (for GC) */ | 150 | return luaL_fileresult(L, (res == 0), NULL); |
| 141 | return luaL_fileresult(L, ok, NULL); | ||
| 142 | } | 151 | } |
| 143 | 152 | ||
| 144 | 153 | ||
| 145 | static int aux_close (lua_State *L) { | 154 | static LStream *newfile (lua_State *L) { |
| 146 | lua_getuservalue(L, 1); | 155 | LStream *p = newprefile(L); |
| 147 | lua_getfield(L, -1, "__close"); | 156 | p->f = NULL; |
| 148 | return (lua_tocfunction(L, -1))(L); | 157 | p->closef = &io_fclose; |
| 149 | } | 158 | return p; |
| 150 | |||
| 151 | |||
| 152 | static int io_close (lua_State *L) { | ||
| 153 | if (lua_isnone(L, 1)) | ||
| 154 | lua_rawgeti(L, lua_upvalueindex(1), IO_OUTPUT); | ||
| 155 | tofile(L); /* make sure argument is a file */ | ||
| 156 | return aux_close(L); | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | static int io_gc (lua_State *L) { | ||
| 161 | FILE *f = *tofilep(L); | ||
| 162 | if (f != NULL) /* ignore closed files */ | ||
| 163 | aux_close(L); | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | static int io_tostring (lua_State *L) { | ||
| 169 | FILE *f = *tofilep(L); | ||
| 170 | if (f == NULL) | ||
| 171 | lua_pushliteral(L, "file (closed)"); | ||
| 172 | else | ||
| 173 | lua_pushfstring(L, "file (%p)", f); | ||
| 174 | return 1; | ||
| 175 | } | 159 | } |
| 176 | 160 | ||
| 177 | 161 | ||
| 178 | static int io_open (lua_State *L) { | 162 | static int io_open (lua_State *L) { |
| 179 | const char *filename = luaL_checkstring(L, 1); | 163 | const char *filename = luaL_checkstring(L, 1); |
| 180 | const char *mode = luaL_optstring(L, 2, "r"); | 164 | const char *mode = luaL_optstring(L, 2, "r"); |
| 181 | FILE **pf; | 165 | LStream *p = newfile(L); |
| 182 | int i = 0; | 166 | int i = 0; |
| 183 | /* check whether 'mode' matches '[rwa]%+?b?' */ | 167 | /* check whether 'mode' matches '[rwa]%+?b?' */ |
| 184 | if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL && | 168 | if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL && |
| 185 | (mode[i] != '+' || ++i) && /* skip if char is '+' */ | 169 | (mode[i] != '+' || ++i) && /* skip if char is '+' */ |
| 186 | (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ | 170 | (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ |
| 187 | (mode[i] == '\0'))) | 171 | (mode[i] == '\0'))) |
| 188 | luaL_error(L, "invalid mode " LUA_QL("%s") | 172 | return luaL_error(L, "invalid mode " LUA_QL("%s") |
| 189 | " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); | 173 | " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); |
| 190 | pf = newfile(L); | 174 | p->f = fopen(filename, mode); |
| 191 | *pf = fopen(filename, mode); | 175 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; |
| 192 | return (*pf == NULL) ? luaL_fileresult(L, 0, filename) : 1; | ||
| 193 | } | 176 | } |
| 194 | 177 | ||
| 195 | 178 | ||
| 196 | /* | 179 | /* |
| 197 | ** this function has a separated environment, which defines the | 180 | ** function to close 'popen' files |
| 198 | ** correct __close for 'popen' files | ||
| 199 | */ | 181 | */ |
| 182 | static int io_pclose (lua_State *L) { | ||
| 183 | LStream *p = tolstream(L); | ||
| 184 | return luaL_execresult(L, lua_pclose(L, p->f)); | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 200 | static int io_popen (lua_State *L) { | 188 | static int io_popen (lua_State *L) { |
| 201 | const char *filename = luaL_checkstring(L, 1); | 189 | const char *filename = luaL_checkstring(L, 1); |
| 202 | const char *mode = luaL_optstring(L, 2, "r"); | 190 | const char *mode = luaL_optstring(L, 2, "r"); |
| 203 | FILE **pf = newfile(L); | 191 | LStream *p = newprefile(L); |
| 204 | *pf = lua_popen(L, filename, mode); | 192 | p->f = lua_popen(L, filename, mode); |
| 205 | return (*pf == NULL) ? luaL_fileresult(L, 0, filename) : 1; | 193 | p->closef = &io_pclose; |
| 194 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; | ||
| 206 | } | 195 | } |
| 207 | 196 | ||
| 208 | 197 | ||
| 209 | static int io_tmpfile (lua_State *L) { | 198 | static int io_tmpfile (lua_State *L) { |
| 210 | FILE **pf = newfile(L); | 199 | LStream *p = newfile(L); |
| 211 | *pf = tmpfile(); | 200 | p->f = tmpfile(); |
| 212 | return (*pf == NULL) ? luaL_fileresult(L, 0, NULL) : 1; | 201 | return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; |
| 213 | } | 202 | } |
| 214 | 203 | ||
| 215 | 204 | ||
| 216 | static FILE *getiofile (lua_State *L, int findex) { | 205 | static FILE *getiofile (lua_State *L, const char *findex) { |
| 217 | FILE *f; | 206 | LStream *p; |
| 218 | lua_rawgeti(L, lua_upvalueindex(1), findex); | 207 | lua_getfield(L, LUA_REGISTRYINDEX, findex); |
| 219 | f = *(FILE **)lua_touserdata(L, -1); | 208 | p = (LStream *)lua_touserdata(L, -1); |
| 220 | if (f == NULL) | 209 | if (isclosed(p)) |
| 221 | luaL_error(L, "standard %s file is closed", fnames[findex - 1]); | 210 | luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); |
| 222 | return f; | 211 | return p->f; |
| 223 | } | 212 | } |
| 224 | 213 | ||
| 225 | 214 | ||
| 226 | static int g_iofile (lua_State *L, int f, const char *mode) { | 215 | static int g_iofile (lua_State *L, const char *f, const char *mode) { |
| 227 | if (!lua_isnoneornil(L, 1)) { | 216 | if (!lua_isnoneornil(L, 1)) { |
| 228 | const char *filename = lua_tostring(L, 1); | 217 | const char *filename = lua_tostring(L, 1); |
| 229 | if (filename) { | 218 | if (filename) { |
| 230 | FILE **pf = newfile(L); | 219 | LStream *p = newfile(L); |
| 231 | *pf = fopen(filename, mode); | 220 | p->f = fopen(filename, mode); |
| 232 | if (*pf == NULL) | 221 | if (p->f == NULL) |
| 233 | fileerror(L, 1, filename); | 222 | fileerror(L, 1, filename); |
| 234 | } | 223 | } |
| 235 | else { | 224 | else { |
| 236 | tofile(L); /* check that it's a valid file handle */ | 225 | tofile(L); /* check that it's a valid file handle */ |
| 237 | lua_pushvalue(L, 1); | 226 | lua_pushvalue(L, 1); |
| 238 | } | 227 | } |
| 239 | lua_rawseti(L, lua_upvalueindex(1), f); | 228 | lua_setfield(L, LUA_REGISTRYINDEX, f); |
| 240 | } | 229 | } |
| 241 | /* return current value */ | 230 | /* return current value */ |
| 242 | lua_rawgeti(L, lua_upvalueindex(1), f); | 231 | lua_getfield(L, LUA_REGISTRYINDEX, f); |
| 243 | return 1; | 232 | return 1; |
| 244 | } | 233 | } |
| 245 | 234 | ||
| @@ -281,16 +270,16 @@ static int io_lines (lua_State *L) { | |||
| 281 | int toclose; | 270 | int toclose; |
| 282 | if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ | 271 | if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ |
| 283 | if (lua_isnil(L, 1)) { /* no file name? */ | 272 | if (lua_isnil(L, 1)) { /* no file name? */ |
| 284 | lua_rawgeti(L, lua_upvalueindex(1), IO_INPUT); /* get default input */ | 273 | lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ |
| 285 | lua_replace(L, 1); /* put it at index 1 */ | 274 | lua_replace(L, 1); /* put it at index 1 */ |
| 286 | tofile(L); /* check that it's a valid file handle */ | 275 | tofile(L); /* check that it's a valid file handle */ |
| 287 | toclose = 0; /* do not close it after iteration */ | 276 | toclose = 0; /* do not close it after iteration */ |
| 288 | } | 277 | } |
| 289 | else { /* open a new file */ | 278 | else { /* open a new file */ |
| 290 | const char *filename = luaL_checkstring(L, 1); | 279 | const char *filename = luaL_checkstring(L, 1); |
| 291 | FILE **pf = newfile(L); | 280 | LStream *p = newfile(L); |
| 292 | *pf = fopen(filename, "r"); | 281 | p->f = fopen(filename, "r"); |
| 293 | if (*pf == NULL) | 282 | if (p->f == NULL) |
| 294 | fileerror(L, 1, filename); | 283 | fileerror(L, 1, filename); |
| 295 | lua_replace(L, 1); /* put file at index 1 */ | 284 | lua_replace(L, 1); /* put file at index 1 */ |
| 296 | toclose = 1; /* close it after iteration */ | 285 | toclose = 1; /* close it after iteration */ |
| @@ -350,6 +339,8 @@ static int read_line (lua_State *L, FILE *f, int chop) { | |||
| 350 | } | 339 | } |
| 351 | 340 | ||
| 352 | 341 | ||
| 342 | #define MAX_SIZE_T (~(size_t)0) | ||
| 343 | |||
| 353 | static void read_all (lua_State *L, FILE *f) { | 344 | static void read_all (lua_State *L, FILE *f) { |
| 354 | size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ | 345 | size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ |
| 355 | luaL_Buffer b; | 346 | luaL_Buffer b; |
| @@ -440,15 +431,15 @@ static int f_read (lua_State *L) { | |||
| 440 | 431 | ||
| 441 | 432 | ||
| 442 | static int io_readline (lua_State *L) { | 433 | static int io_readline (lua_State *L) { |
| 443 | FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); | 434 | LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); |
| 444 | int i; | 435 | int i; |
| 445 | int n = (int)lua_tointeger(L, lua_upvalueindex(2)); | 436 | int n = (int)lua_tointeger(L, lua_upvalueindex(2)); |
| 446 | if (f == NULL) /* file is already closed? */ | 437 | if (isclosed(p)) /* file is already closed? */ |
| 447 | luaL_error(L, "file is already closed"); | 438 | return luaL_error(L, "file is already closed"); |
| 448 | lua_settop(L , 1); | 439 | lua_settop(L , 1); |
| 449 | for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ | 440 | for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ |
| 450 | lua_pushvalue(L, lua_upvalueindex(3 + i)); | 441 | lua_pushvalue(L, lua_upvalueindex(3 + i)); |
| 451 | n = g_read(L, f, 2); /* 'n' is number of results */ | 442 | n = g_read(L, p->f, 2); /* 'n' is number of results */ |
| 452 | lua_assert(n > 0); /* should return at least a nil */ | 443 | lua_assert(n > 0); /* should return at least a nil */ |
| 453 | if (!lua_isnil(L, -n)) /* read at least one value? */ | 444 | if (!lua_isnil(L, -n)) /* read at least one value? */ |
| 454 | return n; /* return them */ | 445 | return n; /* return them */ |
| @@ -494,7 +485,7 @@ static int io_write (lua_State *L) { | |||
| 494 | 485 | ||
| 495 | 486 | ||
| 496 | static int f_write (lua_State *L) { | 487 | static int f_write (lua_State *L) { |
| 497 | FILE * f = tofile(L); | 488 | FILE *f = tofile(L); |
| 498 | lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ | 489 | lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ |
| 499 | return g_write(L, f, 2); | 490 | return g_write(L, f, 2); |
| 500 | } | 491 | } |
| @@ -538,6 +529,9 @@ static int f_flush (lua_State *L) { | |||
| 538 | } | 529 | } |
| 539 | 530 | ||
| 540 | 531 | ||
| 532 | /* | ||
| 533 | ** functions for 'io' library | ||
| 534 | */ | ||
| 541 | static const luaL_Reg iolib[] = { | 535 | static const luaL_Reg iolib[] = { |
| 542 | {"close", io_close}, | 536 | {"close", io_close}, |
| 543 | {"flush", io_flush}, | 537 | {"flush", io_flush}, |
| @@ -554,6 +548,9 @@ static const luaL_Reg iolib[] = { | |||
| 554 | }; | 548 | }; |
| 555 | 549 | ||
| 556 | 550 | ||
| 551 | /* | ||
| 552 | ** methods for file handles | ||
| 553 | */ | ||
| 557 | static const luaL_Reg flib[] = { | 554 | static const luaL_Reg flib[] = { |
| 558 | {"close", io_close}, | 555 | {"close", io_close}, |
| 559 | {"flush", f_flush}, | 556 | {"flush", f_flush}, |
| @@ -562,8 +559,8 @@ static const luaL_Reg flib[] = { | |||
| 562 | {"seek", f_seek}, | 559 | {"seek", f_seek}, |
| 563 | {"setvbuf", f_setvbuf}, | 560 | {"setvbuf", f_setvbuf}, |
| 564 | {"write", f_write}, | 561 | {"write", f_write}, |
| 565 | {"__gc", io_gc}, | 562 | {"__gc", f_gc}, |
| 566 | {"__tostring", io_tostring}, | 563 | {"__tostring", f_tostring}, |
| 567 | {NULL, NULL} | 564 | {NULL, NULL} |
| 568 | }; | 565 | }; |
| 569 | 566 | ||
| @@ -577,46 +574,38 @@ static void createmeta (lua_State *L) { | |||
| 577 | } | 574 | } |
| 578 | 575 | ||
| 579 | 576 | ||
| 580 | static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) { | 577 | /* |
| 581 | *newprefile(L) = f; | 578 | ** function to (not) close the standard files stdin, stdout, and stderr |
| 582 | if (k > 0) { | 579 | */ |
| 583 | lua_pushvalue(L, -1); /* copy new file */ | 580 | static int io_noclose (lua_State *L) { |
| 584 | lua_rawseti(L, 1, k); /* add it to common upvalue */ | 581 | LStream *p = tolstream(L); |
| 585 | } | 582 | p->closef = &io_noclose; /* keep file opened */ |
| 586 | lua_pushvalue(L, 3); /* get environment for default files */ | 583 | lua_pushnil(L); |
| 587 | lua_setuservalue(L, -2); /* set it as environment for file */ | 584 | lua_pushliteral(L, "cannot close standard file"); |
| 588 | lua_setfield(L, 2, fname); /* add file to module */ | 585 | return 2; |
| 589 | } | 586 | } |
| 590 | 587 | ||
| 591 | 588 | ||
| 592 | /* | 589 | static void createstdfile (lua_State *L, FILE *f, const char *k, |
| 593 | ** pushes a new table with {__close = cls} | 590 | const char *fname) { |
| 594 | */ | 591 | LStream *p = newprefile(L); |
| 595 | static void newenv (lua_State *L, lua_CFunction cls) { | 592 | p->f = f; |
| 596 | lua_createtable(L, 0, 1); | 593 | p->closef = &io_noclose; |
| 597 | lua_pushcfunction(L, cls); | 594 | if (k != NULL) { |
| 598 | lua_setfield(L, -2, "__close"); | 595 | lua_pushvalue(L, -1); |
| 596 | lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ | ||
| 597 | } | ||
| 598 | lua_setfield(L, -2, fname); /* add file to module */ | ||
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | 601 | ||
| 602 | LUAMOD_API int luaopen_io (lua_State *L) { | 602 | LUAMOD_API int luaopen_io (lua_State *L) { |
| 603 | lua_settop(L, 0); | 603 | luaL_newlib(L, iolib); /* new module */ |
| 604 | createmeta(L); | 604 | createmeta(L); |
| 605 | /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ | ||
| 606 | newenv(L, io_fclose); /* upvalue for all io functions at index 1 */ | ||
| 607 | luaL_newlibtable(L, iolib); /* new module at index 2 */ | ||
| 608 | lua_pushvalue(L, 1); /* copy of env to be consumed by 'setfuncs' */ | ||
| 609 | luaL_setfuncs(L, iolib, 1); | ||
| 610 | /* create (and set) default files */ | 605 | /* create (and set) default files */ |
| 611 | newenv(L, io_noclose); /* environment for default files at index 3 */ | ||
| 612 | createstdfile(L, stdin, IO_INPUT, "stdin"); | 606 | createstdfile(L, stdin, IO_INPUT, "stdin"); |
| 613 | createstdfile(L, stdout, IO_OUTPUT, "stdout"); | 607 | createstdfile(L, stdout, IO_OUTPUT, "stdout"); |
| 614 | createstdfile(L, stderr, 0, "stderr"); | 608 | createstdfile(L, stderr, NULL, "stderr"); |
| 615 | lua_pop(L, 1); /* pop environment for default files */ | ||
| 616 | lua_getfield(L, 2, "popen"); | ||
| 617 | newenv(L, io_pclose); /* create environment for 'popen' streams */ | ||
| 618 | lua_setupvalue(L, -2, 1); /* set it as upvalue for 'popen' */ | ||
| 619 | lua_pop(L, 1); /* pop 'popen' */ | ||
| 620 | return 1; | 609 | return 1; |
| 621 | } | 610 | } |
| 622 | 611 | ||
