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 /liolib.c | |
| 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
Diffstat (limited to 'liolib.c')
| -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 | ||
