diff options
-rw-r--r-- | liolib.c | 90 |
1 files changed, 69 insertions, 21 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: liolib.c,v 2.16 2002/08/16 20:02:13 roberto Exp roberto $ | 2 | ** $Id: liolib.c,v 2.17 2002/08/21 14:57:48 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 | */ |
@@ -32,7 +32,6 @@ | |||
32 | 32 | ||
33 | 33 | ||
34 | #define FILEHANDLE "FileHandle" | 34 | #define FILEHANDLE "FileHandle" |
35 | #define CLOSEDFILEHANDLE "ClosedFileHandle" | ||
36 | 35 | ||
37 | #define IO_INPUT "_input" | 36 | #define IO_INPUT "_input" |
38 | #define IO_OUTPUT "_output" | 37 | #define IO_OUTPUT "_output" |
@@ -54,13 +53,17 @@ static int pushresult (lua_State *L, int i) { | |||
54 | 53 | ||
55 | static FILE *tofile (lua_State *L, int findex) { | 54 | static FILE *tofile (lua_State *L, int findex) { |
56 | FILE **f = (FILE **)lua_touserdata(L, findex); | 55 | FILE **f = (FILE **)lua_touserdata(L, findex); |
57 | if (f && lua_getmetatable(L, findex) && | 56 | if (f && *f && lua_getmetatable(L, findex) && |
58 | lua_rawequal(L, -1, lua_upvalueindex(1))) { | 57 | lua_rawequal(L, -1, lua_upvalueindex(1))) { |
59 | lua_pop(L, 1); | 58 | lua_pop(L, 1); |
60 | return *f; | 59 | return *f; |
61 | } | 60 | } |
62 | if (findex > 0) | 61 | if (findex > 0) { |
63 | luaL_argerror(L, findex, "bad file"); | 62 | if (f && *f == NULL) |
63 | luaL_error(L, "attempt to use a closed file"); | ||
64 | else | ||
65 | luaL_argerror(L, findex, "bad file"); | ||
66 | } | ||
64 | return NULL; | 67 | return NULL; |
65 | } | 68 | } |
66 | 69 | ||
@@ -96,22 +99,29 @@ static int setnewfile (lua_State *L, FILE *f) { | |||
96 | } | 99 | } |
97 | 100 | ||
98 | 101 | ||
102 | static int aux_close (lua_State *L) { | ||
103 | FILE *f = tofile(L, 1); | ||
104 | if (f == stdin || f == stdout || f == stderr) | ||
105 | return 0; /* file cannot be closed */ | ||
106 | *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ | ||
107 | return (pclose(f) != -1) || (fclose(f) == 0); | ||
108 | } | ||
109 | |||
110 | |||
99 | static int io_close (lua_State *L) { | 111 | static int io_close (lua_State *L) { |
100 | FILE *f; | ||
101 | int status = 1; | ||
102 | if (lua_isnone(L, 1)) { | 112 | if (lua_isnone(L, 1)) { |
103 | lua_pushstring(L, IO_OUTPUT); | 113 | lua_pushstring(L, IO_OUTPUT); |
104 | lua_rawget(L, lua_upvalueindex(1)); | 114 | lua_rawget(L, lua_upvalueindex(1)); |
105 | } | 115 | } |
106 | f = tofile(L, 1); | 116 | return pushresult(L, aux_close(L)); |
107 | if (f != stdin && f != stdout && f != stderr) { | 117 | } |
108 | lua_settop(L, 1); /* make sure file is on top */ | 118 | |
109 | lua_pushliteral(L, CLOSEDFILEHANDLE); | 119 | |
110 | lua_rawget(L, LUA_REGISTRYINDEX); | 120 | static int io_gc (lua_State *L) { |
111 | lua_setmetatable(L, 1); | 121 | FILE **f = (FILE **)lua_touserdata(L, 1); |
112 | status = (pclose(f) != -1) || (fclose(f) == 0); | 122 | if (!(f && *f == NULL)) /* ignore closed files */ |
113 | } | 123 | aux_close(L); |
114 | return pushresult(L, status); | 124 | return 0; |
115 | } | 125 | } |
116 | 126 | ||
117 | 127 | ||
@@ -182,6 +192,30 @@ static int io_output (lua_State *L) { | |||
182 | } | 192 | } |
183 | 193 | ||
184 | 194 | ||
195 | static int io_readline (lua_State *L); | ||
196 | |||
197 | static int io_lines (lua_State *L) { | ||
198 | FILE *f = fopen(luaL_check_string(L, 1), "r"); | ||
199 | luaL_arg_check(L, f, 1, strerror(errno)); | ||
200 | lua_pushliteral(L, FILEHANDLE); | ||
201 | lua_rawget(L, LUA_REGISTRYINDEX); | ||
202 | newfile(L, f); | ||
203 | lua_pushboolean(L, 1); /* must close file when finished */ | ||
204 | lua_pushcclosure(L, io_readline, 3); | ||
205 | return 1; | ||
206 | } | ||
207 | |||
208 | static int f_lines (lua_State *L) { | ||
209 | tofile(L, 1); /* check that it's a valid file handle */ | ||
210 | lua_pushliteral(L, FILEHANDLE); | ||
211 | lua_rawget(L, LUA_REGISTRYINDEX); | ||
212 | lua_pushvalue(L, 1); | ||
213 | lua_pushboolean(L, 0); /* does not close file when finished */ | ||
214 | lua_pushcclosure(L, io_readline, 3); | ||
215 | return 1; | ||
216 | } | ||
217 | |||
218 | |||
185 | /* | 219 | /* |
186 | ** {====================================================== | 220 | ** {====================================================== |
187 | ** READ | 221 | ** READ |
@@ -303,6 +337,22 @@ static int f_read (lua_State *L) { | |||
303 | return g_read(L, tofile(L, 1), 2); | 337 | return g_read(L, tofile(L, 1), 2); |
304 | } | 338 | } |
305 | 339 | ||
340 | |||
341 | static int io_readline (lua_State *L) { | ||
342 | FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); | ||
343 | if (f == NULL) /* file is already closed? */ | ||
344 | luaL_error(L, "file is already closed"); | ||
345 | if (read_line(L, f)) return 1; | ||
346 | else { /* EOF */ | ||
347 | if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ | ||
348 | lua_settop(L, 0); | ||
349 | lua_pushvalue(L, lua_upvalueindex(2)); | ||
350 | aux_close(L); /* close it */ | ||
351 | } | ||
352 | return 0; | ||
353 | } | ||
354 | } | ||
355 | |||
306 | /* }====================================================== */ | 356 | /* }====================================================== */ |
307 | 357 | ||
308 | 358 | ||
@@ -366,6 +416,7 @@ static int f_flush (lua_State *L) { | |||
366 | static const luaL_reg iolib[] = { | 416 | static const luaL_reg iolib[] = { |
367 | {"input", io_input}, | 417 | {"input", io_input}, |
368 | {"output", io_output}, | 418 | {"output", io_output}, |
419 | {"lines", io_lines}, | ||
369 | {"close", io_close}, | 420 | {"close", io_close}, |
370 | {"flush", io_flush}, | 421 | {"flush", io_flush}, |
371 | {"open", io_open}, | 422 | {"open", io_open}, |
@@ -380,6 +431,7 @@ static const luaL_reg iolib[] = { | |||
380 | static const luaL_reg flib[] = { | 431 | static const luaL_reg flib[] = { |
381 | {"flush", f_flush}, | 432 | {"flush", f_flush}, |
382 | {"read", f_read}, | 433 | {"read", f_read}, |
434 | {"lines", f_lines}, | ||
383 | {"seek", f_seek}, | 435 | {"seek", f_seek}, |
384 | {"write", f_write}, | 436 | {"write", f_write}, |
385 | {"close", io_close}, | 437 | {"close", io_close}, |
@@ -393,7 +445,7 @@ static void createmeta (lua_State *L) { | |||
393 | /* close files when collected */ | 445 | /* close files when collected */ |
394 | lua_pushliteral(L, "__gc"); /* S: `gc' mt FH */ | 446 | lua_pushliteral(L, "__gc"); /* S: `gc' mt FH */ |
395 | lua_pushvalue(L, -2); /* S: mt `gc' mt FH */ | 447 | lua_pushvalue(L, -2); /* S: mt `gc' mt FH */ |
396 | lua_pushcclosure(L, io_close, 1); /* S: close `gc' mt FH */ | 448 | lua_pushcclosure(L, io_gc, 1); /* S: close `gc' mt FH */ |
397 | lua_rawset(L, -3); /* S: mt FH */ | 449 | lua_rawset(L, -3); /* S: mt FH */ |
398 | /* file methods */ | 450 | /* file methods */ |
399 | lua_pushliteral(L, "__gettable"); /* S: `gettable' mt FH */ | 451 | lua_pushliteral(L, "__gettable"); /* S: `gettable' mt FH */ |
@@ -403,10 +455,6 @@ static void createmeta (lua_State *L) { | |||
403 | luaL_openlib(L, flib, 1); /* S: mt FH */ | 455 | luaL_openlib(L, flib, 1); /* S: mt FH */ |
404 | /* put new metatable into registry */ | 456 | /* put new metatable into registry */ |
405 | lua_rawset(L, LUA_REGISTRYINDEX); /* S: empty */ | 457 | lua_rawset(L, LUA_REGISTRYINDEX); /* S: empty */ |
406 | /* meta table for CLOSEDFILEHANDLE */ | ||
407 | lua_pushliteral(L, CLOSEDFILEHANDLE); | ||
408 | lua_newtable(L); | ||
409 | lua_rawset(L, LUA_REGISTRYINDEX); | ||
410 | } | 458 | } |
411 | 459 | ||
412 | /* }====================================================== */ | 460 | /* }====================================================== */ |