387 lines
7.6 KiB
C
387 lines
7.6 KiB
C
#ifndef STEAD_PATH
|
|
#define STEAD_PATH "./stead"
|
|
#endif
|
|
|
|
#include "externals.h"
|
|
#include "internals.h"
|
|
/* the Lua interpreter */
|
|
|
|
char *fromgame(const char *s);
|
|
char *togame(const char *s);
|
|
lua_State *L = NULL;
|
|
|
|
static int report (lua_State *L, int status)
|
|
{
|
|
if (status && !lua_isnil(L, -1)) {
|
|
const char *msg = lua_tostring(L, -1);
|
|
if (msg == NULL)
|
|
msg = "(error object is not a string)";
|
|
fprintf(stderr,"Error: %s\n", msg);
|
|
game_err_msg(msg);
|
|
lua_pop(L, 1);
|
|
status = -1;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static int traceback (lua_State *L)
|
|
{
|
|
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
|
if (!lua_istable(L, -1)) {
|
|
lua_pop(L, 1);
|
|
return 1;
|
|
}
|
|
lua_getfield(L, -1, "traceback");
|
|
if (!lua_isfunction(L, -1)) {
|
|
lua_pop(L, 2);
|
|
return 1;
|
|
}
|
|
lua_pushvalue(L, 1); /* pass error message */
|
|
lua_pushinteger(L, 2); /* skip this function and traceback */
|
|
lua_call(L, 2, 1); /* call debug.traceback */
|
|
return 1;
|
|
}
|
|
|
|
extern int debug_sw;
|
|
|
|
static int docall (lua_State *L)
|
|
{
|
|
int status;
|
|
int base = 0;
|
|
if (debug_sw) {
|
|
base = lua_gettop(L); /* function index */
|
|
lua_pushcfunction(L, traceback); /* push traceback function */
|
|
lua_insert(L, base); /* put it under chunk and args */
|
|
}
|
|
status = lua_pcall(L, 0, LUA_MULTRET, base);
|
|
if (debug_sw)
|
|
lua_remove(L, base); /* remove traceback function */
|
|
/* force a complete garbage collection in case of errors */
|
|
if (status != 0)
|
|
lua_gc(L, LUA_GCCOLLECT, 0);
|
|
return status;
|
|
}
|
|
|
|
static int dofile (lua_State *L, const char *name) {
|
|
int status = luaL_loadfile(L, name) || docall(L);
|
|
return report(L, status);
|
|
}
|
|
|
|
static int dostring (lua_State *L, const char *s) {
|
|
int status = luaL_loadstring(L, s) || docall(L);
|
|
return report(L, status);
|
|
}
|
|
|
|
char *getstring(char *cmd)
|
|
{
|
|
char *s;
|
|
if (!L)
|
|
return NULL;
|
|
if (dostring(L, cmd))
|
|
return NULL;
|
|
s = (char*)lua_tostring(L, -1);
|
|
if (s)
|
|
s = fromgame(s);
|
|
return s;
|
|
}
|
|
|
|
|
|
char *instead_eval(char *s)
|
|
{
|
|
char *p;
|
|
p = getstring(s);
|
|
return p;
|
|
}
|
|
|
|
char *instead_cmd(char *s)
|
|
{
|
|
char buf[1024];
|
|
char *p = s;
|
|
while (*p) {
|
|
if (*p == '\\' || *p == '\'' || *p == '\"' || *p == '[' || *p == ']')
|
|
return NULL;
|
|
p ++;
|
|
}
|
|
s = togame(s);
|
|
snprintf(buf, sizeof(buf), "return iface:cmd('%s')", s);
|
|
free(s);
|
|
p = getstring(buf);
|
|
return p;
|
|
}
|
|
|
|
int luacall(char *cmd)
|
|
{
|
|
int rc;
|
|
if (!L)
|
|
return -1;
|
|
if (dostring(L, cmd)) {
|
|
return -1;
|
|
}
|
|
rc = lua_tonumber(L, -1);
|
|
return rc;
|
|
}
|
|
|
|
#ifdef _HAVE_ICONV
|
|
static char *curcp = "UTF-8";
|
|
static char *fromcp = NULL;
|
|
#endif
|
|
|
|
#ifdef _HAVE_ICONV
|
|
#define CHAR_MAX_LEN 4
|
|
static char *decode(iconv_t hiconv, const char *s)
|
|
{
|
|
size_t s_size, chs_size, outsz, insz;
|
|
char *inbuf, *outbuf, *chs_buf;
|
|
if (!s || hiconv == (iconv_t)(-1))
|
|
return NULL;
|
|
s_size = strlen(s) + 1;
|
|
chs_size = s_size * CHAR_MAX_LEN;
|
|
if ((chs_buf = malloc(chs_size + CHAR_MAX_LEN))==NULL)
|
|
goto exitf;
|
|
outsz = chs_size;
|
|
outbuf = chs_buf;
|
|
insz = s_size;
|
|
inbuf = (char*)s;
|
|
while (insz) {
|
|
if (iconv(hiconv, &inbuf, &insz, &outbuf, &outsz)
|
|
== (size_t)(-1))
|
|
goto exitf;
|
|
}
|
|
*outbuf++ = 0;
|
|
return chs_buf;
|
|
exitf:
|
|
if(chs_buf)
|
|
free(chs_buf);
|
|
return NULL;
|
|
}
|
|
|
|
char *fromgame(const char *s)
|
|
{
|
|
iconv_t han;
|
|
char *str;
|
|
if (!s)
|
|
return NULL;
|
|
if (!fromcp)
|
|
goto out0;
|
|
han = iconv_open(curcp, fromcp);
|
|
if (han == (iconv_t)-1)
|
|
goto out0;
|
|
if (!(str = decode(han, s)))
|
|
goto out1;
|
|
iconv_close(han);
|
|
return str;
|
|
out1:
|
|
iconv_close(han);
|
|
out0:
|
|
return strdup(s);
|
|
}
|
|
|
|
char *togame(const char *s)
|
|
{
|
|
iconv_t han;
|
|
char *str;
|
|
if (!s)
|
|
return NULL;
|
|
if (!fromcp)
|
|
goto out0;
|
|
han = iconv_open(fromcp, curcp);
|
|
if (han == (iconv_t)-1)
|
|
goto out0;
|
|
if (!(str = decode(han, s)))
|
|
goto out1;
|
|
iconv_close(han);
|
|
return str;
|
|
out1:
|
|
iconv_close(han);
|
|
out0:
|
|
return strdup(s);
|
|
}
|
|
#else
|
|
char *fromgame(const char *s)
|
|
{
|
|
if (!s)
|
|
return NULL;
|
|
return strdup(s);
|
|
}
|
|
char *togame(const char *s)
|
|
{
|
|
if (!s)
|
|
return NULL;
|
|
return strdup(s);
|
|
}
|
|
#endif
|
|
|
|
int instead_load(char *game)
|
|
{
|
|
if (dofile(L, game)) {
|
|
return -1;
|
|
}
|
|
#ifdef _HAVE_ICONV
|
|
if (fromcp)
|
|
free(fromcp);
|
|
fromcp = getstring("return game.codepage;");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
typedef struct LoadF {
|
|
int extraline;
|
|
unsigned char byte;
|
|
FILE *f;
|
|
unsigned char buff[4096];
|
|
} LoadF;
|
|
|
|
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
|
int i = 0;
|
|
LoadF *lf = (LoadF *)ud;
|
|
(void)L;
|
|
if (lf->extraline) {
|
|
lf->extraline = 0;
|
|
*size = 1;
|
|
return "\n";
|
|
}
|
|
if (feof(lf->f)) return NULL;
|
|
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
|
|
for (i = 0; i < *size; i ++) {
|
|
unsigned char b = lf->buff[i];
|
|
lf->buff[i] ^= lf->byte;
|
|
lf->buff[i] = (lf->buff[i] >> 3) | (lf->buff[i] << 5);
|
|
lf->byte = b;
|
|
}
|
|
return (*size > 0) ? (char*)lf->buff : NULL;
|
|
}
|
|
|
|
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
|
const char *serr = strerror(errno);
|
|
const char *filename = lua_tostring(L, fnameindex) + 1;
|
|
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
|
lua_remove(L, fnameindex);
|
|
return LUA_ERRFILE;
|
|
}
|
|
|
|
static int loadfile (lua_State *L, const char *filename) {
|
|
LoadF lf;
|
|
int status, readstatus;
|
|
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
|
|
lf.extraline = 0;
|
|
lua_pushfstring(L, "@%s", filename);
|
|
lf.f = fopen(filename, "rb");
|
|
lf.byte = 0xcc;
|
|
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
|
status = lua_load(L, getF, &lf, lua_tostring(L, -1));
|
|
readstatus = ferror(lf.f);
|
|
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
|
if (readstatus) {
|
|
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
|
|
return errfile(L, "read", fnameindex);
|
|
}
|
|
lua_remove(L, fnameindex);
|
|
return status;
|
|
}
|
|
|
|
|
|
static int luaB_doencfile (lua_State *L) {
|
|
const char *fname = luaL_optstring(L, 1, NULL);
|
|
int n = lua_gettop(L);
|
|
if (loadfile(L, fname) != 0) lua_error(L);
|
|
lua_call(L, 0, LUA_MULTRET);
|
|
return lua_gettop(L) - n;
|
|
}
|
|
|
|
static int luaB_print (lua_State *L) {
|
|
int n = lua_gettop(L); /* number of arguments */
|
|
int i;
|
|
lua_getglobal(L, "tostring");
|
|
for (i=1; i<=n; i++) {
|
|
const char *s;
|
|
lua_pushvalue(L, -1); /* function to be called */
|
|
lua_pushvalue(L, i); /* value to print */
|
|
lua_call(L, 1, 1);
|
|
s = lua_tostring(L, -1); /* get result */
|
|
if (s == NULL)
|
|
return luaL_error(L, LUA_QL("tostring") " must return a string to "LUA_QL("print"));
|
|
if (i>1) fputs("\t", stdout);
|
|
fputs(s, stdout);
|
|
lua_pop(L, 1); /* pop result */
|
|
}
|
|
fputs("\n", stdout);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg base_funcs[] = {
|
|
{"doencfile", luaB_doencfile},
|
|
{"print", luaB_print}, /* for some mystic, it is needed in win version (with -debug) */
|
|
{NULL, NULL}
|
|
};
|
|
|
|
int instead_init(void)
|
|
{
|
|
setlocale(LC_ALL,"");
|
|
// strcpy(curcp, "UTF-8");
|
|
/* initialize Lua */
|
|
L = lua_open();
|
|
if (!L)
|
|
return -1;
|
|
luaL_openlibs(L);
|
|
luaL_register(L, "_G", base_funcs);
|
|
if (dofile(L,STEAD_PATH"/stead.lua")) {
|
|
return -1;
|
|
}
|
|
|
|
if (dofile(L,STEAD_PATH"/gui.lua")) {
|
|
return -1;
|
|
}
|
|
/* cleanup Lua */
|
|
return 0;
|
|
}
|
|
|
|
void instead_done(void)
|
|
{
|
|
#ifdef _HAVE_ICONV
|
|
if (fromcp)
|
|
free(fromcp);
|
|
#endif
|
|
if (L)
|
|
lua_close(L);
|
|
L = NULL;
|
|
#ifdef _HAVE_ICONV
|
|
fromcp = NULL;
|
|
#endif
|
|
}
|
|
|
|
int instead_encode(const char *s, const char *d)
|
|
{
|
|
FILE *src;
|
|
FILE *dst;
|
|
size_t size;
|
|
int i = 0;
|
|
unsigned char byte = 0xcc;
|
|
unsigned char buff[4096];
|
|
|
|
src = fopen(s, "rb");
|
|
if (!src) {
|
|
fprintf(stderr,"Can't open on read: '%s'.\n", s);
|
|
return -1;
|
|
}
|
|
dst = fopen(d, "wb");
|
|
if (!dst) {
|
|
fprintf(stderr,"Can't open on write: '%s'.\n", s);
|
|
return -1;
|
|
}
|
|
while ((size = fread(buff, 1, sizeof(buff), src))) {
|
|
for (i = 0; i < size; i++) {
|
|
buff[i] = (buff[i] << 3) | (buff[i] >> 5);
|
|
buff[i] ^= byte;
|
|
byte = buff[i];
|
|
}
|
|
if (fwrite(buff, 1, size, dst) != size) {
|
|
fprintf(stderr, "Error while writing file: '%s'.\n", d);
|
|
return -1;
|
|
}
|
|
}
|
|
fclose(src);
|
|
fclose(dst);
|
|
return 0;
|
|
}
|
|
|