diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-03-20 16:13:45 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-03-20 16:13:45 -0300 |
commit | 67592998809bf5816e2256409b384a712270c7b2 (patch) | |
tree | 440bddae0ed82280b4f17096242141964b7e6657 | |
parent | da7eb34cd621325066df3e99a9af39fa0d036a85 (diff) | |
download | lua-67592998809bf5816e2256409b384a712270c7b2.tar.gz lua-67592998809bf5816e2256409b384a712270c7b2.tar.bz2 lua-67592998809bf5816e2256409b384a712270c7b2.zip |
new implementation for handling I/O tags + setglobal TM for tracing
changes in _INPUT/_OUTPUT
-rw-r--r-- | liolib.c | 256 |
1 files changed, 136 insertions, 120 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: liolib.c,v 1.57 2000/02/08 16:34:31 roberto Exp roberto $ | 2 | ** $Id: liolib.c,v 1.58 2000/03/03 14:58: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 | */ |
@@ -35,16 +35,6 @@ | |||
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | 37 | ||
38 | #define IOTAG 1 | ||
39 | |||
40 | #define FIRSTARG 2 /* 1st is upvalue */ | ||
41 | |||
42 | #define CLOSEDTAG(L, tag) ((tag)-1) /* assume that CLOSEDTAG = iotag-1 */ | ||
43 | |||
44 | |||
45 | #define FINPUT "_INPUT" | ||
46 | #define FOUTPUT "_OUTPUT" | ||
47 | |||
48 | 38 | ||
49 | #ifdef POPEN | 39 | #ifdef POPEN |
50 | /* FILE *popen(); | 40 | /* FILE *popen(); |
@@ -57,6 +47,42 @@ int pclose(); */ | |||
57 | #endif | 47 | #endif |
58 | 48 | ||
59 | 49 | ||
50 | #define INFILE 0 | ||
51 | #define OUTFILE 1 | ||
52 | |||
53 | typedef struct IOCtrl { | ||
54 | FILE *file[2]; /* values of _INPUT and _OUTPUT */ | ||
55 | int iotag; /* tag for file handles */ | ||
56 | int closedtag; /* tag for closed handles */ | ||
57 | } IOCtrl; | ||
58 | |||
59 | |||
60 | |||
61 | static const char *const filenames[] = {"_INPUT", "_OUTPUT", NULL}; | ||
62 | |||
63 | |||
64 | static void atribTM (lua_State *L) { | ||
65 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); | ||
66 | const char *varname = luaL_check_string(L, 2); | ||
67 | lua_Object newvalue = lua_getparam(L, 4); | ||
68 | int inout; | ||
69 | if ((inout = luaL_findstring(varname, filenames)) != -1) { | ||
70 | if (lua_tag(L, newvalue) != ctrl->iotag) | ||
71 | luaL_verror(L, "%.20s value must be a valid file handle", | ||
72 | filenames[inout]); | ||
73 | ctrl->file[inout] = (FILE *)lua_getuserdata(L, newvalue); | ||
74 | } | ||
75 | /* set the actual variable */ | ||
76 | lua_pushobject(L, newvalue); | ||
77 | lua_rawsetglobal(L, varname); | ||
78 | } | ||
79 | |||
80 | |||
81 | static void ctrl_collect (lua_State *L) { | ||
82 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); | ||
83 | free(ctrl); | ||
84 | } | ||
85 | |||
60 | 86 | ||
61 | static void pushresult (lua_State *L, int i) { | 87 | static void pushresult (lua_State *L, int i) { |
62 | if (i) | 88 | if (i) |
@@ -75,18 +101,13 @@ static void pushresult (lua_State *L, int i) { | |||
75 | ** ======================================================= | 101 | ** ======================================================= |
76 | */ | 102 | */ |
77 | 103 | ||
78 | static int gettag (lua_State *L) { | ||
79 | return (int)lua_getnumber(L, lua_getparam(L, IOTAG)); | ||
80 | } | ||
81 | |||
82 | 104 | ||
83 | static FILE *gethandle (lua_State *L, lua_Object f) { | 105 | static FILE *gethandle (lua_State *L, IOCtrl *ctrl, lua_Object f) { |
84 | if (lua_isuserdata(L, f)) { | 106 | if (lua_isuserdata(L, f)) { |
85 | int ftag = lua_tag(L, f); | 107 | int ftag = lua_tag(L, f); |
86 | int iotag = gettag(L); | 108 | if (ftag == ctrl->iotag) |
87 | if (ftag == iotag) | ||
88 | return (FILE *)lua_getuserdata(L, f); | 109 | return (FILE *)lua_getuserdata(L, f); |
89 | if (ftag == CLOSEDTAG(L, iotag)) | 110 | else if (ftag == ctrl->closedtag) |
90 | lua_error(L, "cannot access a closed file"); | 111 | lua_error(L, "cannot access a closed file"); |
91 | /* else go through */ | 112 | /* else go through */ |
92 | } | 113 | } |
@@ -94,127 +115,110 @@ static FILE *gethandle (lua_State *L, lua_Object f) { | |||
94 | } | 115 | } |
95 | 116 | ||
96 | 117 | ||
97 | static FILE *getfilebyname (lua_State *L, const char *name) { | 118 | static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) { |
98 | FILE *handle = gethandle(L, lua_rawgetglobal(L, name)); | 119 | FILE *f = gethandle(L, ctrl, lua_getparam(L, arg)); |
99 | if (!handle) | ||
100 | luaL_verror(L, "`%.50s' is not a file handle", name); | ||
101 | return handle; | ||
102 | } | ||
103 | |||
104 | |||
105 | static FILE *getfile (lua_State *L, int arg) { | ||
106 | return gethandle(L, lua_getparam(L, arg)); | ||
107 | } | ||
108 | |||
109 | |||
110 | static FILE *getnonullfile (lua_State *L, int arg) { | ||
111 | FILE *f = getfile(L, arg); | ||
112 | luaL_arg_check(L, f, arg, "invalid file handle"); | 120 | luaL_arg_check(L, f, arg, "invalid file handle"); |
113 | return f; | 121 | return f; |
114 | } | 122 | } |
115 | 123 | ||
116 | 124 | ||
117 | static FILE *getfileparam (lua_State *L, const char *name, int *arg) { | 125 | static FILE *getfileparam (lua_State *L, IOCtrl *ctrl, int *arg, int inout) { |
118 | FILE *f = getfile(L, *arg); | 126 | FILE *f = gethandle(L, ctrl, lua_getparam(L, *arg)); |
119 | if (f) { | 127 | if (f) { |
120 | (*arg)++; | 128 | (*arg)++; |
121 | return f; | 129 | return f; |
122 | } | 130 | } |
123 | else | 131 | else |
124 | return getfilebyname(L, name); | 132 | return ctrl->file[inout]; |
125 | } | 133 | } |
126 | 134 | ||
127 | 135 | ||
128 | static int closefile (lua_State *L, FILE *f) { | 136 | static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f, |
129 | if (f == stdin || f == stdout) | 137 | const char *name) { |
130 | return 1; | 138 | lua_pushusertag(L, f, ctrl->iotag); |
131 | else { | 139 | lua_setglobal(L, name); |
132 | int tag = gettag(L); | ||
133 | lua_pushusertag(L, f, tag); | ||
134 | lua_settag(L, CLOSEDTAG(L, tag)); | ||
135 | return (CLOSEFILE(L, f) == 0); | ||
136 | } | ||
137 | } | 140 | } |
138 | 141 | ||
139 | 142 | ||
140 | static void io_close (lua_State *L) { | 143 | static void setfile (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) { |
141 | pushresult(L, closefile(L, getnonullfile(L, FIRSTARG))); | 144 | ctrl->file[inout] = f; |
145 | lua_pushusertag(L, f, ctrl->iotag); | ||
146 | lua_setglobal(L, filenames[inout]); | ||
142 | } | 147 | } |
143 | 148 | ||
144 | 149 | ||
145 | static void gc_close (lua_State *L) { | 150 | static void setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) { |
146 | FILE *f = getnonullfile(L, FIRSTARG); | 151 | if (f == NULL) |
147 | if (f != stdin && f != stdout && f != stderr) { | 152 | pushresult(L, 0); |
148 | CLOSEFILE(L, f); | 153 | else { |
154 | setfile(L, ctrl, f, inout); | ||
155 | lua_pushusertag(L, f, ctrl->iotag); | ||
149 | } | 156 | } |
150 | } | 157 | } |
151 | 158 | ||
152 | 159 | ||
153 | static void io_open (lua_State *L) { | 160 | static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) { |
154 | FILE *f = fopen(luaL_check_string(L, FIRSTARG), luaL_check_string(L, FIRSTARG+1)); | 161 | if (f == stdin || f == stdout) |
155 | if (f) lua_pushusertag(L, f, gettag(L)); | 162 | return 1; |
156 | else pushresult(L, 0); | 163 | else { |
164 | if (f == ctrl->file[INFILE]) | ||
165 | setfile(L, ctrl, stdin, INFILE); | ||
166 | else if (f == ctrl->file[OUTFILE]) | ||
167 | setfile(L, ctrl, stdout, OUTFILE); | ||
168 | lua_pushusertag(L, f, ctrl->iotag); | ||
169 | lua_settag(L, ctrl->closedtag); | ||
170 | return (CLOSEFILE(L, f) == 0); | ||
171 | } | ||
157 | } | 172 | } |
158 | 173 | ||
159 | 174 | ||
160 | static void setfile (lua_State *L, FILE *f, const char *name, int tag) { | 175 | static void io_close (lua_State *L) { |
161 | lua_pushusertag(L, f, tag); | 176 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
162 | lua_setglobal(L, name); | 177 | pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 2))); |
163 | } | 178 | } |
164 | 179 | ||
165 | 180 | ||
166 | static void setreturn (lua_State *L, FILE *f, const char *name) { | 181 | static void io_open (lua_State *L) { |
167 | if (f == NULL) | 182 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
168 | pushresult(L, 0); | 183 | FILE *f = fopen(luaL_check_string(L, 2), luaL_check_string(L, 3)); |
169 | else { | 184 | if (f) lua_pushusertag(L, f, ctrl->iotag); |
170 | int tag = gettag(L); | 185 | else pushresult(L, 0); |
171 | setfile(L, f, name, tag); | ||
172 | lua_pushusertag(L, f, tag); | ||
173 | } | ||
174 | } | 186 | } |
175 | 187 | ||
176 | 188 | ||
177 | static void io_readfrom (lua_State *L) { | 189 | |
190 | static void io_fromto (lua_State *L, int inout, const char *mode) { | ||
191 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); | ||
192 | lua_Object f = lua_getparam(L, 2); | ||
178 | FILE *current; | 193 | FILE *current; |
179 | lua_Object f = lua_getparam(L, FIRSTARG); | ||
180 | if (f == LUA_NOOBJECT) { | 194 | if (f == LUA_NOOBJECT) { |
181 | if (closefile(L, getfilebyname(L, FINPUT))) | 195 | pushresult(L, closefile(L, ctrl, ctrl->file[inout])); |
182 | current = stdin; | 196 | return; |
183 | else | ||
184 | current = NULL; /* to signal error */ | ||
185 | } | 197 | } |
186 | else if (lua_tag(L, f) == gettag(L)) /* deprecated option */ | 198 | else if (lua_tag(L, f) == ctrl->iotag) /* deprecated option */ |
187 | current = (FILE *)lua_getuserdata(L, f); | 199 | current = (FILE *)lua_getuserdata(L, f); |
188 | else { | 200 | else { |
189 | const char *s = luaL_check_string(L, FIRSTARG); | 201 | const char *s = luaL_check_string(L, 2); |
190 | current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); | 202 | current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode); |
191 | } | 203 | } |
192 | setreturn(L, current, FINPUT); | 204 | setreturn(L, ctrl, current, inout); |
205 | } | ||
206 | |||
207 | |||
208 | static void io_readfrom (lua_State *L) { | ||
209 | io_fromto(L, INFILE, "r"); | ||
193 | } | 210 | } |
194 | 211 | ||
195 | 212 | ||
196 | static void io_writeto (lua_State *L) { | 213 | static void io_writeto (lua_State *L) { |
197 | FILE *current; | 214 | io_fromto(L, OUTFILE, "w"); |
198 | lua_Object f = lua_getparam(L, FIRSTARG); | ||
199 | if (f == LUA_NOOBJECT) { | ||
200 | if (closefile(L, getfilebyname(L, FOUTPUT))) | ||
201 | current = stdout; | ||
202 | else | ||
203 | current = NULL; /* to signal error */ | ||
204 | } | ||
205 | else if (lua_tag(L, f) == gettag(L)) /* deprecated option */ | ||
206 | current = (FILE *)lua_getuserdata(L, f); | ||
207 | else { | ||
208 | const char *s = luaL_check_string(L, FIRSTARG); | ||
209 | current = (*s == '|') ? popen(s+1,"w") : fopen(s, "w"); | ||
210 | } | ||
211 | setreturn(L, current, FOUTPUT); | ||
212 | } | 215 | } |
213 | 216 | ||
214 | 217 | ||
215 | static void io_appendto (lua_State *L) { | 218 | static void io_appendto (lua_State *L) { |
216 | FILE *current = fopen(luaL_check_string(L, FIRSTARG), "a"); | 219 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
217 | setreturn(L, current, FOUTPUT); | 220 | FILE *current = fopen(luaL_check_string(L, 2), "a"); |
221 | setreturn(L, ctrl, current, OUTFILE); | ||
218 | } | 222 | } |
219 | 223 | ||
220 | 224 | ||
@@ -348,8 +352,9 @@ static int read_chars (lua_State *L, FILE *f, int n) { | |||
348 | 352 | ||
349 | 353 | ||
350 | static void io_read (lua_State *L) { | 354 | static void io_read (lua_State *L) { |
351 | int arg = FIRSTARG; | 355 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
352 | FILE *f = getfileparam(L, FINPUT, &arg); | 356 | int arg = 2; |
357 | FILE *f = getfileparam(L, ctrl, &arg, INFILE); | ||
353 | lua_Object op = lua_getparam(L, arg); | 358 | lua_Object op = lua_getparam(L, arg); |
354 | do { /* repeat for each part */ | 359 | do { /* repeat for each part */ |
355 | long l; | 360 | long l; |
@@ -393,8 +398,9 @@ static void io_read (lua_State *L) { | |||
393 | 398 | ||
394 | 399 | ||
395 | static void io_write (lua_State *L) { | 400 | static void io_write (lua_State *L) { |
396 | int arg = FIRSTARG; | 401 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
397 | FILE *f = getfileparam(L, FOUTPUT, &arg); | 402 | int arg = 2; |
403 | FILE *f = getfileparam(L, ctrl, &arg, OUTFILE); | ||
398 | int status = 1; | 404 | int status = 1; |
399 | lua_Object o; | 405 | lua_Object o; |
400 | while ((o = lua_getparam(L, arg)) != LUA_NOOBJECT) { | 406 | while ((o = lua_getparam(L, arg)) != LUA_NOOBJECT) { |
@@ -416,10 +422,11 @@ static void io_write (lua_State *L) { | |||
416 | static void io_seek (lua_State *L) { | 422 | static void io_seek (lua_State *L) { |
417 | static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; | 423 | static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; |
418 | static const char *const modenames[] = {"set", "cur", "end", NULL}; | 424 | static const char *const modenames[] = {"set", "cur", "end", NULL}; |
419 | FILE *f = getnonullfile(L, FIRSTARG); | 425 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
420 | int op = luaL_findstring(luaL_opt_string(L, FIRSTARG+1, "cur"), modenames); | 426 | FILE *f = getnonullfile(L, ctrl, 2); |
421 | long offset = luaL_opt_long(L, FIRSTARG+2, 0); | 427 | int op = luaL_findstring(luaL_opt_string(L, 3, "cur"), modenames); |
422 | luaL_arg_check(L, op != -1, FIRSTARG+1, "invalid mode"); | 428 | long offset = luaL_opt_long(L, 4, 0); |
429 | luaL_arg_check(L, op != -1, 3, "invalid mode"); | ||
423 | op = fseek(f, offset, mode[op]); | 430 | op = fseek(f, offset, mode[op]); |
424 | if (op) | 431 | if (op) |
425 | pushresult(L, 0); /* error */ | 432 | pushresult(L, 0); /* error */ |
@@ -429,9 +436,10 @@ static void io_seek (lua_State *L) { | |||
429 | 436 | ||
430 | 437 | ||
431 | static void io_flush (lua_State *L) { | 438 | static void io_flush (lua_State *L) { |
432 | FILE *f = getfile(L, FIRSTARG); | 439 | IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1)); |
433 | luaL_arg_check(L, f || lua_getparam(L, FIRSTARG) == LUA_NOOBJECT, FIRSTARG, | 440 | lua_Object of = lua_getparam(L, 2); |
434 | "invalid file handle"); | 441 | FILE *f = gethandle(L, ctrl, of); |
442 | luaL_arg_check(L, f || of == LUA_NOOBJECT, 2, "invalid file handle"); | ||
435 | pushresult(L, fflush(f) == 0); | 443 | pushresult(L, fflush(f) == 0); |
436 | } | 444 | } |
437 | 445 | ||
@@ -604,30 +612,38 @@ static const struct luaL_reg iolibtag[] = { | |||
604 | }; | 612 | }; |
605 | 613 | ||
606 | 614 | ||
607 | static void openwithtags (lua_State *L) { | 615 | static void openwithcontrol (lua_State *L) { |
616 | IOCtrl *ctrl = (IOCtrl *)malloc(sizeof(IOCtrl)); | ||
608 | unsigned int i; | 617 | unsigned int i; |
609 | int iotag = lua_newtag(L); | 618 | int ctrltag = lua_newtag(L); |
610 | lua_newtag(L); /* alloc CLOSEDTAG: assume that CLOSEDTAG = iotag-1 */ | 619 | ctrl->iotag = lua_newtag(L); |
620 | ctrl->closedtag = lua_newtag(L); | ||
611 | for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) { | 621 | for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) { |
612 | /* put iotag as upvalue for these functions */ | 622 | /* put `ctrl' as upvalue for these functions */ |
613 | lua_pushnumber(L, iotag); | 623 | lua_pushusertag(L, ctrl, ctrltag); |
614 | lua_pushcclosure(L, iolibtag[i].func, 1); | 624 | lua_pushcclosure(L, iolibtag[i].func, 1); |
615 | lua_setglobal(L, iolibtag[i].name); | 625 | lua_setglobal(L, iolibtag[i].name); |
616 | } | 626 | } |
617 | /* predefined file handles */ | 627 | /* predefined file handles */ |
618 | setfile(L, stdin, FINPUT, iotag); | 628 | ctrl->file[INFILE] = stdin; |
619 | setfile(L, stdout, FOUTPUT, iotag); | 629 | setfile(L, ctrl, stdin, INFILE); |
620 | setfile(L, stdin, "_STDIN", iotag); | 630 | ctrl->file[OUTFILE] = stdout; |
621 | setfile(L, stdout, "_STDOUT", iotag); | 631 | setfile(L, ctrl, stdout, OUTFILE); |
622 | setfile(L, stderr, "_STDERR", iotag); | 632 | setfilebyname(L, ctrl, stdin, "_STDIN"); |
623 | /* close file when collected */ | 633 | setfilebyname(L, ctrl, stdout, "_STDOUT"); |
624 | lua_pushnumber(L, iotag); | 634 | setfilebyname(L, ctrl, stderr, "_STDERR"); |
625 | lua_pushcclosure(L, gc_close, 1); | 635 | /* change file when assigned */ |
626 | lua_settagmethod(L, iotag, "gc"); | 636 | lua_pushusertag(L, ctrl, ctrltag); |
637 | lua_pushcclosure(L, atribTM, 1); | ||
638 | lua_settagmethod(L, ctrl->iotag, "setglobal"); | ||
639 | /* delete `ctrl' when collected */ | ||
640 | lua_pushusertag(L, ctrl, ctrltag); | ||
641 | lua_pushcclosure(L, ctrl_collect, 1); | ||
642 | lua_settagmethod(L, ctrltag, "gc"); | ||
627 | } | 643 | } |
628 | 644 | ||
629 | void lua_iolibopen (lua_State *L) { | 645 | void lua_iolibopen (lua_State *L) { |
630 | luaL_openl(L, iolib); | 646 | luaL_openl(L, iolib); |
631 | openwithtags(L); | 647 | openwithcontrol(L); |
632 | } | 648 | } |
633 | 649 | ||