aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--liolib.c267
1 files changed, 128 insertions, 139 deletions
diff --git a/liolib.c b/liolib.c
index a688ad93..2f3920d3 100644
--- a/liolib.c
+++ b/liolib.c
@@ -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
58static const char *const fnames[] = {"input", "output"}; 57typedef struct LStream {
58 FILE *f; /* stream */
59 lua_CFunction closef; /* to close stream (NULL for closed streams) */
60} LStream;
59 61
60 62
61static void fileerror (lua_State *L, int arg, const char *filename) { 63static 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
70static int io_type (lua_State *L) { 74static 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
88static 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
84static FILE *tofile (lua_State *L) { 98static 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*/
97static FILE **newprefile (lua_State *L) { 112static 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
105static FILE **newfile (lua_State *L) { 120static 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/* 128static 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 */
116static 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/* 136static 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)
126static 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*/
137static int io_fclose (lua_State *L) { 147static 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
145static int aux_close (lua_State *L) { 154static 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
152static 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
160static 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
168static 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
178static int io_open (lua_State *L) { 162static 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*/
182static int io_pclose (lua_State *L) {
183 LStream *p = tolstream(L);
184 return luaL_execresult(L, lua_pclose(L, p->f));
185}
186
187
200static int io_popen (lua_State *L) { 188static 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
209static int io_tmpfile (lua_State *L) { 198static 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
216static FILE *getiofile (lua_State *L, int findex) { 205static 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
226static int g_iofile (lua_State *L, int f, const char *mode) { 215static 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
353static void read_all (lua_State *L, FILE *f) { 344static 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
442static int io_readline (lua_State *L) { 433static 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
496static int f_write (lua_State *L) { 487static 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*/
541static const luaL_Reg iolib[] = { 535static 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*/
557static const luaL_Reg flib[] = { 554static 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
580static 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 */ 580static 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/* 589static 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);
595static 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
602LUAMOD_API int luaopen_io (lua_State *L) { 602LUAMOD_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