mirror of
https://github.com/lua/lua.git
synced 2025-01-14 05:43:00 +08:00
new design for iolib (object style)
This commit is contained in:
parent
a2e414d679
commit
c3b90061ea
297
liolib.c
297
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 */
|
||||
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;
|
||||
}
|
||||
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));
|
||||
}
|
||||
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_input (lua_State *L) {
|
||||
return g_iofile(L, IO_INPUT, "r");
|
||||
}
|
||||
|
||||
|
||||
static int io_writeto (lua_State *L) {
|
||||
return io_fromto(L, OUTFILE, "w");
|
||||
static int io_output (lua_State *L) {
|
||||
return g_iofile(L, IO_OUTPUT, "w");
|
||||
}
|
||||
|
||||
|
||||
static int io_appendto (lua_State *L) {
|
||||
FILE *current = fopen(luaL_check_string(L, 1), "a");
|
||||
return setnewfile(L, current, OUTFILE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** 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},
|
||||
{"read", io_read},
|
||||
{"readfrom", io_readfrom},
|
||||
{"seek", io_seek},
|
||||
{"tmpfile", io_tmpfile},
|
||||
{"write", io_write},
|
||||
{"writeto", io_writeto},
|
||||
{"flush", io_flush},
|
||||
{"open", io_open},
|
||||
{"popen", io_popen},
|
||||
{"read", io_read},
|
||||
{"tmpfile", io_tmpfile},
|
||||
{"write", io_write},
|
||||
{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…
x
Reference in New Issue
Block a user