Browse Source

new design for iolib (object style)

v5-2
Roberto Ierusalimschy 23 years ago
parent
commit
c3b90061ea
  1. 287
      liolib.c

287
liolib.c

@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 1.132 2002/03/20 12:54:08 roberto Exp roberto $
** $Id: liolib.c,v 1.133 2002/03/27 15:30:41 roberto Exp roberto $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@ -27,32 +27,21 @@
*/
#ifdef POPEN
/* FILE *popen();
int pclose(); */
#define CLOSEFILE(L, f) ((pclose(f) == -1) ? fclose(f) : 0)
#else
/* no support for popen */
#define popen(x,y) NULL /* that is, popen always fails */
#define CLOSEFILE(L, f) (fclose(f))
#ifndef POPEN
#define pclose(f) (-1)
#endif
#define INFILE 0
#define OUTFILE 1
#define NOFILE 2
#define FILEHANDLE "FileHandle"
#define CLOSEDFILEHANDLE "ClosedFileHandle"
static const char *const filenames[] = {"_INPUT", "_OUTPUT"};
static const char *const basicfiles[] = {"stdin", "stdout"};
#define IO_INPUT "_input"
#define IO_OUTPUT "_output"
static int pushresult (lua_State *L, int i) {
if (i) {
lua_pushnumber(L, 1);
lua_pushboolean(L, 1);
return 1;
}
else {
@ -64,43 +53,15 @@ static int pushresult (lua_State *L, int i) {
}
static int checkfile (lua_State *L, int findex, const char *tname) {
int res;
lua_getmetatable(L, findex);
lua_pushstring(L, tname);
lua_rawget(L, LUA_REGISTRYINDEX);
res = lua_equal(L, -1, -2);
lua_pop(L, 2);
return res;
}
/* temporary?? should be in auxlib... */
static void *luaL_check_userdata (lua_State *L, int findex, const char *tn) {
luaL_arg_check(L, checkfile(L, findex, tn), findex, "bad file");
return lua_touserdata(L, findex);
}
static FILE *getopthandle (lua_State *L, int inout) {
FILE *p = (FILE *)(lua_touserdata(L, 1));
if (p != NULL) { /* is it a userdata ? */
if (!checkfile(L, 1, FILEHANDLE)) { /* not a valid file handle? */
if (checkfile(L, 1, CLOSEDFILEHANDLE))
luaL_argerror(L, 1, "file is closed");
else
luaL_argerror(L, 1, "(invalid value)");
}
lua_pushvalue(L, 1); lua_remove(L, 1); /* move it to stack top */
}
else { /* try global value */
lua_getglobal(L, filenames[inout]);
if (!checkfile(L, -1, FILEHANDLE))
luaL_verror(L, "global variable `%.10s' is not a valid file handle",
filenames[inout]);
p = (FILE *)(lua_touserdata(L, -1));
static FILE *tofile (lua_State *L, int findex) {
FILE *f = (FILE *)lua_touserdata(L, findex);
if (f && lua_getmetatable(L, findex) &&
lua_equal(L, -1, lua_upvalueindex(1))) {
lua_pop(L, 1);
return f;
}
return p; /* leave handle at stack top to avoid GC */
luaL_argerror(L, findex, "bad file");
return NULL; /* to avoid warnings */
}
@ -112,102 +73,106 @@ static void newfile (lua_State *L, FILE *f) {
}
static void newfilewithname (lua_State *L, FILE *f, const char *name) {
static void registerfile (lua_State *L, FILE *f, const char *name,
const char *impname) {
lua_pushstring(L, name);
newfile(L, f);
if (impname) {
lua_pushstring(L, impname);
lua_pushvalue(L, -2);
lua_settable(L, -6);
}
lua_settable(L, -3);
}
static int setnewfile (lua_State *L, FILE *f, int inout) {
static int setnewfile (lua_State *L, FILE *f) {
if (f == NULL)
return pushresult(L, 0);
else {
newfile(L, f);
if (inout != NOFILE) {
lua_pushvalue(L, -1);
lua_setglobal(L, filenames[inout]);
}
return 1;
}
}
static void resetfile (lua_State *L, int inout) {
lua_getglobal(L, "io");
lua_pushstring(L, basicfiles[inout]);
lua_gettable(L, -2);
lua_setglobal(L, filenames[inout]);
lua_pop(L, 1);
}
static int io_close (lua_State *L) {
FILE *f = (FILE *)(luaL_check_userdata(L, 1, FILEHANDLE));
FILE *f = tofile(L, 1);
int status = 1;
if (f != stdin && f != stdout && f != stderr) {
lua_settop(L, 1); /* make sure file is on top */
lua_pushliteral(L, CLOSEDFILEHANDLE);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, 1);
status = (CLOSEFILE(L, f) == 0);
status = (pclose(f) != -1) || (fclose(f) == 0);
}
return pushresult(L, status);
}
static int file_collect (lua_State *L) {
FILE *f = (FILE *)(luaL_check_userdata(L, 1, FILEHANDLE));
if (f != stdin && f != stdout && f != stderr)
CLOSEFILE(L, f);
return 0;
static int io_open (lua_State *L) {
FILE *f = fopen(luaL_check_string(L, 1), luaL_opt_string(L, 2, "r"));
return setnewfile(L, f);
}
static int io_open (lua_State *L) {
FILE *f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2));
return setnewfile(L, f, NOFILE);
static int io_popen (lua_State *L) {
#ifndef POPEN
lua_error(L, "`popen' not supported");
return 0;
#else
FILE *f = popen(luaL_check_string(L, 1), luaL_opt_string(L, 2, "r"));
return setnewfile(L, f);
#endif
}
static int io_tmpfile (lua_State *L) {
return setnewfile(L, tmpfile(), NOFILE);
return setnewfile(L, tmpfile());
}
static FILE *getiofile (lua_State *L, const char *name) {
lua_pushstring(L, name);
lua_rawget(L, lua_upvalueindex(1));
return tofile(L, -1);
}
static int io_fromto (lua_State *L, int inout, const char *mode) {
FILE *current;
static int g_iofile (lua_State *L, const char *name, const char *mode) {
if (lua_isnone(L, 1)) {
getopthandle(L, inout);
resetfile(L, inout);
return io_close(L);
lua_pushstring(L, name);
lua_rawget(L, lua_upvalueindex(1));
return 1;
}
else {
const char *s = luaL_check_string(L, 1);
current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode);
return setnewfile(L, current, inout);
const char *filename = lua_tostring(L, 1);
lua_pushstring(L, name);
if (filename) {
FILE *f = fopen(filename, mode);
luaL_arg_check(L, f, 1, strerror(errno));
newfile(L, f);
}
else {
lua_pushvalue(L, 1);
tofile(L, -1); /* check that it's a valid file handle */
}
lua_rawset(L, lua_upvalueindex(1));
return 0;
}
}
static int io_readfrom (lua_State *L) {
return io_fromto(L, INFILE, "r");
}
static int io_writeto (lua_State *L) {
return io_fromto(L, OUTFILE, "w");
static int io_input (lua_State *L) {
return g_iofile(L, IO_INPUT, "r");
}
static int io_appendto (lua_State *L) {
FILE *current = fopen(luaL_check_string(L, 1), "a");
return setnewfile(L, current, OUTFILE);
static int io_output (lua_State *L) {
return g_iofile(L, IO_OUTPUT, "w");
}
/*
** {======================================================
** READ
@ -307,19 +272,18 @@ static int read_chars (lua_State *L, FILE *f, size_t n) {
}
static int io_read (lua_State *L) {
FILE *f = getopthandle(L, INFILE);
static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
if (nargs == 0) { /* no arguments? */
success = read_until(L, f, "\n", 1); /* read until \n (a line) */
n = 2; /* will return n-1 results */
n = first+1; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
luaL_check_stack(L, nargs+LUA_MINSTACK, "too many arguments");
success = 1;
for (n = 1; n<=nargs && success; n++) {
for (n = first; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tonumber(L, n);
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
@ -360,18 +324,26 @@ static int io_read (lua_State *L) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
}
return n - 1;
return n - first;
}
static int io_read (lua_State *L) {
return g_read(L, getiofile(L, IO_INPUT), 1);
}
static int f_read (lua_State *L) {
return g_read(L, tofile(L, 1), 2);
}
/* }====================================================== */
static int io_write (lua_State *L) {
FILE *f = getopthandle(L, OUTFILE);
int nargs = lua_gettop(L)-1;
int arg;
static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - 1;
int status = 1;
for (arg=1; arg<=nargs; arg++) {
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
@ -388,10 +360,20 @@ static int io_write (lua_State *L) {
}
static int io_seek (lua_State *L) {
static int io_write (lua_State *L) {
return g_write(L, getiofile(L, IO_OUTPUT), 1);
}
static int f_write (lua_State *L) {
return g_write(L, tofile(L, 1), 2);
}
static int f_seek (lua_State *L) {
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = (FILE *)(luaL_check_userdata(L, 1, FILEHANDLE));
FILE *f = tofile(L, 1);
int op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames);
long offset = luaL_opt_long(L, 3, 0);
luaL_arg_check(L, op != -1, 2, "invalid mode");
@ -406,25 +388,60 @@ static int io_seek (lua_State *L) {
static int io_flush (lua_State *L) {
FILE *f = (lua_isnoneornil(L, 1)) ? (FILE *)(NULL) :
(FILE *)(luaL_check_userdata(L, 1, FILEHANDLE));
return pushresult(L, fflush(f) == 0);
return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0);
}
static int f_flush (lua_State *L) {
return pushresult(L, fflush(tofile(L, 1)) == 0);
}
static const luaL_reg iolib[] = {
{"appendto", io_appendto},
{"input", io_input},
{"output", io_output},
{"close", io_close},
{"flush", io_flush},
{"open", io_open},
{"popen", io_popen},
{"read", io_read},
{"readfrom", io_readfrom},
{"seek", io_seek},
{"tmpfile", io_tmpfile},
{"write", io_write},
{"writeto", io_writeto},
{NULL, NULL}
};
static const luaL_reg flib[] = {
{"flush", f_flush},
{"read", f_read},
{"seek", f_seek},
{"write", f_write},
{NULL, NULL}
};
static void createmeta (lua_State *L) {
lua_pushliteral(L, FILEHANDLE); /* S: FH */
lua_newtable(L); /* S: mt FH */
/* close files when collected */
lua_pushliteral(L, "__gc"); /* S: `gc' mt FH */
lua_pushvalue(L, -2); /* S: mt `gc' mt FH */
lua_pushcclosure(L, io_close, 1); /* S: close `gc' mt FH */
lua_rawset(L, -3); /* S: mt FH */
/* file methods */
lua_pushliteral(L, "__gettable"); /* S: `gettable' mt FH */
lua_pushvalue(L, -2); /* S: mt `gettable' mt FH */
lua_rawset(L, -3); /* S: mt FH */
lua_pushvalue(L, -1); /* S: mt mt FH */
luaL_openlib(L, flib, 1); /* S: mt FH */
/* put new metatable into registry */
lua_rawset(L, LUA_REGISTRYINDEX); /* S: empty */
/* meta table for CLOSEDFILEHANDLE */
lua_pushliteral(L, CLOSEDFILEHANDLE);
lua_newtable(L);
lua_rawset(L, LUA_REGISTRYINDEX);
}
/* }====================================================== */
@ -613,29 +630,19 @@ static const luaL_reg syslib[] = {
LUALIB_API int lua_iolibopen (lua_State *L) {
lua_pushliteral(L, FILEHANDLE);
lua_newtable(L); /* meta table for FILEHANDLE */
/* close files when collected */
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, file_collect);
lua_rawset(L, -3);
/* put new metatable into registry */
lua_rawset(L, LUA_REGISTRYINDEX);
/* meta table for CLOSEDFILEHANDLE */
lua_pushliteral(L, CLOSEDFILEHANDLE);
lua_newtable(L);
lua_rawset(L, LUA_REGISTRYINDEX);
luaL_opennamedlib(L, "os", syslib);
lua_pushliteral(L, "io");
lua_newtable(L);
luaL_openlib(L, iolib);
/* predefined file handles */
newfilewithname(L, stdin, basicfiles[INFILE]);
newfilewithname(L, stdout, basicfiles[OUTFILE]);
newfilewithname(L, stderr, "stderr");
lua_settable(L, LUA_GLOBALSINDEX);
resetfile(L, INFILE);
resetfile(L, OUTFILE);
createmeta(L);
luaL_opennamedlib(L, "os", syslib, 0);
lua_pushliteral(L, FILEHANDLE); /* S: FH */
lua_rawget(L, LUA_REGISTRYINDEX); /* S: mt */
lua_pushvalue(L, -1); /* S: mt mt */
luaL_opennamedlib(L, "io", iolib, 1); /* S: mt */
lua_pushliteral(L, "io"); /* S: `io' mt */
lua_gettable(L, LUA_GLOBALSINDEX); /* S: io mt */
/* put predefined file handles into `io' table */
registerfile(L, stdin, "stdin", IO_INPUT);
registerfile(L, stdout, "stdout", IO_OUTPUT);
registerfile(L, stderr, "stderr", NULL);
lua_pop(L, 2); /* S: empty */
return 0;
}

Loading…
Cancel
Save