scummvm/engines/grim/lua/liolib.cpp

487 lines
11 KiB
C++
Raw Normal View History

2003-08-15 18:00:22 +00:00
/*
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
2011-05-08 15:38:26 +02:00
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
#define FORBIDDEN_SYMBOL_EXCEPTION_fseek
2011-06-09 11:17:15 +02:00
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
2003-08-15 18:00:22 +00:00
2008-08-02 21:20:13 +00:00
#include "common/savefile.h"
#include "common/fs.h"
2009-05-07 19:06:31 +00:00
#include "common/system.h"
2008-08-02 21:20:13 +00:00
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/lua.h"
#include "engines/grim/lua/luadebug.h"
#include "engines/grim/lua/lualib.h"
#include "base/commandLine.h"
#include "engines/grim/resource.h"
2008-07-26 20:27:15 +00:00
2008-08-03 19:48:17 +00:00
#if defined(UNIX) || defined(__SYMBIAN32__)
#include <sys/stat.h>
#endif
2009-05-25 06:49:57 +00:00
#include <time.h>
#ifdef _WIN32
#include <direct.h>
#endif
2009-05-25 06:49:57 +00:00
namespace Grim {
2003-08-15 18:00:22 +00:00
#define CLOSEDTAG 2
#define IOTAG 1
2008-07-29 08:05:28 +00:00
#define FIRSTARG 3 // 1st and 2nd are upvalues
2003-08-15 18:00:22 +00:00
#define FINPUT "_INPUT"
#define FOUTPUT "_OUTPUT"
LuaFile *g_fin;
LuaFile *g_fout;
LuaFile *g_stdin;
LuaFile *g_stdout;
LuaFile *g_stderr;
2008-08-02 21:20:13 +00:00
static int32 s_id = 0;
Common::HashMap<int32, LuaFile *> *g_files;
LuaFile::LuaFile() : _in(NULL), _out(NULL), _stdin(false), _stdout(false), _stderr(false) {
}
LuaFile::~LuaFile() {
close();
}
2008-08-02 21:20:13 +00:00
void LuaFile::close() {
delete _in;
delete _out;
_in = NULL;
_out = NULL;
_stdin = _stdout = _stderr = false;
}
2008-08-02 21:20:13 +00:00
bool LuaFile::isOpen() const {
return _in || _out || _stdin || stdout || stderr;
}
2008-08-02 21:20:13 +00:00
uint32 LuaFile::read(void *buf, uint32 len) {
if (_stdin) {
return fread(buf, len, 1, stdin);
} else if (_in) {
return _in->read(buf, len);
} else
assert(0);
return 0;
}
2008-08-02 21:20:13 +00:00
uint32 LuaFile::write(const char *buf, uint32 len) {
if (_stdin)
error("LuaFile::write() not allowed on stdin");
if (_in)
error("LuaFile::write() not allowed on in");
if (_stdout) {
return fwrite(buf, len, 1, stdout);
} else if (_stderr) {
return fwrite(buf, len, 1, stderr);
} else if (_out) {
return _out->write(buf, len);
} else
assert(0);
return 0;
2008-08-02 21:20:13 +00:00
}
void LuaFile::seek(int32 pos, int whence) {
if (_stdin) {
fseek(stdin, pos, whence);
} else if (_in) {
_in->seek(pos, whence);
} else
assert(0);
}
2008-08-02 21:20:13 +00:00
2008-07-29 08:05:28 +00:00
static int32 gettag(int32 i) {
return (int32)lua_getnumber(lua_getparam(i));
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void pushresult(int32 i) {
if (i)
lua_pushuserdata(0);
2008-07-29 08:05:28 +00:00
else {
lua_pushnil();
2008-08-02 21:20:13 +00:00
lua_pushstring("File I/O error.");
2008-07-29 08:05:28 +00:00
}
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static int32 ishandler(lua_Object f) {
if (lua_isuserdata(f)) {
if (lua_tag(f) == gettag(CLOSEDTAG))
lua_error("cannot access a closed file");
return lua_tag(f) == gettag(IOTAG);
}
else return 0;
2003-08-15 18:00:22 +00:00
}
static LuaFile *getfile(int32 id) {
if (g_files->contains(id)) {
return (*g_files)[id];
}
return NULL;
}
static LuaFile *getfile(const char *name) {
2008-07-29 08:05:28 +00:00
lua_Object f = lua_getglobal(name);
if (!ishandler(f))
luaL_verror("global variable `%.50s' is not a file handle", name);
return getfile(lua_getuserdata(f));
2003-08-15 18:00:22 +00:00
}
static LuaFile *getfileparam(const char *name, int32 *arg) {
2008-07-29 08:05:28 +00:00
lua_Object f = lua_getparam(*arg);
if (ishandler(f)) {
(*arg)++;
return getfile(lua_getuserdata(f));
2008-07-29 08:05:28 +00:00
} else
return getfile(name);
2003-08-15 18:00:22 +00:00
}
2008-08-02 21:20:13 +00:00
static void closefile(const char *name) {
LuaFile *f = getfile(name);
2008-08-02 21:20:13 +00:00
f->close();
2008-07-29 08:05:28 +00:00
lua_pushobject(lua_getglobal(name));
lua_settag(gettag(CLOSEDTAG));
2003-08-15 18:00:22 +00:00
}
static void setfile(int32 id, const char *name, int32 tag) {
lua_pushusertag(id, tag);
2008-07-29 08:05:28 +00:00
lua_setglobal(name);
2003-08-15 18:00:22 +00:00
}
static void setreturn(int32 id, const char *name) {
2008-07-29 08:05:28 +00:00
int32 tag = gettag(IOTAG);
setfile(id, name, tag);
lua_pushusertag(id, tag);
}
static int32 addfile(LuaFile *f) {
++s_id;
(*g_files)[s_id] = f;
return s_id;
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void io_readfrom() {
lua_Object f = lua_getparam(FIRSTARG);
if (f == LUA_NOOBJECT) {
closefile(FINPUT);
setreturn(1, FINPUT);
2008-07-29 08:05:28 +00:00
} else if (lua_tag(f) == gettag(IOTAG)) {
int32 id = lua_getuserdata(f);
LuaFile *current = getfile(id);
2008-08-02 21:20:13 +00:00
if (!current) {
pushresult(0);
return;
}
setreturn(id, FINPUT);
2008-07-29 08:05:28 +00:00
} else {
const char *s = luaL_check_string(FIRSTARG);
LuaFile *current;
Common::SeekableReadStream *inFile = NULL;
2009-05-07 19:06:31 +00:00
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
inFile = saveFileMan->openForLoading(s);
if (!inFile)
2009-06-26 16:13:11 +00:00
current = g_resourceloader->openNewStreamLuaFile(s);
else {
current = new LuaFile();
current->_in = inFile;
current->_filename = s;
2008-08-02 21:20:13 +00:00
}
if (!current) {
delete current;
2008-08-02 21:20:13 +00:00
pushresult(0);
} else {
setreturn(addfile(current), FINPUT);
2008-08-02 21:20:13 +00:00
}
2005-08-20 22:05:55 +00:00
}
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void io_writeto() {
lua_Object f = lua_getparam(FIRSTARG);
if (f == LUA_NOOBJECT) {
closefile(FOUTPUT);
setreturn(2, FOUTPUT);
2008-08-02 21:20:13 +00:00
} else if (lua_tag(f) == gettag(IOTAG)) {
int32 id = lua_getuserdata(f);
LuaFile *current = getfile(id);
2008-08-02 21:20:13 +00:00
if (!current->isOpen()) {
pushresult(0);
return;
}
setreturn(id, FOUTPUT);
2008-08-02 21:20:13 +00:00
} else {
2008-07-29 08:05:28 +00:00
const char *s = luaL_check_string(FIRSTARG);
if (Common::String(s).hasSuffix("\\bino.txt")) {
pushresult(0);
return;
}
LuaFile *current;
Common::WriteStream *outFile = NULL;
2009-05-07 19:06:31 +00:00
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
outFile = saveFileMan->openForSaving(s);
if (!outFile) {
2008-07-29 08:05:28 +00:00
pushresult(0);
return;
}
current = new LuaFile();
current->_out = outFile;
current->_filename = s;
setreturn(addfile(current), FOUTPUT);
2008-07-29 08:05:28 +00:00
}
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void io_appendto() {
const char *s = luaL_check_string(FIRSTARG);
Common::SeekableReadStream *inFile = NULL;
2009-05-07 19:06:31 +00:00
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
inFile = saveFileMan->openForLoading(s);
if (!inFile) {
2008-08-02 21:20:13 +00:00
pushresult(0);
return;
}
int size = inFile->size();
2008-08-02 21:20:13 +00:00
byte *buf = new byte[size];
inFile->read(buf, size);
delete inFile;
Common::WriteStream *outFile = NULL;
outFile = saveFileMan->openForSaving(s);
if (!outFile)
2008-07-29 08:05:28 +00:00
pushresult(0);
else {
outFile->write(buf, size);
LuaFile *current = new LuaFile();
current->_out = outFile;
current->_filename = s;
setreturn(addfile(current), FOUTPUT);
2008-08-02 21:20:13 +00:00
}
2008-08-11 19:14:03 +00:00
delete[] buf;
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
#define NEED_OTHER (EOF - 1) // just some flag different from EOF
2003-08-15 18:00:22 +00:00
2008-07-30 07:37:00 +00:00
static void io_read() {
2008-07-29 08:05:28 +00:00
int32 arg = FIRSTARG;
LuaFile *f = (LuaFile *)getfileparam(FINPUT, &arg);
char *buff;
const char *p = luaL_opt_string(arg, "[^\n]*{\n}");
int inskip = 0; // to control {skips}
int c = NEED_OTHER;
2008-07-29 08:05:28 +00:00
luaL_resetbuffer();
while (*p) {
if (*p == '{') {
inskip++;
p++;
} else if (*p == '}') {
if (inskip == 0)
lua_error("unbalanced braces in read pattern");
inskip--;
p++;
} else {
const char *ep; // get what is next
int m; // match result
2009-05-23 06:57:19 +00:00
if (c == NEED_OTHER) {
char z;
if (f->read(&z, 1) != 1)
c = EOF;
else
c = z;
2009-05-23 06:57:19 +00:00
}
m = luaI_singlematch((c == EOF) ? 0 : (char)c, p, &ep);
if (m) {
2008-07-29 08:05:28 +00:00
if (inskip == 0)
luaL_addchar(c);
c = NEED_OTHER;
}
switch (*ep) {
case '*': // repetition
if (!m)
p = ep + 1; // else stay in (repeat) the same item
break;
case '?': // optional
p = ep + 1; // continues reading the pattern
break;
2008-07-29 08:05:28 +00:00
default:
if (m)
p = ep; // continues reading the pattern
else
goto break_while; // pattern fails
2008-07-29 08:05:28 +00:00
}
}
}
break_while:
if (c >= 0) // not EOF nor NEED_OTHER?
f->seek(-1, SEEK_CUR);
luaL_addchar(0);
buff = luaL_buffer();
if (*buff != 0 || *p == 0) // read something or did not fail?
lua_pushstring(buff);
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void io_write() {
int32 arg = FIRSTARG;
LuaFile *f = (LuaFile *)getfileparam(FOUTPUT, &arg);
2008-07-29 08:05:28 +00:00
int32 status = 1;
const char *s;
while ((s = luaL_opt_string(arg++, NULL)) != NULL)
2009-06-06 07:03:41 +00:00
status = status && ((int32)f->write(s, strlen(s)) != EOF);
2008-07-29 08:05:28 +00:00
pushresult(status);
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void io_date() {
2010-01-21 19:25:03 +00:00
TimeDate t;
2008-07-29 08:05:28 +00:00
char b[BUFSIZ];
2003-08-15 18:00:22 +00:00
2009-05-07 19:06:31 +00:00
g_system->getTimeAndDate(t);
2008-07-29 08:05:28 +00:00
sprintf(b, "%02d.%02d.%d %02d:%02d.%02d", t.tm_mday, t.tm_mon + 1, 1900 + t.tm_year, t.tm_hour, t.tm_min, t.tm_sec);
lua_pushstring(b);
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void io_exit() {
lua_Object o = lua_getparam(1);
exit((int)lua_isnumber(o) ? (int)lua_getnumber(o) : 1);
2003-08-15 18:00:22 +00:00
}
2008-08-02 21:20:13 +00:00
static void lua_printstack() {
2008-07-29 08:05:28 +00:00
int32 level = 1; // skip level 0 (it's this function)
lua_Object func;
2008-08-02 21:20:13 +00:00
char buf[256];
2008-07-29 08:05:28 +00:00
while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) {
const char *name;
int32 currentline;
const char *filename;
int32 linedefined;
lua_funcinfo(func, &filename, &linedefined);
2008-08-03 07:55:16 +00:00
sprintf(buf, (level == 2) ? "Active Stack:\n\t" : "\t");
2008-08-02 21:20:13 +00:00
g_stderr->write(buf, strlen(buf));
2008-07-29 08:05:28 +00:00
switch (*lua_getobjname(func, &name)) {
case 'g':
2008-08-03 07:55:16 +00:00
sprintf(buf, "function %s", name);
2008-07-29 08:05:28 +00:00
break;
case 't':
2008-08-03 07:55:16 +00:00
sprintf(buf, "`%s' tag method", name);
2008-07-29 08:05:28 +00:00
break;
default:
2008-07-29 08:05:28 +00:00
{
if (linedefined == 0)
2008-08-03 07:55:16 +00:00
sprintf(buf, "main of %s", filename);
2008-07-29 08:05:28 +00:00
else if (linedefined < 0)
2008-08-03 07:55:16 +00:00
sprintf(buf, "%s", filename);
2008-07-29 08:05:28 +00:00
else
2008-08-03 07:55:16 +00:00
sprintf(buf, "function (%s:%d)", filename, (int)linedefined);
2008-07-29 08:05:28 +00:00
filename = NULL;
}
}
2008-08-02 21:20:13 +00:00
g_stderr->write(buf, strlen(buf));
2008-07-29 08:05:28 +00:00
2008-08-02 21:20:13 +00:00
if ((currentline = lua_currentline(func)) > 0) {
2008-08-03 07:55:16 +00:00
sprintf(buf, " at line %d", (int)currentline);
2008-08-02 21:20:13 +00:00
g_stderr->write(buf, strlen(buf));
}
if (filename) {
2008-08-03 07:55:16 +00:00
sprintf(buf, " [in file %s]", filename);
2008-08-02 21:20:13 +00:00
g_stderr->write(buf, strlen(buf));
}
2008-08-03 07:55:16 +00:00
sprintf(buf, "\n");
2008-08-02 21:20:13 +00:00
g_stderr->write(buf, strlen(buf));
2008-07-29 08:05:28 +00:00
}
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
static void errorfb() {
2008-08-03 07:55:16 +00:00
char buf[256];
sprintf(buf, "lua: %s\n", lua_getstring(lua_getparam(1)));
g_stderr->write(buf, strlen(buf));
2008-08-02 21:20:13 +00:00
lua_printstack();
2003-08-15 18:00:22 +00:00
}
static struct luaL_reg iolib[] = {
2008-07-29 08:05:28 +00:00
{ "date", io_date },
{ "exit", io_exit },
{ "print_stack", errorfb }
2003-08-15 18:00:22 +00:00
};
static struct luaL_reg iolibtag[] = {
2008-07-29 08:05:28 +00:00
{ "readfrom", io_readfrom },
{ "writeto", io_writeto },
{ "appendto", io_appendto },
{ "read", io_read },
{ "write", io_write }
2003-08-15 18:00:22 +00:00
};
2008-07-29 08:05:28 +00:00
static void openwithtags() {
int32 iotag = lua_newtag();
int32 closedtag = lua_newtag();
uint32 i;
for (i = 0; i < sizeof(iolibtag) / sizeof(iolibtag[0]); i++) {
// put both tags as upvalues for these functions
lua_pushnumber(iotag);
lua_pushnumber(closedtag);
lua_pushCclosure(iolibtag[i].func, 2);
2008-07-29 08:05:28 +00:00
lua_setglobal(iolibtag[i].name);
}
2008-08-02 21:20:13 +00:00
g_fin = new LuaFile();
g_fin->_stdin = true;
setfile(addfile(g_fin), FINPUT, iotag);
g_fout = new LuaFile();
g_fout->_stdout = true;
setfile(addfile(g_fout), FOUTPUT, iotag);
g_stdin = new LuaFile();
g_stdin->_stdin = true;
setfile(addfile(g_stdin), "_STDIN", iotag);
g_stdout = new LuaFile();
g_stdout->_stdout = true;
setfile(addfile(g_stdout), "_STDOUT", iotag);
g_stderr = new LuaFile();
g_stderr->_stderr = true;
setfile(addfile(g_stderr), "_STDERR", iotag);
2003-08-15 18:00:22 +00:00
}
2008-07-29 08:05:28 +00:00
void lua_iolibopen() {
g_files = new Common::HashMap<int32, LuaFile *>();
2008-07-29 08:05:28 +00:00
luaL_openlib(iolib, (sizeof(iolib) / sizeof(iolib[0])));
2008-08-02 21:20:13 +00:00
luaL_addlibtolist(iolibtag, (sizeof(iolibtag) / sizeof(iolibtag[0])));
2008-07-29 08:05:28 +00:00
openwithtags();
lua_pushcfunction(errorfb);
lua_seterrormethod();
2003-08-15 18:00:22 +00:00
}
2008-08-02 21:20:13 +00:00
void lua_iolibclose() {
delete g_fin;
delete g_fout;
delete g_stdin;
delete g_stdout;
delete g_stderr;
delete g_files;
2008-08-02 21:20:13 +00:00
}
2009-05-25 06:49:57 +00:00
} // end of namespace Grim