diff --git a/iolib.c b/iolib.c index 3a532c8a..d367097e 100644 --- a/iolib.c +++ b/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(); diff --git a/manual.tex b/manual.tex index 210721b2..1bab89c1 100644 --- a/manual.tex +++ b/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.