/* llualib.c Copyright 2006-2008 Taco Hoekwater This file is part of LuaTeX. LuaTeX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with LuaTeX; if not, see . */ #include "ptexlib.h" #include "lua/luatex-api.h" #define LOAD_BUF_SIZE 64*1024 #define UINT_MAX32 0xFFFFFFFF typedef struct { unsigned char *buf; int size; /* int done; */ int alloc; } bytecode; static bytecode *lua_bytecode_registers = NULL; int luabytecode_max = -1; unsigned int luabytecode_bytes = 0; char *luanames[65536] = { NULL }; char *get_lua_name(int i) { if (i < 0 || i > 65535) return NULL; return luanames[i]; } void dump_luac_registers(void) { int x; int k, n; bytecode b; dump_int(luabytecode_max); if (lua_bytecode_registers != NULL) { n = 0; for (k = 0; k <= luabytecode_max; k++) { if (lua_bytecode_registers[k].size != 0) n++; } dump_int(n); for (k = 0; k <= luabytecode_max; k++) { b = lua_bytecode_registers[k]; if (b.size != 0) { dump_int(k); dump_int(b.size); do_zdump((char *) b.buf, 1, (b.size), DUMP_FILE); } } } for (k = 0; k < 65536; k++) { char *a = luanames[k]; if (a != NULL) { x = (int) strlen(a) + 1; dump_int(x); dump_things(*a, x); } else { x = 0; dump_int(x); } } } void undump_luac_registers(void) { int x; int k, n; unsigned int i; bytecode b; undump_int(luabytecode_max); if (luabytecode_max >= 0) { i = (unsigned) (luabytecode_max + 1); if ((int) (UINT_MAX32 / (int) sizeof(bytecode) + 1) <= i) { fatal_error("Corrupt format file"); } lua_bytecode_registers = xmalloc((unsigned) (i * sizeof(bytecode))); luabytecode_bytes = (unsigned) (i * sizeof(bytecode)); for (i = 0; i <= (unsigned) luabytecode_max; i++) { /* lua_bytecode_registers[i].done = 0; */ lua_bytecode_registers[i].size = 0; lua_bytecode_registers[i].buf = NULL; } undump_int(n); for (i = 0; i < (unsigned) n; i++) { undump_int(k); undump_int(x); b.size = x; b.buf = xmalloc((unsigned) b.size); luabytecode_bytes += (unsigned) b.size; memset(b.buf, 0, (size_t) b.size); do_zundump((char *) b.buf, 1, b.size, DUMP_FILE); lua_bytecode_registers[k].size = b.size; lua_bytecode_registers[k].alloc = b.size; lua_bytecode_registers[k].buf = b.buf; } } for (k = 0; k < 65536; k++) { undump_int(x); if (x > 0) { char *s = xmalloc((unsigned) x); undump_things(*s, x); luanames[k] = s; } } } static void bytecode_register_shadow_set(lua_State * L, int k) { /* the stack holds the value to be set */ lua_get_metatablelua(lua_bytecodes_indirect); if (lua_istable(L, -1)) { lua_pushvalue(L, -2); lua_rawseti(L, -2, k); } lua_pop(L, 1); /* pop table or nil */ lua_pop(L, 1); /* pop value */ } static int bytecode_register_shadow_get(lua_State * L, int k) { /* the stack holds the value to be set */ int ret = 0; lua_get_metatablelua(lua_bytecodes_indirect); if (lua_istable(L, -1)) { lua_rawgeti(L, -1, k); if (!lua_isnil(L, -1)) ret = 1; lua_insert(L, -3); /* store the value or nil, deeper down */ lua_pop(L, 1); /* pop the value or nil at top */ } lua_pop(L, 1); /* pop table or nil */ return ret; } static int writer(lua_State * L, const void *b, size_t size, void *B) { bytecode *buf = (bytecode *) B; (void) L; /* for -Wunused */ if ((int) (buf->size + (int) size) > buf->alloc) { buf->buf = xrealloc(buf->buf, (unsigned) (buf->alloc + (int) size + LOAD_BUF_SIZE)); buf->alloc = buf->alloc + (int) size + LOAD_BUF_SIZE; } memcpy(buf->buf + buf->size, b, size); buf->size += (int) size; luabytecode_bytes += (unsigned) size; return 0; } static const char *reader(lua_State * L, void *ud, size_t * size) { bytecode *buf = (bytecode *) ud; (void) L; /* for -Wunused */ /* if (buf->done == buf->size) { *size = 0; buf->done = 0; return NULL; } */ *size = (size_t) buf->size; /* buf->done = buf->size; */ return (const char *) buf->buf; } static int get_bytecode(lua_State * L) { int k; k = (int) luaL_checkinteger(L, -1); if (k < 0) { lua_pushnil(L); } else if (!bytecode_register_shadow_get(L, k)) { if (k <= luabytecode_max && lua_bytecode_registers[k].buf != NULL) { if (lua_load (L, reader, (void *) (lua_bytecode_registers + k), #ifdef LuajitTeX "bytecode")) { #else "bytecode", NULL)) { #endif return luaL_error(L, "bad bytecode register"); } else { lua_pushvalue(L, -1); bytecode_register_shadow_set(L, k); } } else { lua_pushnil(L); } } return 1; } void luabytecodecall(int slot) { int i; int stacktop = lua_gettop(Luas); lua_active++; if (slot < 0 || slot > luabytecode_max) { luaL_error(Luas, "bytecode register out of range"); } else if (bytecode_register_shadow_get(Luas, slot) || lua_bytecode_registers[slot].buf == NULL) { luaL_error(Luas, "undefined bytecode register"); } else if (lua_load(Luas, reader, (void *) (lua_bytecode_registers + slot), #ifdef LuajitTeX "bytecode")) #else "bytecode", NULL)) #endif { luaL_error(Luas, "bytecode register doesn't load well"); } else { int base = lua_gettop(Luas); /* function index */ lua_pushinteger(Luas, slot); lua_pushcfunction(Luas, lua_traceback); /* push traceback function */ lua_insert(Luas, base); /* put it under chunk */ ++function_callback_count; /* this will be a dedicated counter */ i = lua_pcall(Luas, 1, 0, base); lua_remove(Luas, base); /* remove traceback function */ if (i != 0) { lua_gc(Luas, LUA_GCCOLLECT, 0); Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1)); } } lua_settop(Luas,stacktop); lua_active--; } static int set_bytecode(lua_State * L) { int k, ltype; unsigned int i; int strip = 0; int top = lua_gettop(L); if (lua_type(L,top) == LUA_TBOOLEAN) { strip = lua_toboolean(L,top); lua_settop(L,top - 1); } k = (int) luaL_checkinteger(L, -2); i = (unsigned) k + 1; if ((int) (UINT_MAX32 / sizeof(bytecode) + 1) < i) { luaL_error(L, "value too large"); } if (k < 0) { luaL_error(L, "negative values not allowed"); } ltype = lua_type(L, -1); if (ltype != LUA_TFUNCTION && ltype != LUA_TNIL) { luaL_error(L, "unsupported type"); } if (k > luabytecode_max) { i = (unsigned) (sizeof(bytecode) * ((unsigned) k + 1)); lua_bytecode_registers = xrealloc(lua_bytecode_registers, i); if (luabytecode_max == -1) { luabytecode_bytes += (unsigned) (sizeof(bytecode) * (unsigned) (k + 1)); } else { luabytecode_bytes += (unsigned) (sizeof(bytecode) * (unsigned) (k + 1 - luabytecode_max)); } for (i = (unsigned) (luabytecode_max + 1); i <= (unsigned) k; i++) { lua_bytecode_registers[i].buf = NULL; lua_bytecode_registers[i].size = 0; /* lua_bytecode_registers[i].done = 0; */ } luabytecode_max = k; } if (lua_bytecode_registers[k].buf != NULL) { xfree(lua_bytecode_registers[k].buf); luabytecode_bytes -= (unsigned) lua_bytecode_registers[k].size; lua_bytecode_registers[k].size = 0; /* lua_bytecode_registers[k].done = 0; */ lua_pushnil(L); bytecode_register_shadow_set(L, k); } if (ltype == LUA_TFUNCTION) { lua_bytecode_registers[k].buf = xmalloc(LOAD_BUF_SIZE); lua_bytecode_registers[k].alloc = LOAD_BUF_SIZE; memset(lua_bytecode_registers[k].buf, 0, LOAD_BUF_SIZE); #ifdef LuajitTeX RESERVED_lua_dump(L, writer, (void *) (lua_bytecode_registers + k),strip); /*lua_dump(L, writer, (void *) (lua_bytecode_registers + k));*/ #else #if LUA_VERSION_NUM == 503 lua_dump(L, writer, (void *) (lua_bytecode_registers + k),strip); #endif #if LUA_VERSION_NUM == 502 lua_dump(L, writer, (void *) (lua_bytecode_registers + k)); #endif #endif } lua_pop(L, 1); return 0; } static int set_luaname(lua_State * L) { int k; const char *s; if (lua_gettop(L) == 2) { k = (int) luaL_checkinteger(L, 1); if (k > 65535 || k < 0) { /* error */ } else { if (luanames[k] != NULL) { free(luanames[k]); luanames[k] = NULL; } if (lua_type(L, 2) == LUA_TSTRING) { s = lua_tostring(L, 2); if (s != NULL) luanames[k] = xstrdup(s); } } } return 0; } static int get_luaname(lua_State * L) { int k = (int) luaL_checkinteger(L, 1); if (k > 65535 || k < 0) { /* error */ lua_pushnil(L); } else { if (luanames[k] != NULL) lua_pushstring(L, luanames[k]); else lua_pushnil(L); } return 1; } static int lua_functions_get_table(lua_State * L) /* hh */ { lua_get_metatablelua(lua_functions); return 1; } static int new_table(lua_State * L) /* hh */ { int i = (int) luaL_checkinteger(L, 1); int h = (int) luaL_checkinteger(L, 2); lua_createtable(L,i,h); return 1; } static int get_stack_top(lua_State * L) /* hh */ { lua_pushinteger(L, lua_gettop(L)); return 1; } static int get_call_level(lua_State * L) /* hh */ { lua_pushinteger(L, lua_active); return 1; } static int get_code_page(lua_State *L) { # ifdef _WIN32 lua_pushinteger(L,(int) GetOEMCP()); lua_pushinteger(L,(int) GetACP()); # else lua_pushboolean(L,0); lua_pushboolean(L,0); # endif return 2; } static const struct luaL_Reg lualib[] = { /* *INDENT-OFF* */ {"getluaname", get_luaname}, {"setluaname", set_luaname}, {"getbytecode", get_bytecode}, {"setbytecode", set_bytecode}, {"newtable", new_table}, {"get_functions_table",lua_functions_get_table}, {"getstacktop", get_stack_top}, {"getcalllevel", get_call_level}, {"getcodepage", get_code_page }, /* *INDENT-ON* */ {NULL, NULL} /* sentinel */ }; int luaopen_lua(lua_State * L, char *fname) { luaL_openlib(L, "lua", lualib, 0); make_table(L, "bytecode", "tex.bytecode", "getbytecode", "setbytecode"); make_table(L, "name", "tex.name", "getluaname", "setluaname"); lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "lua.bytecodes.indirect"); lua_pushstring(L, LUA_VERSION); lua_setfield(L, -2, "version"); if (fname == NULL) { lua_pushnil(L); } else { lua_pushstring(L, fname); } lua_setfield(L, -2, "startupfile"); return 1; }