Browse Source

new method to handle current files, with global variables
_INPUT and _OUTPUT.

Roberto Ierusalimschy 28 years ago
parent
commit
da585783e3
2 changed files with 105 additions and 75 deletions
  1. 56 33
      iolib.c
  2. 49 42
      manual.tex

+ 56 - 33
iolib.c

@@ -10,8 +10,6 @@
 #include "lualib.h"
 #include "lualib.h"
 
 
 
 
-FILE *lua_infile, *lua_outfile;
-
 int lua_tagio;
 int lua_tagio;
 
 
 
 
@@ -39,59 +37,80 @@ static void pushresult (int i)
 }
 }
 
 
 
 
-static void closefile (FILE *f)
+
+static FILE *getfile (char *name)
 {
 {
-  if (f == stdin || f == stdout)
-    return;
-  if (f == lua_infile)
-    lua_infile = stdin;
-  if (f == lua_outfile)
-    lua_outfile = stdout;
+  lua_Object f = lua_getglobal(name);
+  if (lua_tag(f) != lua_tagio)
+    luaL_verror("global variable %s is not a file handle", name);
+  return lua_getuserdata(f);
+}
+
+
+static void closefile (char *name)
+{
+  FILE *f = getfile(name);
+  if (f == stdin || f == stdout) return;
   if (pclose(f) == -1)
   if (pclose(f) == -1)
     fclose(f);
     fclose(f);
 }
 }
 
 
 
 
+static void setfile (FILE *f, char *name)
+{
+  lua_pushusertag(f, lua_tagio);
+  lua_setglobal(name);
+}
+
+
+static void setreturn (FILE *f, char *name)
+{
+  setfile(f, name);
+  lua_pushusertag(f, lua_tagio);
+}
+
 
 
 static void io_readfrom (void)
 static void io_readfrom (void)
 {
 {
+  FILE *current;
   lua_Object f = lua_getparam(1);
   lua_Object f = lua_getparam(1);
-  if (f == LUA_NOOBJECT)
-    closefile(lua_infile);  /* restore standart input */
+  if (f == LUA_NOOBJECT) {
+    closefile("_INPUT");
+    current = stdin;
+  }
   else if (lua_tag(f) == lua_tagio)
   else if (lua_tag(f) == lua_tagio)
-    lua_infile = lua_getuserdata(f);
+    current = lua_getuserdata(f);
   else {
   else {
     char *s = luaL_check_string(1);
     char *s = luaL_check_string(1);
-    FILE *fp = (*s == '|') ? popen(s+1, "r") : fopen(s, "r");
-    if (fp)
-      lua_infile = fp;
-    else {
+    current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r");
+    if (current == NULL) {
       pushresult(0);
       pushresult(0);
       return;
       return;
     }
     }
   }
   }
-  lua_pushusertag(lua_infile, lua_tagio);
+  setreturn(current, "_INPUT");
 }
 }
 
 
 
 
 static void io_writeto (void)
 static void io_writeto (void)
 {
 {
+  FILE *current;
   lua_Object f = lua_getparam(1);
   lua_Object f = lua_getparam(1);
-  if (f == LUA_NOOBJECT)
-    closefile(lua_outfile);  /* restore standart output */
+  if (f == LUA_NOOBJECT) {
+    closefile("_OUTPUT");
+    current = stdout;
+  }
   else if (lua_tag(f) == lua_tagio)
   else if (lua_tag(f) == lua_tagio)
-    lua_outfile = lua_getuserdata(f);
+    current = lua_getuserdata(f);
   else {
   else {
     char *s = luaL_check_string(1);
     char *s = luaL_check_string(1);
-    FILE *fp = (*s == '|') ? popen(s+1,"w") : fopen(s,"w");
-    if (fp)
-      lua_outfile = fp;
-    else {
+    current = (*s == '|') ? popen(s+1,"w") : fopen(s,"w");
+    if (current == NULL) {
       pushresult(0);
       pushresult(0);
       return;
       return;
     }
     }
   }
   }
-  lua_pushusertag(lua_outfile, lua_tagio);
+  setreturn(current, "_OUTPUT");
 }
 }
 
 
 
 
@@ -99,10 +118,8 @@ static void io_appendto (void)
 {
 {
   char *s = luaL_check_string(1);
   char *s = luaL_check_string(1);
   FILE *fp = fopen (s, "a");
   FILE *fp = fopen (s, "a");
-  if (fp != NULL) {
-    lua_outfile = fp;
-    lua_pushusertag(lua_outfile, lua_tagio);
-  }
+  if (fp != NULL)
+    setreturn(fp, "_OUTPUT");
   else
   else
     pushresult(0);
     pushresult(0);
 }
 }
@@ -112,6 +129,7 @@ static void io_appendto (void)
 
 
 static void io_read (void)
 static void io_read (void)
 {
 {
+  FILE *f = getfile("_INPUT");
   char *buff;
   char *buff;
   char *p = luaL_opt_string(1, "[^\n]*{\n}");
   char *p = luaL_opt_string(1, "[^\n]*{\n}");
   int inskip = 0;  /* to control {skips} */
   int inskip = 0;  /* to control {skips} */
@@ -131,7 +149,7 @@ static void io_read (void)
     else {
     else {
       char *ep = luaL_item_end(p);  /* get what is next */
       char *ep = luaL_item_end(p);  /* get what is next */
       int m;  /* match result */
       int m;  /* match result */
-      if (c == NEED_OTHER) c = getc(lua_infile);
+      if (c == NEED_OTHER) c = getc(f);
       m = (c == EOF) ? 0 : luaL_singlematch((char)c, p);
       m = (c == EOF) ? 0 : luaL_singlematch((char)c, p);
       if (m) {
       if (m) {
         if (inskip == 0) luaI_addchar(c);
         if (inskip == 0) luaI_addchar(c);
@@ -152,7 +170,7 @@ static void io_read (void)
     }
     }
   } break_while:
   } break_while:
   if (c >= 0)  /* not EOF nor NEED_OTHER? */
   if (c >= 0)  /* not EOF nor NEED_OTHER? */
-     ungetc(c, lua_infile);
+     ungetc(c, f);
   buff = luaI_addchar(0);
   buff = luaI_addchar(0);
   if (*buff != 0 || *p == 0)  /* read something or did not fail? */
   if (*buff != 0 || *p == 0)  /* read something or did not fail? */
     lua_pushstring(buff);
     lua_pushstring(buff);
@@ -161,11 +179,12 @@ static void io_read (void)
 
 
 static void io_write (void)
 static void io_write (void)
 {
 {
+  FILE *f = getfile("_OUTPUT");
   int arg = 1;
   int arg = 1;
   int status = 1;
   int status = 1;
   char *s;
   char *s;
   while ((s = luaL_opt_string(arg++, NULL)) != NULL)
   while ((s = luaL_opt_string(arg++, NULL)) != NULL)
-    status = status && (fputs(s, lua_outfile) != EOF);
+    status = status && (fputs(s, f) != EOF);
   pushresult(status);
   pushresult(status);
 }
 }
 
 
@@ -300,7 +319,11 @@ static struct luaL_reg iolib[] = {
 void iolib_open (void)
 void iolib_open (void)
 {
 {
   lua_tagio = lua_newtag();
   lua_tagio = lua_newtag();
-  lua_infile=stdin; lua_outfile=stdout;
+  setfile(stdin, "_INPUT");
+  setfile(stdout, "_OUTPUT");
+  setfile(stdin, "_STDIN");
+  setfile(stdout, "_STDOUT");
+  setfile(stderr, "_STDERR");
   luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0])));
   luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0])));
   lua_pushcfunction(errorfb);
   lua_pushcfunction(errorfb);
   lua_seterrormethod();
   lua_seterrormethod();

+ 49 - 42
manual.tex

@@ -1,4 +1,4 @@
-% $Id: manual.tex,v 2.4 1997/06/19 18:49:40 roberto Exp roberto $
+% $Id: manual.tex,v 2.5 1997/06/20 19:28:16 roberto Exp roberto $
 
 
 \documentstyle[fullpage,11pt,bnf]{article}
 \documentstyle[fullpage,11pt,bnf]{article}
 
 
@@ -38,7 +38,7 @@ Waldemar Celes
 \tecgraf\ --- Computer Science Department --- PUC-Rio
 \tecgraf\ --- Computer Science Department --- PUC-Rio
 }
 }
 
 
-\date{\small \verb$Date: 1997/06/19 18:49:40 $}
+\date{\small \verb$Date: 1997/06/20 19:28:16 $}
 
 
 \maketitle
 \maketitle
 
 
@@ -1034,7 +1034,7 @@ This method cannot be set for tables with default tag.
       function settable_event (table, index, value)
       function settable_event (table, index, value)
         local tm = gettagmethod(tag(table), "settable")
         local tm = gettagmethod(tag(table), "settable")
         if tm then
         if tm then
-          return tm(table, index, value)
+          tm(table, index, value)
         elseif type(table) ~= "table" then
         elseif type(table) ~= "table" then
           error("indexed expression not a table")
           error("indexed expression not a table")
         else
         else
@@ -1598,11 +1598,10 @@ If \verb|retmode| is absent,
 all results from \verb|func| are just returned by the call.
 all results from \verb|func| are just returned by the call.
 If \verb|retmode| is equal to \verb|"pack"|,
 If \verb|retmode| is equal to \verb|"pack"|,
 the results are {\em packed\/} in a single table.\index{packed results}
 the results are {\em packed\/} in a single table.\index{packed results}
-That is, \verb|call| returns just one table.
-At index \verb|n|, the table has the total number of results
+That is, \verb|call| returns just one table;
+at index \verb|n|, the table has the total number of results
 from the call;
 from the call;
 the first result is at index 1, etc.
 the first result is at index 1, etc.
-
 For instance, the following calls produce the following results:
 For instance, the following calls produce the following results:
 \begin{verbatim}
 \begin{verbatim}
 a = call(sin, {5})    --> a = 0.0871557 = sin(5)
 a = call(sin, {5})    --> a = 0.0871557 = sin(5)
@@ -1666,7 +1665,9 @@ semantically, there is no difference between a
 field not present in a table or a field with value \nil.
 field not present in a table or a field with value \nil.
 Therefore, the function only considers fields with non \nil\ values.
 Therefore, the function only considers fields with non \nil\ values.
 The order in which the indices are enumerated is not specified,
 The order in which the indices are enumerated is not specified,
-{\em not even for numeric indices}.
+{\em not even for numeric indices}
+(to traverse a table in numeric order,
+use a counter).
 If the table is modified in any way during a traversal,
 If the table is modified in any way during a traversal,
 the semantics of \verb|next| is undefined.
 the semantics of \verb|next| is undefined.
 
 
@@ -1904,7 +1905,7 @@ stands for the value of the n-th captured substring.
 
 
 If \verb|repl| is a function, then this function is called every time a
 If \verb|repl| is a function, then this function is called every time a
 match occurs, with the following arguments:
 match occurs, with the following arguments:
-If \verb|table| is present, the the first argument is this table
+If \verb|table| is present, then the first argument is this table
 and the second one is a match counter (1 for the first call).
 and the second one is a match counter (1 for the first call).
 Independently of these two optional arguments,
 Independently of these two optional arguments,
 all captured substrings are passed as arguments,
 all captured substrings are passed as arguments,
@@ -2072,10 +2073,21 @@ range \Math{[0,1)}.
 
 
 \subsection{I/O Facilities} \label{libio}
 \subsection{I/O Facilities} \label{libio}
 
 
-All input and output operations in Lua are done over two {\em current\/} files:
-one for reading and one for writing.
-Initially, the current input file is \verb|stdin|,
-and the current output file is \verb|stdout|.
+All input and output operations in Lua are done over two
+\Def{file handles}, one for reading and one for writing.
+These handles are stored in two Lua global variables,
+called \verb|_INPUT| and \verb|_OUTPUT|.
+The global variables
+\verb|_STDIN|, \verb|_STDOUT| and \verb|_STDERR|
+are initialized with file descriptors for
+\verb|stdin|, \verb|stdout| and \verb|stderr|.
+Initially, \verb|_INPUT=_STDIN| and \verb|_OUTPUT=_STDOUT|.
+\Deffunc{_INPUT}\Deffunc{_OUTPUT}
+\Deffunc{_STDIN}\Deffunc{_STDOUT}\Deffunc{_STDERR}
+
+A file handle is a userdata containing the file stream \verb|FILE*|,
+and with a distinctive tag created by the I/O library.
+
 
 
 Unless otherwise stated,
 Unless otherwise stated,
 all I/O functions return \nil\ on failure and
 all I/O functions return \nil\ on failure and
@@ -2083,18 +2095,16 @@ some value different from \nil\ on success.
 
 
 \subsubsection*{\ff {\tt readfrom (filename)}}\Deffunc{readfrom}
 \subsubsection*{\ff {\tt readfrom (filename)}}\Deffunc{readfrom}
 
 
-This function may be called in three ways.
-When called with a file name,
-it opens the named file,
-sets it as the {\em current\/} input file,
-and returns a {\em handle\/} to the file
-(this handle is a userdata containing the file stream \verb|FILE*|).
+This function may be called in two ways.
+When called with a file name, it opens the named file,
+sets its handle as the value of \verb|_INPUT|,
+and returns this value.
 It does not close the current input file.
 It does not close the current input file.
-When called with a file handle returned by a previous call,
-it restores the file as the current input.
+%When called with a file handle returned by a previous call,
+%it simply assigns it to \verb|_INPUT|.
 When called without parameters,
 When called without parameters,
-it closes the current input file,
-and restores \verb|stdin| as the current input file.
+it closes the \verb|_INPUT| file,
+and restores \verb|stdin| as the value of \verb|_INPUT|.
 
 
 If this function fails, it returns \nil,
 If this function fails, it returns \nil,
 plus a string describing the error.
 plus a string describing the error.
@@ -2105,28 +2115,26 @@ plus a string describing the error.
 then a \Index{piped input} is open, via function \IndexVerb{popen}.
 then a \Index{piped input} is open, via function \IndexVerb{popen}.
 Not all systems implement pipes.
 Not all systems implement pipes.
 Moreover,
 Moreover,
-the number of files that can be open at the same time is usually limited and
-depends on the system.
+the number of files that can be open at the same time is
+usually limited and depends on the system.
 \end{quotation}
 \end{quotation}
 
 
 \subsubsection*{\ff {\tt writeto (filename)}}\Deffunc{writeto}
 \subsubsection*{\ff {\tt writeto (filename)}}\Deffunc{writeto}
 
 
-This function may be called in three ways.
+This function may be called in two ways.
 When called with a file name,
 When called with a file name,
 it opens the named file,
 it opens the named file,
-sets it as the {\em current\/} output file,
-and returns a {\em handle\/} to the file
-(this handle is a user data containing the file stream \verb|FILE*|).
+sets its handle as the value of \verb|_OUTPUT|,
+and returns this value.
 It does not close the current output file.
 It does not close the current output file.
 Notice that, if the file already exists,
 Notice that, if the file already exists,
 then it will be {\em completely erased\/} with this operation.
 then it will be {\em completely erased\/} with this operation.
-When called with a file handle returned by a previous call,
-it restores the file as the current output.
+%When called with a file handle returned by a previous call,
+%it restores the file as the current output.
 When called without parameters,
 When called without parameters,
-this function closes the current output file,
-and restores \verb|stdout| as the current output file.
+this function closes the \verb|_OUTPUT| file,
+and restores \verb|stdout| as the value of \verb|_OUTPUT|.
 \index{closing a file}
 \index{closing a file}
-%%LHF: nao tem como escrever em stderr, tem?
 
 
 If this function fails, it returns \nil,
 If this function fails, it returns \nil,
 plus a string describing the error.
 plus a string describing the error.
@@ -2137,16 +2145,14 @@ plus a string describing the error.
 then a \Index{piped output} is open, via function \IndexVerb{popen}.
 then a \Index{piped output} is open, via function \IndexVerb{popen}.
 Not all systems implement pipes.
 Not all systems implement pipes.
 Moreover,
 Moreover,
-the number of files that can be open at the same time is usually limited and
-depends on the system.
+the number of files that can be open at the same time is
+usually limited and depends on the system.
 \end{quotation}
 \end{quotation}
 
 
 \subsubsection*{\ff {\tt appendto (filename)}}\Deffunc{appendto}
 \subsubsection*{\ff {\tt appendto (filename)}}\Deffunc{appendto}
 
 
 This function opens a file named \verb|filename| and sets it as the
 This function opens a file named \verb|filename| and sets it as the
-{\em current\/} output file.
-It returns the file handle,
-or \nil\ in case of error.
+value of \verb|_OUTPUT|.
 Unlike the \verb|writeto| operation,
 Unlike the \verb|writeto| operation,
 this function does not erase any previous content of the file.
 this function does not erase any previous content of the file.
 If this function fails, it returns \nil,
 If this function fails, it returns \nil,
@@ -2174,7 +2180,7 @@ The file must be explicitly removed when no longer needed.
 
 
 \subsubsection*{\ff {\tt read ([readpattern])}}\Deffunc{read}
 \subsubsection*{\ff {\tt read ([readpattern])}}\Deffunc{read}
 
 
-This function reads the current input
+This function reads the file \verb|_INPUT|
 according to a read pattern, that specifies how much to read;
 according to a read pattern, that specifies how much to read;
 characters are read from the current input file until
 characters are read from the current input file until
 the read pattern fails or ends.
 the read pattern fails or ends.
@@ -2196,7 +2202,7 @@ from the input if it belongs to the class;
 it never fails.
 it never fails.
 A character class followed by \verb|*| reads until a character that
 A character class followed by \verb|*| reads until a character that
 does not belong to the class, or end of file;
 does not belong to the class, or end of file;
-since it can match a sequence of zero characteres, it never fails.%
+since it can match a sequence of zero characters, it never fails.%
 \footnote{
 \footnote{
 Notice that the behavior of read patterns is different from
 Notice that the behavior of read patterns is different from
 the regular pattern matching behavior,
 the regular pattern matching behavior,
@@ -2220,6 +2226,7 @@ Following are some examples of read patterns and their meanings:
 This is the default pattern.
 This is the default pattern.
 \item \verb|"{%s*}%S%S*"| returns the next word
 \item \verb|"{%s*}%S%S*"| returns the next word
 (maximal sequence of non white-space characters),
 (maximal sequence of non white-space characters),
+skipping spaces if necessary,
 or \nil\ on end of file.
 or \nil\ on end of file.
 \item \verb|"{%s*}[+-]?%d%d*"| returns the next integer
 \item \verb|"{%s*}[+-]?%d%d*"| returns the next integer
 or \nil\ if the next characters do not conform to an integer format.
 or \nil\ if the next characters do not conform to an integer format.
@@ -2228,10 +2235,10 @@ or \nil\ if the next characters do not conform to an integer format.
 \subsubsection*{\ff {\tt write (value1, ...)}}\Deffunc{write}
 \subsubsection*{\ff {\tt write (value1, ...)}}\Deffunc{write}
 
 
 This function writes the value of each of its arguments to the
 This function writes the value of each of its arguments to the
-current output file.
+file \verb|_OUTPUT|.
 The arguments must be strings or numbers.
 The arguments must be strings or numbers.
 To write other values,
 To write other values,
-use \verb|tostring| before \verb|write|.
+use \verb|tostring| or \verb|format| before \verb|write|.
 If this function fails, it returns \nil,
 If this function fails, it returns \nil,
 plus a string describing the error.
 plus a string describing the error.