浏览代码

simpler way to access _INPUT and _OUTPUT

Roberto Ierusalimschy 25 年之前
父节点
当前提交
e662e0f1cd
共有 1 个文件被更改,包括 46 次插入66 次删除
  1. 46 66
      liolib.c

+ 46 - 66
liolib.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: liolib.c,v 1.69 2000/08/09 19:16:57 roberto Exp roberto $
+** $Id: liolib.c,v 1.70 2000/08/14 19:10:14 roberto Exp roberto $
 ** Standard I/O (and system) library
 ** Standard I/O (and system) library
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -51,39 +51,14 @@ int pclose(); */
 #define OUTFILE 1
 #define OUTFILE 1
 
 
 typedef struct IOCtrl {
 typedef struct IOCtrl {
-  FILE *file[2];  /* values of _INPUT and _OUTPUT */
+  int ref[2];  /* ref for strings _INPUT/_OUTPUT */
   int iotag;    /* tag for file handles */
   int iotag;    /* tag for file handles */
   int closedtag;  /* tag for closed handles */
   int closedtag;  /* tag for closed handles */
 } IOCtrl;
 } IOCtrl;
 
 
 
 
 
 
-static const char *const filenames[] = {"_INPUT", "_OUTPUT", NULL};
-
-
-static void atribTM (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
-  const char *varname = luaL_check_string(L, 2);
-  lua_Object newvalue = lua_getparam(L, 4);
-  int inout;
-  if ((inout = luaL_findstring(varname, filenames)) != -1) {
-    if (lua_tag(L, newvalue) != ctrl->iotag)
-      luaL_verror(L, "%.20s value must be a valid file handle",
-                     filenames[inout]);
-    ctrl->file[inout] = (FILE *)lua_getuserdata(L, newvalue);
-  }
-  /* set the actual variable */
-  lua_pushglobals(L);
-  lua_pushstring(L, varname);
-  lua_pushobject(L, newvalue);
-  lua_rawset(L);
-}
-
-
-static void ctrl_collect (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
-  free(ctrl);
-}
+static const char *const filenames[] = {"_INPUT", "_OUTPUT"};
 
 
 
 
 static void pushresult (lua_State *L, int i) {
 static void pushresult (lua_State *L, int i) {
@@ -105,10 +80,11 @@ static void pushresult (lua_State *L, int i) {
 
 
 
 
 static FILE *gethandle (lua_State *L, IOCtrl *ctrl, lua_Object f) {
 static FILE *gethandle (lua_State *L, IOCtrl *ctrl, lua_Object f) {
-  if (lua_isuserdata(L, f)) {
+  void *p = lua_getuserdata(L, f);
+  if (p != NULL) {  /* is `f' a userdata ? */
     int ftag = lua_tag(L, f);
     int ftag = lua_tag(L, f);
-    if (ftag == ctrl->iotag)
-      return (FILE *)lua_getuserdata(L, f);
+    if (ftag == ctrl->iotag)  /* does it have the correct tag? */
+      return (FILE *)p;
     else if (ftag == ctrl->closedtag)
     else if (ftag == ctrl->closedtag)
       lua_error(L, "cannot access a closed file");
       lua_error(L, "cannot access a closed file");
     /* else go through */
     /* else go through */
@@ -124,14 +100,15 @@ static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) {
 }
 }
 
 
 
 
-static FILE *getfileparam (lua_State *L, IOCtrl *ctrl, int *arg, int inout) {
-  FILE *f = gethandle(L, ctrl, lua_getparam(L, *arg));
-  if (f) {
-    (*arg)++;
-    return f;
-  }
-  else
-    return ctrl->file[inout];
+static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) {
+  FILE *f;
+  lua_pushglobals(L);
+  lua_pushref(L, ctrl->ref[inout]);
+  f = gethandle(L, ctrl, lua_rawget(L));
+  if (f == NULL)
+    luaL_verror(L, "global variable `%.10s' is not a file handle",
+                filenames[inout]);
+  return f;
 }
 }
 
 
 
 
@@ -142,11 +119,7 @@ static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f,
 }
 }
 
 
 
 
-static void setfile (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) {
-  ctrl->file[inout] = f;
-  lua_pushusertag(L, f, ctrl->iotag);
-  lua_setglobal(L, filenames[inout]);
-}
+#define setfile(L,ctrl,f,inout)	(setfilebyname(L,ctrl,f,filenames[inout]))
 
 
 
 
 static void setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) {
 static void setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) {
@@ -163,10 +136,6 @@ static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) {
   if (f == stdin || f == stdout || f == stderr)
   if (f == stdin || f == stdout || f == stderr)
     return 1;
     return 1;
   else {
   else {
-    if (f == ctrl->file[INFILE])
-      setfile(L, ctrl, stdin, INFILE);
-    else if (f == ctrl->file[OUTFILE])
-      setfile(L, ctrl, stdout, OUTFILE);
     lua_pushusertag(L, f, ctrl->iotag);
     lua_pushusertag(L, f, ctrl->iotag);
     lua_settag(L, ctrl->closedtag);
     lua_settag(L, ctrl->closedtag);
     return (CLOSEFILE(L, f) == 0);
     return (CLOSEFILE(L, f) == 0);
@@ -182,9 +151,17 @@ static void io_close (lua_State *L) {
 
 
 static void file_collect (lua_State *L) {
 static void file_collect (lua_State *L) {
   IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
   IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
-  FILE *f = getnonullfile(L, ctrl, 2);
-  if (f != stdin && f != stdout && f != stderr)
-    CLOSEFILE(L, f);
+  if (ctrl == (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 2))) {
+    /* collectig `ctrl' itself */
+    lua_unref(L, ctrl->ref[INFILE]);
+    lua_unref(L, ctrl->ref[OUTFILE]);
+    free(ctrl);
+  }
+  else {  /* collecting a file: Close it */
+    FILE *f = getnonullfile(L, ctrl, 2);
+    if (f != stdin && f != stdout && f != stderr)
+      CLOSEFILE(L, f);
+  }
 }
 }
 
 
 
 
@@ -202,8 +179,8 @@ static void io_fromto (lua_State *L, int inout, const char *mode) {
   lua_Object f = lua_getparam(L, 2);
   lua_Object f = lua_getparam(L, 2);
   FILE *current;
   FILE *current;
   if (f == LUA_NOOBJECT) {
   if (f == LUA_NOOBJECT) {
-    pushresult(L, closefile(L, ctrl, ctrl->file[inout]));
-    return;
+    closefile(L, ctrl, getfilebyref(L, ctrl, inout));
+    current = (inout == 0) ? stdin : stdout;    
   }
   }
   else if (lua_tag(L, f) == ctrl->iotag)  /* deprecated option */
   else if (lua_tag(L, f) == ctrl->iotag)  /* deprecated option */
     current = (FILE *)lua_getuserdata(L, f);
     current = (FILE *)lua_getuserdata(L, f);
@@ -368,8 +345,11 @@ static int read_chars (lua_State *L, FILE *f, size_t n) {
 static void io_read (lua_State *L) {
 static void io_read (lua_State *L) {
   IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
   IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
   int arg = 2;
   int arg = 2;
-  FILE *f = getfileparam(L, ctrl, &arg, INFILE);
-  lua_Object op = lua_getparam(L, arg);
+  lua_Object op;
+  FILE *f = gethandle(L, ctrl, lua_getparam(L, arg));
+  if (f) arg++;
+  else f = getfilebyref(L, ctrl, INFILE);  /* get _INPUT */
+  op = lua_getparam(L, arg);
   do {  /* repeat for each part */
   do {  /* repeat for each part */
     size_t l;
     size_t l;
     int success;
     int success;
@@ -414,9 +394,11 @@ static void io_read (lua_State *L) {
 static void io_write (lua_State *L) {
 static void io_write (lua_State *L) {
   IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
   IOCtrl *ctrl = (IOCtrl *)lua_getuserdata(L, lua_getparam(L, 1));
   int arg = 2;
   int arg = 2;
-  FILE *f = getfileparam(L, ctrl, &arg, OUTFILE);
   int status = 1;
   int status = 1;
   lua_Object o;
   lua_Object o;
+  FILE *f = gethandle(L, ctrl, lua_getparam(L, arg));
+  if (f) arg++;
+  else f = getfilebyref(L, ctrl, OUTFILE);  /* get _OUTPUT */
   while ((o = lua_getparam(L, arg)) != LUA_NOOBJECT) {
   while ((o = lua_getparam(L, arg)) != LUA_NOOBJECT) {
     if (lua_type(L, o)[2] == 'm') {  /* nuMber? */  /* LUA_NUMBER */
     if (lua_type(L, o)[2] == 'm') {  /* nuMber? */  /* LUA_NUMBER */
       /* optimization: could be done exactly as for strings */
       /* optimization: could be done exactly as for strings */
@@ -641,28 +623,26 @@ static void openwithcontrol (lua_State *L) {
     lua_pushcclosure(L, iolibtag[i].func, 1);
     lua_pushcclosure(L, iolibtag[i].func, 1);
     lua_setglobal(L, iolibtag[i].name);
     lua_setglobal(L, iolibtag[i].name);
   }
   }
+  /* create references to variable names */
+  lua_pushstring(L, filenames[INFILE]);
+  ctrl->ref[INFILE] = lua_ref(L, 1);
+  lua_pushstring(L, filenames[OUTFILE]);
+  ctrl->ref[OUTFILE] = lua_ref(L, 1);
   /* predefined file handles */
   /* predefined file handles */
-  ctrl->file[INFILE] = stdin;
   setfile(L, ctrl, stdin, INFILE);
   setfile(L, ctrl, stdin, INFILE);
-  ctrl->file[OUTFILE] = stdout;
   setfile(L, ctrl, stdout, OUTFILE);
   setfile(L, ctrl, stdout, OUTFILE);
   setfilebyname(L, ctrl, stdin, "_STDIN");
   setfilebyname(L, ctrl, stdin, "_STDIN");
   setfilebyname(L, ctrl, stdout, "_STDOUT");
   setfilebyname(L, ctrl, stdout, "_STDOUT");
   setfilebyname(L, ctrl, stderr, "_STDERR");
   setfilebyname(L, ctrl, stderr, "_STDERR");
-  /* change file when assigned */
-  lua_pushusertag(L, ctrl, ctrltag);
-  lua_pushcclosure(L, atribTM, 1); 
-  lua_settagmethod(L, ctrl->iotag, "setglobal");
   /* delete `ctrl' when collected */
   /* delete `ctrl' when collected */
   lua_pushusertag(L, ctrl, ctrltag);
   lua_pushusertag(L, ctrl, ctrltag);
-  lua_pushcclosure(L, ctrl_collect, 1); 
+  lua_pushcclosure(L, file_collect, 1); 
   lua_settagmethod(L, ctrltag, "gc");
   lua_settagmethod(L, ctrltag, "gc");
   /* close files when collected */
   /* close files when collected */
-  lua_pushusertag(L, ctrl, ctrltag);
-  lua_pushcclosure(L, file_collect, 1); 
-  lua_settagmethod(L, ctrl->iotag, "gc");
+  lua_copytagmethods(L, ctrl->iotag, ctrltag);
 }
 }
 
 
+
 void lua_iolibopen (lua_State *L) {
 void lua_iolibopen (lua_State *L) {
   luaL_openl(L, iolib);
   luaL_openl(L, iolib);
   openwithcontrol(L);
   openwithcontrol(L);