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"
 
 
-FILE *lua_infile, *lua_outfile;
-
 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)
     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)
 {
+  FILE *current;
   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)
-    lua_infile = lua_getuserdata(f);
+    current = lua_getuserdata(f);
   else {
     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);
       return;
     }
   }
-  lua_pushusertag(lua_infile, lua_tagio);
+  setreturn(current, "_INPUT");
 }
 
 
 static void io_writeto (void)
 {
+  FILE *current;
   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)
-    lua_outfile = lua_getuserdata(f);
+    current = lua_getuserdata(f);
   else {
     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);
       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);
   FILE *fp = fopen (s, "a");
-  if (fp != NULL) {
-    lua_outfile = fp;
-    lua_pushusertag(lua_outfile, lua_tagio);
-  }
+  if (fp != NULL)
+    setreturn(fp, "_OUTPUT");
   else
     pushresult(0);
 }
@@ -112,6 +129,7 @@ static void io_appendto (void)
 
 static void io_read (void)
 {
+  FILE *f = getfile("_INPUT");
   char *buff;
   char *p = luaL_opt_string(1, "[^\n]*{\n}");
   int inskip = 0;  /* to control {skips} */
@@ -131,7 +149,7 @@ static void io_read (void)
     else {
       char *ep = luaL_item_end(p);  /* get what is next */
       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);
       if (m) {
         if (inskip == 0) luaI_addchar(c);
@@ -152,7 +170,7 @@ static void io_read (void)
     }
   } break_while:
   if (c >= 0)  /* not EOF nor NEED_OTHER? */
-     ungetc(c, lua_infile);
+     ungetc(c, f);
   buff = luaI_addchar(0);
   if (*buff != 0 || *p == 0)  /* read something or did not fail? */
     lua_pushstring(buff);
@@ -161,11 +179,12 @@ static void io_read (void)
 
 static void io_write (void)
 {
+  FILE *f = getfile("_OUTPUT");
   int arg = 1;
   int status = 1;
   char *s;
   while ((s = luaL_opt_string(arg++, NULL)) != NULL)
-    status = status && (fputs(s, lua_outfile) != EOF);
+    status = status && (fputs(s, f) != EOF);
   pushresult(status);
 }
 
@@ -300,7 +319,11 @@ static struct luaL_reg iolib[] = {
 void iolib_open (void)
 {
   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])));
   lua_pushcfunction(errorfb);
   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}
 
@@ -38,7 +38,7 @@ Waldemar Celes
 \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
 
@@ -1034,7 +1034,7 @@ This method cannot be set for tables with default tag.
       function settable_event (table, index, value)
         local tm = gettagmethod(tag(table), "settable")
         if tm then
-          return tm(table, index, value)
+          tm(table, index, value)
         elseif type(table) ~= "table" then
           error("indexed expression not a table")
         else
@@ -1598,11 +1598,10 @@ If \verb|retmode| is absent,
 all results from \verb|func| are just returned by the call.
 If \verb|retmode| is equal to \verb|"pack"|,
 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;
 the first result is at index 1, etc.
-
 For instance, the following calls produce the following results:
 \begin{verbatim}
 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.
 Therefore, the function only considers fields with non \nil\ values.
 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,
 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
 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).
 Independently of these two optional arguments,
 all captured substrings are passed as arguments,
@@ -2072,10 +2073,21 @@ range \Math{[0,1)}.
 
 \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,
 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}
 
-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.
-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,
-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,
 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}.
 Not all systems implement pipes.
 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}
 
 \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,
 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.
 Notice that, if the file already exists,
 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,
-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}
-%%LHF: nao tem como escrever em stderr, tem?
 
 If this function fails, it returns \nil,
 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}.
 Not all systems implement pipes.
 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}
 
 \subsubsection*{\ff {\tt appendto (filename)}}\Deffunc{appendto}
 
 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,
 this function does not erase any previous content of the file.
 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}
 
-This function reads the current input
+This function reads the file \verb|_INPUT|
 according to a read pattern, that specifies how much to read;
 characters are read from the current input file until
 the read pattern fails or ends.
@@ -2196,7 +2202,7 @@ from the input if it belongs to the class;
 it never fails.
 A character class followed by \verb|*| reads until a character that
 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{
 Notice that the behavior of read patterns is different from
 the regular pattern matching behavior,
@@ -2220,6 +2226,7 @@ Following are some examples of read patterns and their meanings:
 This is the default pattern.
 \item \verb|"{%s*}%S%S*"| returns the next word
 (maximal sequence of non white-space characters),
+skipping spaces if necessary,
 or \nil\ on end of file.
 \item \verb|"{%s*}[+-]?%d%d*"| returns the next integer
 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}
 
 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.
 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,
 plus a string describing the error.