/* 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 "lua/luatex-api.h" #include "ptexlib.h" static const char _svn_version[] = "$Id: llualib.c 3615 2010-04-13 21:59:59Z oneiros $ $URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.70.1/source/texk/web2c/luatexdir/lua/llualib.c $"; #define LOAD_BUF_SIZE 256 #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) { lua_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_pushstring(L, "bytecode_shadow"); /* lua.bytecode_shadow */ lua_rawget(L, LUA_REGISTRYINDEX); 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_pushstring(L, "bytecode_shadow"); lua_rawget(L, LUA_REGISTRYINDEX); 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), "bytecode")) { return luaL_error(L, "bad bytecode register"); } else { lua_pushvalue(L, -1); bytecode_register_shadow_set(L, k); } } else { lua_pushnil(L); } } return 1; } static int set_bytecode(lua_State * L) { int k, ltype; unsigned int i; 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); lua_dump(L, writer, (void *) (lua_bytecode_registers + k)); } lua_pop(L, 1); return 0; } static int set_luaname(lua_State * L) { int k; const char *s; if (lua_gettop(L) == 3) { k = (int) luaL_checkinteger(L, 2); if (k > 65535 || k < 0) { /* error */ } else { if (luanames[k] != NULL) { free(luanames[k]); luanames[k] = NULL; } if (lua_isstring(L, 3)) { s = lua_tostring(L, 3); if (s != NULL) luanames[k] = xstrdup(s); } } } return 0; } static int get_luaname(lua_State * L) { int k; k = (int) luaL_checkinteger(L, 2); 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 const struct luaL_reg lualib[] = { /* *INDENT-OFF* */ {"getluaname", get_luaname}, {"setluaname", set_luaname}, {"getbytecode", get_bytecode}, {"setbytecode", set_bytecode}, /* *INDENT-ON* */ {NULL, NULL} /* sentinel */ }; int luaopen_lua(lua_State * L, char *fname) { luaL_register(L, "lua", lualib); make_table(L, "bytecode", "getbytecode", "setbytecode"); make_table(L, "name", "getluaname", "setluaname"); lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "bytecode_shadow"); 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; }