/* llualib.c
Copyright 2006-2008 Taco Hoekwater <
[email protected]>
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 <
http://www.gnu.org/licenses/>. */
#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;
}