Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Lua_library_template/udtype_example/udtype.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
253 lines (206 sloc)
6.97 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <lua.h> | |
| #include <lauxlib.h> | |
| #include "udtype.h" // TODO: rename | |
| /* | |
| ** =============================================================== | |
| ** Declarations | |
| ** =============================================================== | |
| */ | |
| // TODO: add declarations | |
| /* | |
| ** =============================================================== | |
| ** Generic internal code | |
| ** =============================================================== | |
| */ | |
| // TODO: add generic code | |
| #ifdef _DEBUG | |
| //can be found here http://www.lua.org/pil/24.2.3.html | |
| static void stackDump (lua_State *L, const char *text) { | |
| int i; | |
| int top = lua_gettop(L); | |
| if (text == NULL) | |
| printf("--------Start Dump------------\n"); | |
| else | |
| printf("--------Start %s------------\n", text); | |
| for (i = 1; i <= top; i++) { /* repeat for each level */ | |
| int t = lua_type(L, i); | |
| switch (t) { | |
| case LUA_TSTRING: /* strings */ | |
| printf("`%s'", lua_tostring(L, i)); | |
| break; | |
| case LUA_TBOOLEAN: /* booleans */ | |
| printf(lua_toboolean(L, i) ? "true" : "false"); | |
| break; | |
| case LUA_TNUMBER: /* numbers */ | |
| printf("%g", lua_tonumber(L, i)); | |
| break; | |
| default: /* other values */ | |
| printf("%s", lua_typename(L, t)); | |
| break; | |
| } | |
| printf(" "); /* put a separator */ | |
| } | |
| printf("\n"); /* end the listing */ | |
| printf("--------End Dump------------\n"); | |
| } | |
| static void tableDump(lua_State *L, int idx, const char* text) | |
| { | |
| lua_pushvalue(L, idx); // copy target table | |
| lua_pushnil(L); | |
| if (text == NULL) | |
| printf("--------Table Dump------------\n"); | |
| else | |
| printf("--------Table dump: %s------------\n", text); | |
| while (lua_next(L,-2) != 0) { | |
| printf("%s - %s\n", | |
| lua_typename(L, lua_type(L, -2)), | |
| lua_typename(L, lua_type(L, -1))); | |
| lua_pop(L, 1); | |
| } | |
| lua_pop(L, 1); // remove table copy | |
| printf("--------End Table dump------------\n"); | |
| } | |
| #endif | |
| /* | |
| ** =============================================================== | |
| ** Exposed Lua API | |
| ** =============================================================== | |
| */ | |
| // TODO: example somefunction, add more here | |
| int L_type(lua_State *L) | |
| { | |
| // perform standard type functionality | |
| luaL_checkany(L, 1); | |
| lua_settop(L, 1); // val | |
| lua_checkstack(L, 6); | |
| lua_pushstring(L, luaL_typename(L, 1)); // val, type | |
| // Now check for userdata and metatable | |
| if (lua_type(L, 1) == LUA_TUSERDATA) { | |
| if (lua_getmetatable(L, 1) != 0) { // val, type, metatable | |
| // it is a userdata and has a metatable | |
| lua_getfield(L, LUA_REGISTRYINDEX, UDTYPE_TABLE); // val, type, metatable, mytable | |
| lua_insert(L, -2); // val, type, mytable, metatable | |
| lua_pushvalue(L, -1); // val, type, mytable, metatable, metatable | |
| lua_gettable(L, -3); // val, type, mytable, metatable, metatablename|nil | |
| if (! lua_isnil(L,-1)) { | |
| // metatable was in our list | |
| lua_remove(L, -2); // val, type, mytable, metatablename | |
| lua_remove(L, -2); // val, type, metatablename | |
| return 2; | |
| } else { | |
| // metatable isn't in our list already, so go look it up // val, type, mytable, metatable, nil | |
| while (lua_next(L, LUA_REGISTRYINDEX) != 0) { // val, type, mytable, metatable, key, value | |
| #if LUA_VERSION_NUM < 502 | |
| if (lua_equal(L, -3, -1)) { | |
| #else | |
| if (lua_compare(L, -3, -1, LUA_OPEQ)) { | |
| #endif | |
| // found it! // val, type, mytable, metatable, metatablename, metatable | |
| lua_remove(L, -3); // val, type, mytable, metatablename, metatable | |
| lua_pushvalue(L, -2); // val, type, mytable, metatablename, metatable, metatablename | |
| lua_settable(L, 3); // val, type, mytable, metatablename | |
| lua_remove(L, -2); // val, type, metatablename | |
| return 2; | |
| } | |
| lua_pop(L,1); // val, type, mytable, metatable, key | |
| } | |
| // metatable not found, return type only | |
| lua_settop(L,2); // val, type | |
| return 1; | |
| } | |
| } else { | |
| // It is a userdata, without a metatable | |
| return 1; | |
| } | |
| } else { | |
| return 1; // just the regular type | |
| } | |
| }; | |
| /* | |
| ** =============================================================== | |
| ** Library initialization and shutdown | |
| ** =============================================================== | |
| */ | |
| // Structure with all functions made available to Lua | |
| static const struct luaL_Reg LuaExportFunctions[] = { | |
| // TODO: add functions from 'exposed Lua API' section above | |
| {"type",L_type}, | |
| {NULL,NULL} | |
| }; | |
| // Open method called when Lua opens the library | |
| // On success; return 1 | |
| // On error; push errorstring on stack and return 0 | |
| static int L_openLib(lua_State *L) { | |
| // create lookup table for already checked metatables | |
| lua_newtable(L); | |
| // set weak keys and values | |
| luaL_newmetatable(L, UDTYPE_TABLEMT); | |
| lua_pushstring(L, "k"); | |
| lua_setfield(L, -2, "__mode"); | |
| // store it in registry | |
| lua_setfield(L, LUA_REGISTRYINDEX, UDTYPE_TABLE); | |
| return 1; // report success | |
| } | |
| // Close method called when Lua shutsdown the library | |
| // Note: check Lua os.exit() function for exceptions, | |
| // it will not always be called! | |
| static int L_closeLib(lua_State *L) { | |
| // TODO: add shutdown/cleanup code | |
| return 0; | |
| } | |
| /* | |
| ** =============================================================== | |
| ** Core startup functionality, no need to change anything below | |
| ** =============================================================== | |
| */ | |
| // Setup a userdata to provide a close method | |
| static void L_setupClose(lua_State *L) { | |
| // create library tracking userdata | |
| if (lua_newuserdata(L, sizeof(void*)) == NULL) { | |
| luaL_error(L, "Cannot allocate userdata, out of memory?"); | |
| }; | |
| // Create a new metatable for the tracking userdata | |
| luaL_newmetatable(L, LTLIB_UDATAMT); | |
| // Add GC metamethod | |
| lua_pushstring(L, "__gc"); | |
| lua_pushcfunction(L, L_closeLib); | |
| lua_settable(L, -3); | |
| // Attach metatable to userdata | |
| lua_setmetatable(L, -2); | |
| // store userdata in registry | |
| lua_setfield(L, LUA_REGISTRYINDEX, LTLIB_UDATANAME); | |
| } | |
| // When initialization fails, removes the userdata and metatable | |
| // again, throws the error stored by L_openLib(), will not return | |
| // Top of stack must hold error string | |
| static void L_openFailed(lua_State *L) { | |
| // get userdata and remove its metatable | |
| lua_getfield(L, LUA_REGISTRYINDEX, LTLIB_UDATANAME); | |
| lua_pushnil(L); | |
| lua_setmetatable(L, -2); | |
| // remove userdata | |
| lua_pushnil(L); | |
| lua_setfield(L, LUA_REGISTRYINDEX, LTLIB_UDATANAME); | |
| // throw the error (won't return) | |
| luaL_error(L, lua_tostring(L, -1)); | |
| } | |
| LTLIB_EXPORTAPI int LTLIB_OPENFUNC (lua_State *L){ | |
| int result = 0; | |
| // Setup a userdata with metatable to create a close method | |
| L_setupClose(L); | |
| // call initialization code | |
| result = L_openLib(L); | |
| if (result == 0) | |
| { | |
| // Init failed, so cleanup | |
| L_openFailed(L); // will not return | |
| } | |
| // Export Lua API | |
| lua_newtable(L); | |
| #if LUA_VERSION_NUM < 502 | |
| luaL_register(L, LTLIB_GLOBALNAME, LuaExportFunctions); | |
| #else | |
| luaL_setfuncs (L, LuaExportFunctions, 0); | |
| #endif | |
| return result; | |
| }; | |