new method to handle current files, with global variables

_INPUT and _OUTPUT.
This commit is contained in:
Roberto Ierusalimschy 1997-06-26 17:39:10 -03:00
parent e81f184164
commit da585783e3
2 changed files with 105 additions and 75 deletions

89
iolib.c
View File

@ -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();

View File

@ -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.