/* * lmo - Lua Machine Objects - Lua binding * * Copyright (C) 2009 Jo-Philipp Wich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "lmo_lualib.h" extern char _lmo_error[1024]; static int lmo_L_open(lua_State *L) { const char *filename = luaL_checklstring(L, 1, NULL); lmo_archive_t *ar, **udata; if( (ar = lmo_open(filename)) != NULL ) { if( (udata = lua_newuserdata(L, sizeof(lmo_archive_t *))) != NULL ) { *udata = ar; luaL_getmetatable(L, LMO_ARCHIVE_META); lua_setmetatable(L, -2); return 1; } lmo_close(ar); lua_pushnil(L); lua_pushstring(L, "out of memory"); return 2; } lua_pushnil(L); lua_pushstring(L, lmo_error()); return 2; } static int lmo_L_hash(lua_State *L) { const char *data = luaL_checkstring(L, 1); uint32_t hash = sfh_hash(data, strlen(data)); lua_pushinteger(L, (lua_Integer)hash); return 1; } static lmo_luaentry_t *_lmo_push_entry(lua_State *L) { lmo_luaentry_t *le; if( (le = lua_newuserdata(L, sizeof(lmo_luaentry_t))) != NULL ) { luaL_getmetatable(L, LMO_ENTRY_META); lua_setmetatable(L, -2); return le; } return NULL; } static int _lmo_lookup(lua_State *L, lmo_archive_t *ar, uint32_t hash) { lmo_entry_t *e = ar->index; lmo_luaentry_t *le = NULL; while( e != NULL ) { if( e->key_id == hash ) { if( (le = _lmo_push_entry(L)) != NULL ) { le->archive = ar; le->entry = e; return 1; } else { lua_pushnil(L); lua_pushstring(L, "out of memory"); return 2; } } e = e->next; } lua_pushnil(L); return 1; } static int lmo_L_get(lua_State *L) { lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); uint32_t hash = (uint32_t) luaL_checkinteger(L, 2); return _lmo_lookup(L, *ar, hash); } static int lmo_L_lookup(lua_State *L) { lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); const char *key = luaL_checkstring(L, 2); uint32_t hash = sfh_hash(key, strlen(key)); return _lmo_lookup(L, *ar, hash); } static int lmo_L_foreach(lua_State *L) { lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); lmo_entry_t *e = (*ar)->index; if( lua_isfunction(L, 2) ) { while( e != NULL ) { lua_pushvalue(L, 2); lua_pushinteger(L, e->key_id); lua_pushlstring(L, &(*ar)->mmap[e->offset], e->length); lua_pcall(L, 2, 0, 0); e = e->next; } } return 0; } static int lmo_L__gc(lua_State *L) { lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); if( (*ar) != NULL ) lmo_close(*ar); *ar = NULL; return 0; } static int lmo_L__tostring(lua_State *L) { lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); lua_pushfstring(L, "LMO Archive (%d bytes)", (*ar)->length); return 1; } static int _lmo_convert_entry(lua_State *L, int idx) { lmo_luaentry_t *le = luaL_checkudata(L, idx, LMO_ENTRY_META); lua_pushlstring(L, &le->archive->mmap[le->entry->offset], le->entry->length ); return 1; } static int lmo_L_entry__tostring(lua_State *L) { return _lmo_convert_entry(L, 1); } static int lmo_L_entry__concat(lua_State *L) { if( lua_isuserdata(L, 1) ) _lmo_convert_entry(L, 1); else lua_pushstring(L, lua_tostring(L, 1)); if( lua_isuserdata(L, 2) ) _lmo_convert_entry(L, 2); else lua_pushstring(L, lua_tostring(L, 2)); lua_concat(L, 2); return 1; } static int lmo_L_entry__len(lua_State *L) { lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META); lua_pushinteger(L, le->entry->length); return 1; } static int lmo_L_entry__gc(lua_State *L) { lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META); le->archive = NULL; le->entry = NULL; return 0; } /* lmo method table */ static const luaL_reg M[] = { {"close", lmo_L__gc}, {"get", lmo_L_get}, {"lookup", lmo_L_lookup}, {"foreach", lmo_L_foreach}, {"__tostring", lmo_L__tostring}, {"__gc", lmo_L__gc}, {NULL, NULL} }; /* lmo.entry method table */ static const luaL_reg E[] = { {"__tostring", lmo_L_entry__tostring}, {"__concat", lmo_L_entry__concat}, {"__len", lmo_L_entry__len}, {"__gc", lmo_L_entry__gc}, {NULL, NULL} }; /* module table */ static const luaL_reg R[] = { {"open", lmo_L_open}, {"hash", lmo_L_hash}, {NULL, NULL} }; LUALIB_API int luaopen_lmo(lua_State *L) { luaL_newmetatable(L, LMO_ARCHIVE_META); luaL_register(L, NULL, M); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_setglobal(L, LMO_ARCHIVE_META); luaL_newmetatable(L, LMO_ENTRY_META); luaL_register(L, NULL, E); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_setglobal(L, LMO_ENTRY_META); luaL_register(L, LMO_LUALIB_META, R); return 1; }