From b356ce254616430db6f63fd15c15bbd0cb7d744a Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 27 Dec 2020 10:55:35 -0700 Subject: [PATCH] Plugins; - The plugins folder can contain native plugins. - CMake will build plugins with CMakeLists in them - They can check the LOVR variable to see if they are being built inside LOVR. - They can set the LOVR_PLUGIN_TARGETS variable to a list of targets they build. - If blank, all non-imported targets added in the folder will be used. - The libraries built by their targets will be moved next to the executable or into the apk. - The library loader now tries to load libraries next to the executable or in the APK. - It is "fixed function" now, this may be improved in the future. - The lovr.filesystem C require path has been removed. - enet and cjson have been removed. Use plugins. --- .gitignore | 1 + .gitmodules | 3 - CMakeLists.txt | 98 +- deps/enet | 1 - src/api/l_filesystem.c | 117 +-- src/api/l_lovr.c | 8 - src/lib/lua-cjson/LICENSE | 20 - src/lib/lua-cjson/fpconv.c | 205 ---- src/lib/lua-cjson/fpconv.h | 22 - src/lib/lua-cjson/lua_cjson.c | 1443 --------------------------- src/lib/lua-cjson/lua_cjson.h | 5 - src/lib/lua-cjson/strbuf.c | 252 ----- src/lib/lua-cjson/strbuf.h | 154 --- src/lib/lua-enet/enet.c | 808 --------------- src/lib/lua-enet/enet.h | 5 - src/modules/filesystem/filesystem.c | 15 +- src/modules/filesystem/filesystem.h | 2 - 17 files changed, 103 insertions(+), 3056 deletions(-) delete mode 160000 deps/enet delete mode 100644 src/lib/lua-cjson/LICENSE delete mode 100644 src/lib/lua-cjson/fpconv.c delete mode 100644 src/lib/lua-cjson/fpconv.h delete mode 100644 src/lib/lua-cjson/lua_cjson.c delete mode 100644 src/lib/lua-cjson/lua_cjson.h delete mode 100644 src/lib/lua-cjson/strbuf.c delete mode 100644 src/lib/lua-cjson/strbuf.h delete mode 100644 src/lib/lua-enet/enet.c delete mode 100644 src/lib/lua-enet/enet.h diff --git a/.gitignore b/.gitignore index 3c807011..eb5bc850 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ deps/VrApi deps/pico deps/openxr deps/OpenXR-Oculus +/plugins/* diff --git a/.gitmodules b/.gitmodules index 41ec8017..be487ab9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "deps/enet"] - path = deps/enet - url = https://github.com/lsalzman/enet [submodule "deps/glfw"] path = deps/glfw url = https://github.com/glfw/glfw diff --git a/CMakeLists.txt b/CMakeLists.txt index b2866002..d8ae698b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,9 +14,6 @@ option(LOVR_ENABLE_PHYSICS "Enable the physics module" ON) option(LOVR_ENABLE_THREAD "Enable the thread module" ON) option(LOVR_ENABLE_TIMER "Enable the timer module" ON) -option(LOVR_ENABLE_ENET "Bundle with lua-enet" ON) -option(LOVR_ENABLE_JSON "Bundle with lua-cjson" ON) - option(LOVR_USE_LUAJIT "Use LuaJIT instead of Lua" ON) option(LOVR_USE_OPENVR "Enable the OpenVR backend for the headset module" ON) option(LOVR_USE_OPENXR "Enable the OpenXR backend for the headset module" OFF) @@ -27,7 +24,6 @@ option(LOVR_USE_PICO "Enable the Pico backend for the headset module" OFF) option(LOVR_USE_DESKTOP_HEADSET "Enable the keyboard/mouse backend for the headset module" ON) option(LOVR_USE_LINUX_EGL "Use the EGL graphics extension on Linux" OFF) -option(LOVR_SYSTEM_ENET "Use the system-provided enet" OFF) option(LOVR_SYSTEM_GLFW "Use the system-provided glfw" OFF) option(LOVR_SYSTEM_LUA "Use the system-provided Lua" OFF) option(LOVR_SYSTEM_ODE "Use the system-provided ODE" OFF) @@ -71,22 +67,6 @@ elseif(UNIX) endif() endif() -# enet -if(LOVR_ENABLE_ENET AND NOT EMSCRIPTEN) - if(LOVR_SYSTEM_ENET) - pkg_search_module(ENET REQUIRED enet) - include_directories(${ENET_INCLUDE_DIRS}) - set(LOVR_ENET ${ENET_LIBRARIES}) - else() - add_subdirectory(deps/enet enet) - include_directories(deps/enet/include) - set(LOVR_ENET enet) - if(WIN32) - set(LOVR_ENET ${LOVR_ENET} ws2_32 winmm) - endif() - endif() -endif() - # GLFW if(NOT (EMSCRIPTEN OR ANDROID)) if(LOVR_SYSTEM_GLFW) @@ -296,23 +276,19 @@ endif() # LÖVR -# Resources -file(GLOB LOVR_RESOURCES "src/resources/*.ttf" "src/resources/*.json" "src/resources/*.lua") -foreach(path ${LOVR_RESOURCES}) - - # Turn the absolute path into a C variable like src_resources_boot_lua - file(RELATIVE_PATH identifier ${CMAKE_CURRENT_SOURCE_DIR} ${path}) - string(MAKE_C_IDENTIFIER ${identifier} identifier) - - # Read the file and turn the bytes into comma-separated hex literals - file(READ ${path} data HEX) - string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data ${data}) - - # Generate the output filename by adding .h to the input filename - string(CONCAT output ${path} ".h") - - # Write some xxd-compatible C code! - file(WRITE ${output} "const unsigned char ${identifier}[] = {${data}};\nconst unsigned int ${identifier}_len = sizeof(${identifier});\n") +# Plugins +set(LOVR 1) +file(GLOB LOVR_PLUGINS plugins/*) +foreach(plugin ${LOVR_PLUGINS}) + if(IS_DIRECTORY ${plugin} AND EXISTS ${plugin}/CMakeLists.txt) + add_subdirectory(${plugin}) + get_directory_property(PLUGIN_TARGETS DIRECTORY ${plugin} DEFINITION LOVR_PLUGIN_TARGETS) + if(NOT PLUGIN_TARGETS) + get_directory_property(PLUGIN_TARGETS DIRECTORY ${plugin} BUILDSYSTEM_TARGETS) + endif() + set_target_properties(${PLUGIN_TARGETS} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/plugins/lib") + list(APPEND ALL_PLUGIN_TARGETS ${PLUGIN_TARGETS}) + endif() endforeach() set(LOVR_SRC @@ -344,7 +320,6 @@ set_target_properties(lovr PROPERTIES C_VISIBILITY_PRESET hidden) set_target_properties(lovr PROPERTIES C_STANDARD 99) target_include_directories(lovr PRIVATE src src/modules) target_link_libraries(lovr - ${LOVR_ENET} ${LOVR_GLFW} ${LOVR_LUA} ${LOVR_MSDF} @@ -515,19 +490,24 @@ if(LOVR_ENABLE_TIMER) target_sources(lovr PRIVATE src/modules/timer/timer.c src/api/l_timer.c) endif() -if(LOVR_ENABLE_ENET) - target_compile_definitions(lovr PRIVATE LOVR_ENABLE_ENET) - target_sources(lovr PRIVATE src/lib/lua-enet/enet.c) -endif() +# Resources +file(GLOB LOVR_RESOURCES "src/resources/*.ttf" "src/resources/*.json" "src/resources/*.lua") +foreach(path ${LOVR_RESOURCES}) -if(LOVR_ENABLE_JSON) - target_compile_definitions(lovr PRIVATE LOVR_ENABLE_JSON) - target_sources(lovr PRIVATE - src/lib/lua-cjson/fpconv.c - src/lib/lua-cjson/lua_cjson.c - src/lib/lua-cjson/strbuf.c - ) -endif() + # Turn the absolute path into a C variable like src_resources_boot_lua + file(RELATIVE_PATH identifier ${CMAKE_CURRENT_SOURCE_DIR} ${path}) + string(MAKE_C_IDENTIFIER ${identifier} identifier) + + # Read the file and turn the bytes into comma-separated hex literals + file(READ ${path} data HEX) + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data ${data}) + + # Generate the output filename by adding .h to the input filename + string(CONCAT output ${path} ".h") + + # Write some xxd-compatible C code! + file(WRITE ${output} "const unsigned char ${identifier}[] = {${data}};\nconst unsigned int ${identifier}_len = sizeof(${identifier});\n") +endforeach() # Platforms if(WIN32) @@ -558,6 +538,9 @@ if(WIN32) move_dll(${LOVR_OPENAL}) move_dll(${LOVR_OPENVR}) move_dll(${LOVR_MSDF}) + foreach(target ${ALL_PLUGIN_TARGETS}) + move_dll(${target}) + endforeach() target_compile_definitions(lovr PRIVATE LOVR_GL) elseif(APPLE) target_link_libraries(lovr objc) @@ -580,6 +563,9 @@ elseif(APPLE) move_lib(${LOVR_OPENAL}) move_lib(${LOVR_OPENVR}) move_lib(${LOVR_MSDF}) + foreach(target ${ALL_PLUGIN_TARGETS}) + move_lib(${target}) + endforeach() target_sources(lovr PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/resources/lovr.icns") set_target_properties(lovr PROPERTIES @@ -671,7 +657,8 @@ elseif(ANDROID) COMMAND ${ANDROID_TOOLS}/aapt add -f lovr.unaligned.apk - classes.dex lib/${ANDROID_ABI}/*.so + classes.dex + lib/${ANDROID_ABI}/*.so COMMAND ${ANDROID_TOOLS}/zipalign -f 4 lovr.unaligned.apk lovr.unsigned.apk COMMAND ${ANDROID_TOOLS}/apksigner sign @@ -682,6 +669,15 @@ elseif(ANDROID) COMMAND ${CMAKE_COMMAND} -E remove lovr.unaligned.apk lovr.unsigned.apk AndroidManifest.xml Activity.java classes.dex COMMAND ${CMAKE_COMMAND} -E remove_directory org ) + + # Copy plugin libraries to lib folder before packaging APK + foreach(target ${ALL_PLUGIN_TARGETS}) + add_custom_command(TARGET buildAPK PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + lib/${ANDROID_ABI}/$ + ) + endforeach() endif() elseif(UNIX) if(LOVR_USE_LINUX_EGL) diff --git a/deps/enet b/deps/enet deleted file mode 160000 index a84c120e..00000000 --- a/deps/enet +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a84c120eff13d2fa3eadb41ef7afe0f7819f4d6c diff --git a/src/api/l_filesystem.c b/src/api/l_filesystem.c index 7907dc60..cb6b94f5 100644 --- a/src/api/l_filesystem.c +++ b/src/api/l_filesystem.c @@ -169,8 +169,7 @@ static int l_lovrFilesystemGetRealDirectory(lua_State* L) { static int l_lovrFilesystemGetRequirePath(lua_State* L) { lua_pushstring(L, lovrFilesystemGetRequirePath()); - lua_pushstring(L, lovrFilesystemGetCRequirePath()); - return 2; + return 1; } static int l_lovrFilesystemGetSaveDirectory(lua_State* L) { @@ -298,8 +297,7 @@ static int l_lovrFilesystemSetIdentity(lua_State* L) { } static int l_lovrFilesystemSetRequirePath(lua_State* L) { - if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(lua_tostring(L, 1)); - if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(lua_tostring(L, 2)); + lovrFilesystemSetRequirePath(luaL_checkstring(L, 1)); return 0; } @@ -404,70 +402,59 @@ static int libLoader(lua_State* L) { const char* module = lua_tostring(L, 1); const char* hyphen = strchr(module, '-'); const char* symbol = hyphen ? hyphen + 1 : module; - const char* p = lovrFilesystemGetCRequirePath(); - char filename[1024]; - char* f = filename; - size_t n = sizeof(filename); - - lua_getglobal(L, "package"); - while (1) { - if (*p == ';' || *p == '\0') { - *f = '\0'; - - if (lovrFilesystemIsFile(filename)) { - lua_getfield(L, -1, "loadlib"); - - // Synthesize the absolute path to the library on disk - luaL_Buffer buffer; - luaL_buffinit(L, &buffer); - luaL_addstring(&buffer, lovrFilesystemGetRealDirectory(filename)); - luaL_addchar(&buffer, LOVR_PATH_SEP); - luaL_addstring(&buffer, filename); - luaL_pushresult(&buffer); - - // Synthesize the symbol to load: luaopen_ followed by the module name with dots converted - // to underscores, starting after the first hyphen (if there is one). - luaL_buffinit(L, &buffer); - luaL_addstring(&buffer, "luaopen_"); - for (const char* s = symbol; *s; s++) { - luaL_addchar(&buffer, *s == '.' ? '_' : *s); - } - luaL_pushresult(&buffer); - - // Finally call package.loadlib with the library path and symbol name - lua_call(L, 2, 1); - return 1; - } - - if (*p == '\0') { - break; - } else { - p++; - f = filename; - n = sizeof(filename); - } - } else if (*p == '?') { - for (const char* m = module; n && *m; n--, m++) { - *f++ = *m == '.' ? LOVR_PATH_SEP : *m; - } - p++; - - if (*p == '?') { - for (const char* e = extension; n && *e; n--, e++) { - *f++ = *e; - } - p++; - } - } else { - *f++ = *p++; - n--; - } - - lovrAssert(n > 0, "Tried to require a filename that was too long (%s)", module); + char path[1024]; + size_t length = lovrFilesystemGetExecutablePath(path, sizeof(path)); + if (length == 0) { + return 0; } - return 0; +#ifdef __ANDROID__ + const char* subpath = "!/lib/arm64-v8a/"; + size_t subpathLength = strlen(subpath); + char* p = path + length; + if (length + subpathLength >= sizeof(path)) { + return 0; + } + + memcpy(p, subpath, subpathLength); + length += subpathLength; + p += subpathLength; +#else + char* slash = strrchr(path, '/'); + char* p = slash ? slash + 1 : path; + length = p - path; +#endif + + for (const char* m = module; *m && length < sizeof(path); m++, length++) { + *p++ = *m == '.' ? LOVR_PATH_SEP : *m; + } + + for (const char* e = extension; *e && length < sizeof(path); e++, length++) { + *p++ = *e; + } + + if (length >= sizeof(path)) { + return 0; + } + + *p = '\0'; + + lua_getglobal(L, "package"); + lua_getfield(L, -1, "loadlib"); + lua_pushlstring(L, path, length); + + // Synthesize luaopen_ symbol + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + luaL_addstring(&buffer, "luaopen_"); + for (const char* s = symbol; *s; s++) { + luaL_addchar(&buffer, *s == '.' ? '_' : *s); + } + luaL_pushresult(&buffer); + + lua_call(L, 2, 1); + return 1; } int luaopen_lovr_filesystem(lua_State* L) { diff --git a/src/api/l_lovr.c b/src/api/l_lovr.c index 39b5c261..aaafee99 100644 --- a/src/api/l_lovr.c +++ b/src/api/l_lovr.c @@ -1,8 +1,6 @@ #include "api.h" #include "core/os.h" #include "core/util.h" -#include "lib/lua-cjson/lua_cjson.h" -#include "lib/lua-enet/enet.h" const luaL_Reg lovrModules[] = { { "lovr", luaopen_lovr }, @@ -35,12 +33,6 @@ const luaL_Reg lovrModules[] = { #endif #ifdef LOVR_ENABLE_TIMER { "lovr.timer", luaopen_lovr_timer }, -#endif -#ifdef LOVR_ENABLE_JSON - { "cjson", luaopen_cjson }, -#endif -#ifdef LOVR_ENABLE_ENET - { "enet", luaopen_enet }, #endif { NULL, NULL } }; diff --git a/src/lib/lua-cjson/LICENSE b/src/lib/lua-cjson/LICENSE deleted file mode 100644 index 747a8bff..00000000 --- a/src/lib/lua-cjson/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2010-2012 Mark Pulford - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/lib/lua-cjson/fpconv.c b/src/lib/lua-cjson/fpconv.c deleted file mode 100644 index 3ecb8f71..00000000 --- a/src/lib/lua-cjson/fpconv.c +++ /dev/null @@ -1,205 +0,0 @@ -/* fpconv - Floating point conversion routines - * - * Copyright (c) 2011-2012 Mark Pulford - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries - * with locale support will break when the decimal separator is a comma. - * - * fpconv_* will around these issues with a translation buffer if required. - */ - -#include -#include -#include -#include - -#include "fpconv.h" - -/* Lua CJSON assumes the locale is the same for all threads within a - * process and doesn't change after initialisation. - * - * This avoids the need for per thread storage or expensive checks - * for call. */ -static char locale_decimal_point = '.'; - -/* In theory multibyte decimal_points are possible, but - * Lua CJSON only supports UTF-8 and known locales only have - * single byte decimal points ([.,]). - * - * localconv() may not be thread safe (=>crash), and nl_langinfo() is - * not supported on some platforms. Use sprintf() instead - if the - * locale does change, at least Lua CJSON won't crash. */ -static void fpconv_update_locale() -{ - char buf[8]; - - snprintf(buf, sizeof(buf), "%g", 0.5); - - /* Failing this test might imply the platform has a buggy dtoa - * implementation or wide characters */ - if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) { - fprintf(stderr, "Error: wide characters found or printf() bug."); - abort(); - } - - locale_decimal_point = buf[1]; -} - -/* Check for a valid number character: [-+0-9a-yA-Y.] - * Eg: -0.6e+5, infinity, 0xF0.F0pF0 - * - * Used to find the probable end of a number. It doesn't matter if - * invalid characters are counted - strtod() will find the valid - * number if it exists. The risk is that slightly more memory might - * be allocated before a parse error occurs. */ -static inline int valid_number_character(char ch) -{ - char lower_ch; - - if ('0' <= ch && ch <= '9') - return 1; - if (ch == '-' || ch == '+' || ch == '.') - return 1; - - /* Hex digits, exponent (e), base (p), "infinity",.. */ - lower_ch = ch | 0x20; - if ('a' <= lower_ch && lower_ch <= 'y') - return 1; - - return 0; -} - -/* Calculate the size of the buffer required for a strtod locale - * conversion. */ -static int strtod_buffer_size(const char *s) -{ - const char *p = s; - - while (valid_number_character(*p)) - p++; - - return p - s; -} - -/* Similar to strtod(), but must be passed the current locale's decimal point - * character. Guaranteed to be called at the start of any valid number in a string */ -double fpconv_strtod(const char *nptr, char **endptr) -{ - char localbuf[FPCONV_G_FMT_BUFSIZE]; - char *buf, *endbuf, *dp; - int buflen; - double value; - - /* System strtod() is fine when decimal point is '.' */ - if (locale_decimal_point == '.') - return strtod(nptr, endptr); - - buflen = strtod_buffer_size(nptr); - if (!buflen) { - /* No valid characters found, standard strtod() return */ - *endptr = (char *)nptr; - return 0; - } - - /* Duplicate number into buffer */ - if (buflen >= FPCONV_G_FMT_BUFSIZE) { - /* Handle unusually large numbers */ - buf = (char *)malloc(buflen + 1); - if (!buf) { - fprintf(stderr, "Out of memory"); - abort(); - } - } else { - /* This is the common case.. */ - buf = localbuf; - } - memcpy(buf, nptr, buflen); - buf[buflen] = 0; - - /* Update decimal point character if found */ - dp = strchr(buf, '.'); - if (dp) - *dp = locale_decimal_point; - - value = strtod(buf, &endbuf); - *endptr = (char *)&nptr[endbuf - buf]; - if (buflen >= FPCONV_G_FMT_BUFSIZE) - free(buf); - - return value; -} - -/* "fmt" must point to a buffer of at least 6 characters */ -static void set_number_format(char *fmt, int precision) -{ - int d1, d2, i; - - assert(1 <= precision && precision <= 14); - - /* Create printf format (%.14g) from precision */ - d1 = precision / 10; - d2 = precision % 10; - fmt[0] = '%'; - fmt[1] = '.'; - i = 2; - if (d1) { - fmt[i++] = '0' + d1; - } - fmt[i++] = '0' + d2; - fmt[i++] = 'g'; - fmt[i] = 0; -} - -/* Assumes there is always at least 32 characters available in the target buffer */ -int fpconv_g_fmt(char *str, double num, int precision) -{ - char buf[FPCONV_G_FMT_BUFSIZE]; - char fmt[6]; - int len; - char *b; - - set_number_format(fmt, precision); - - /* Pass through when decimal point character is dot. */ - if (locale_decimal_point == '.') - return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num); - - /* snprintf() to a buffer then translate for other decimal point characters */ - len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num); - - /* Copy into target location. Translate decimal point if required */ - b = buf; - do { - *str++ = (*b == locale_decimal_point ? '.' : *b); - } while(*b++); - - return len; -} - -void fpconv_init() -{ - fpconv_update_locale(); -} - -/* vi:ai et sw=4 ts=4: - */ diff --git a/src/lib/lua-cjson/fpconv.h b/src/lib/lua-cjson/fpconv.h deleted file mode 100644 index 7b0d0ee3..00000000 --- a/src/lib/lua-cjson/fpconv.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Lua CJSON floating point conversion routines */ - -/* Buffer required to store the largest string representation of a double. - * - * Longest double printed with %.14g is 21 characters long: - * -1.7976931348623e+308 */ -# define FPCONV_G_FMT_BUFSIZE 32 - -#ifdef USE_INTERNAL_FPCONV -static inline void fpconv_init() -{ - /* Do nothing - not required */ -} -#else -extern void fpconv_init(); -#endif - -extern int fpconv_g_fmt(char*, double, int); -extern double fpconv_strtod(const char*, char**); - -/* vi:ai et sw=4 ts=4: - */ diff --git a/src/lib/lua-cjson/lua_cjson.c b/src/lib/lua-cjson/lua_cjson.c deleted file mode 100644 index 8da5c604..00000000 --- a/src/lib/lua-cjson/lua_cjson.c +++ /dev/null @@ -1,1443 +0,0 @@ -/* Lua CJSON - JSON support for Lua - * - * Copyright (c) 2010-2012 Mark Pulford - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* Caveats: - * - JSON "null" values are represented as lightuserdata since Lua - * tables cannot contain "nil". Compare with cjson.null. - * - Invalid UTF-8 characters are not detected and will be passed - * untouched. If required, UTF-8 error checking should be done - * outside this library. - * - Javascript comments are not part of the JSON spec, and are not - * currently supported. - * - * Note: Decoding is slower than encoding. Lua spends significant - * time (30%) managing tables when parsing JSON since it is - * difficult to know object/array sizes ahead of time. - */ - -#include -#include -#include -#include -#include -#include - -#include "strbuf.h" -#include "fpconv.h" - -#ifndef CJSON_MODNAME -#define CJSON_MODNAME "cjson" -#endif - -#ifndef CJSON_VERSION -#define CJSON_VERSION "2.1devel" -#endif - -#ifdef _MSC_VER -#define CJSON_EXPORT __declspec(dllexport) -#else -#define CJSON_EXPORT extern -#endif - -/* Workaround for Solaris platforms missing isinf() */ -#if !defined(isinf) && (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF)) -#define isinf(x) (!isnan(x) && isnan((x) - (x))) -#endif - -#ifdef _WIN32 -#define strncasecmp _strnicmp -#else -#include -#endif - -#define DEFAULT_SPARSE_CONVERT 0 -#define DEFAULT_SPARSE_RATIO 2 -#define DEFAULT_SPARSE_SAFE 10 -#define DEFAULT_ENCODE_MAX_DEPTH 1000 -#define DEFAULT_DECODE_MAX_DEPTH 1000 -#define DEFAULT_ENCODE_INVALID_NUMBERS 0 -#define DEFAULT_DECODE_INVALID_NUMBERS 1 -#define DEFAULT_ENCODE_KEEP_BUFFER 1 -#define DEFAULT_ENCODE_NUMBER_PRECISION 14 - -#ifdef DISABLE_INVALID_NUMBERS -#undef DEFAULT_DECODE_INVALID_NUMBERS -#define DEFAULT_DECODE_INVALID_NUMBERS 0 -#endif - -typedef enum { - T_OBJ_BEGIN, - T_OBJ_END, - T_ARR_BEGIN, - T_ARR_END, - T_STRING, - T_NUMBER, - T_BOOLEAN, - T_NULL, - T_COLON, - T_COMMA, - T_END, - T_WHITESPACE, - T_ERROR, - T_UNKNOWN -} json_token_type_t; - -static const char *json_token_type_name[] = { - "T_OBJ_BEGIN", - "T_OBJ_END", - "T_ARR_BEGIN", - "T_ARR_END", - "T_STRING", - "T_NUMBER", - "T_BOOLEAN", - "T_NULL", - "T_COLON", - "T_COMMA", - "T_END", - "T_WHITESPACE", - "T_ERROR", - "T_UNKNOWN", - NULL -}; - -typedef struct { - json_token_type_t ch2token[256]; - char escape2char[256]; /* Decoding */ - - /* encode_buf is only allocated and used when - * encode_keep_buffer is set */ - strbuf_t encode_buf; - - int encode_sparse_convert; - int encode_sparse_ratio; - int encode_sparse_safe; - int encode_max_depth; - int encode_invalid_numbers; /* 2 => Encode as "null" */ - int encode_number_precision; - int encode_keep_buffer; - - int decode_invalid_numbers; - int decode_max_depth; -} json_config_t; - -typedef struct { - const char *data; - const char *ptr; - strbuf_t *tmp; /* Temporary storage for strings */ - json_config_t *cfg; - int current_depth; -} json_parse_t; - -typedef struct { - json_token_type_t type; - int index; - union { - const char *string; - double number; - int boolean; - } value; - int string_len; -} json_token_t; - -static const char *char2escape[256] = { - "\\u0000", "\\u0001", "\\u0002", "\\u0003", - "\\u0004", "\\u0005", "\\u0006", "\\u0007", - "\\b", "\\t", "\\n", "\\u000b", - "\\f", "\\r", "\\u000e", "\\u000f", - "\\u0010", "\\u0011", "\\u0012", "\\u0013", - "\\u0014", "\\u0015", "\\u0016", "\\u0017", - "\\u0018", "\\u0019", "\\u001a", "\\u001b", - "\\u001c", "\\u001d", "\\u001e", "\\u001f", - NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -/* ===== CONFIGURATION ===== */ - -static json_config_t *json_fetch_config(lua_State *l) -{ - json_config_t *cfg; - - cfg = (json_config_t *)lua_touserdata(l, lua_upvalueindex(1)); - if (!cfg) - luaL_error(l, "BUG: Unable to fetch CJSON configuration"); - - return cfg; -} - -/* Ensure the correct number of arguments have been provided. - * Pad with nil to allow other functions to simply check arg[i] - * to find whether an argument was provided */ -static json_config_t *json_arg_init(lua_State *l, int args) -{ - luaL_argcheck(l, lua_gettop(l) <= args, args + 1, - "found too many arguments"); - - while (lua_gettop(l) < args) - lua_pushnil(l); - - return json_fetch_config(l); -} - -/* Process integer options for configuration functions */ -static int json_integer_option(lua_State *l, int optindex, int *setting, - int min, int max) -{ - char errmsg[64]; - int value; - - if (!lua_isnil(l, optindex)) { - value = luaL_checkinteger(l, optindex); - snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max); - luaL_argcheck(l, min <= value && value <= max, 1, errmsg); - *setting = value; - } - - lua_pushinteger(l, *setting); - - return 1; -} - -/* Process enumerated arguments for a configuration function */ -static int json_enum_option(lua_State *l, int optindex, int *setting, - const char **options, int bool_true) -{ - static const char *bool_options[] = { "off", "on", NULL }; - - if (!options) { - options = bool_options; - bool_true = 1; - } - - if (!lua_isnil(l, optindex)) { - if (bool_true && lua_isboolean(l, optindex)) - *setting = lua_toboolean(l, optindex) * bool_true; - else - *setting = luaL_checkoption(l, optindex, NULL, options); - } - - if (bool_true && (*setting == 0 || *setting == bool_true)) - lua_pushboolean(l, *setting); - else - lua_pushstring(l, options[*setting]); - - return 1; -} - -/* Configures handling of extremely sparse arrays: - * convert: Convert extremely sparse arrays into objects? Otherwise error. - * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio - * safe: Always use an array when the max index <= safe */ -static int json_cfg_encode_sparse_array(lua_State *l) -{ - json_config_t *cfg = json_arg_init(l, 3); - - json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1); - json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX); - json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX); - - return 3; -} - -/* Configures the maximum number of nested arrays/objects allowed when - * encoding */ -static int json_cfg_encode_max_depth(lua_State *l) -{ - json_config_t *cfg = json_arg_init(l, 1); - - return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX); -} - -/* Configures the maximum number of nested arrays/objects allowed when - * encoding */ -static int json_cfg_decode_max_depth(lua_State *l) -{ - json_config_t *cfg = json_arg_init(l, 1); - - return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX); -} - -/* Configures number precision when converting doubles to text */ -static int json_cfg_encode_number_precision(lua_State *l) -{ - json_config_t *cfg = json_arg_init(l, 1); - - return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 14); -} - -/* Configures JSON encoding buffer persistence */ -static int json_cfg_encode_keep_buffer(lua_State *l) -{ - json_config_t *cfg = json_arg_init(l, 1); - int old_value; - - old_value = cfg->encode_keep_buffer; - - json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1); - - /* Init / free the buffer if the setting has changed */ - if (old_value ^ cfg->encode_keep_buffer) { - if (cfg->encode_keep_buffer) - strbuf_init(&cfg->encode_buf, 0); - else - strbuf_free(&cfg->encode_buf); - } - - return 1; -} - -#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV) -void json_verify_invalid_number_setting(lua_State *l, int *setting) -{ - if (*setting == 1) { - *setting = 0; - luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); - } -} -#else -#define json_verify_invalid_number_setting(l, s) do { } while(0) -#endif - -static int json_cfg_encode_invalid_numbers(lua_State *l) -{ - static const char *options[] = { "off", "on", "null", NULL }; - json_config_t *cfg = json_arg_init(l, 1); - - json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1); - - json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); - - return 1; -} - -static int json_cfg_decode_invalid_numbers(lua_State *l) -{ - json_config_t *cfg = json_arg_init(l, 1); - - json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1); - - json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); - - return 1; -} - -static int json_destroy_config(lua_State *l) -{ - json_config_t *cfg; - - cfg = (json_config_t *)lua_touserdata(l, 1); - if (cfg) - strbuf_free(&cfg->encode_buf); - cfg = NULL; - - return 0; -} - -static void json_create_config(lua_State *l) -{ - json_config_t *cfg; - int i; - - cfg = (json_config_t *)lua_newuserdata(l, sizeof(*cfg)); - - /* Create GC method to clean up strbuf */ - lua_newtable(l); - lua_pushcfunction(l, json_destroy_config); - lua_setfield(l, -2, "__gc"); - lua_setmetatable(l, -2); - - cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; - cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; - cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; - cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; - cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; - cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS; - cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS; - cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; - cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; - -#if DEFAULT_ENCODE_KEEP_BUFFER > 0 - strbuf_init(&cfg->encode_buf, 0); -#endif - - /* Decoding init */ - - /* Tag all characters as an error */ - for (i = 0; i < 256; i++) - cfg->ch2token[i] = T_ERROR; - - /* Set tokens that require no further processing */ - cfg->ch2token['{'] = T_OBJ_BEGIN; - cfg->ch2token['}'] = T_OBJ_END; - cfg->ch2token['['] = T_ARR_BEGIN; - cfg->ch2token[']'] = T_ARR_END; - cfg->ch2token[','] = T_COMMA; - cfg->ch2token[':'] = T_COLON; - cfg->ch2token['\0'] = T_END; - cfg->ch2token[' '] = T_WHITESPACE; - cfg->ch2token['\t'] = T_WHITESPACE; - cfg->ch2token['\n'] = T_WHITESPACE; - cfg->ch2token['\r'] = T_WHITESPACE; - - /* Update characters that require further processing */ - cfg->ch2token['f'] = T_UNKNOWN; /* false? */ - cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */ - cfg->ch2token['I'] = T_UNKNOWN; - cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */ - cfg->ch2token['N'] = T_UNKNOWN; - cfg->ch2token['t'] = T_UNKNOWN; /* true? */ - cfg->ch2token['"'] = T_UNKNOWN; /* string? */ - cfg->ch2token['+'] = T_UNKNOWN; /* number? */ - cfg->ch2token['-'] = T_UNKNOWN; - for (i = 0; i < 10; i++) - cfg->ch2token['0' + i] = T_UNKNOWN; - - /* Lookup table for parsing escape characters */ - for (i = 0; i < 256; i++) - cfg->escape2char[i] = 0; /* String error */ - cfg->escape2char['"'] = '"'; - cfg->escape2char['\\'] = '\\'; - cfg->escape2char['/'] = '/'; - cfg->escape2char['b'] = '\b'; - cfg->escape2char['t'] = '\t'; - cfg->escape2char['n'] = '\n'; - cfg->escape2char['f'] = '\f'; - cfg->escape2char['r'] = '\r'; - cfg->escape2char['u'] = 'u'; /* Unicode parsing required */ -} - -/* ===== ENCODING ===== */ - -static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex, - const char *reason) -{ - if (!cfg->encode_keep_buffer) - strbuf_free(json); - luaL_error(l, "Cannot serialise %s: %s", - lua_typename(l, lua_type(l, lindex)), reason); -} - -/* json_append_string args: - * - lua_State - * - JSON strbuf - * - String (Lua stack index) - * - * Returns nothing. Doesn't remove string from Lua stack */ -static void json_append_string(lua_State *l, strbuf_t *json, int lindex) -{ - const char *escstr; - const char *str; - size_t len; - size_t i; - - str = lua_tolstring(l, lindex, &len); - - /* Worst case is len * 6 (all unicode escapes). - * This buffer is reused constantly for small strings - * If there are any excess pages, they won't be hit anyway. - * This gains ~5% speedup. */ - strbuf_ensure_empty_length(json, (int) (len * 6 + 2)); - - strbuf_append_char_unsafe(json, '\"'); - for (i = 0; i < len; i++) { - escstr = char2escape[(unsigned char)str[i]]; - if (escstr) - strbuf_append_string(json, escstr); - else - strbuf_append_char_unsafe(json, str[i]); - } - strbuf_append_char_unsafe(json, '\"'); -} - -/* Find the size of the array on the top of the Lua stack - * -1 object (not a pure array) - * >=0 elements in array - */ -static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json) -{ - double k; - int max; - int items; - - max = 0; - items = 0; - - lua_pushnil(l); - /* table, startkey */ - while (lua_next(l, -2) != 0) { - /* table, key, value */ - if (lua_type(l, -2) == LUA_TNUMBER && - (k = lua_tonumber(l, -2))) { - /* Integer >= 1 ? */ - if (floor(k) == k && k >= 1) { - if (k > max) - max = k; - items++; - lua_pop(l, 1); - continue; - } - } - - /* Must not be an array (non integer key) */ - lua_pop(l, 2); - return -1; - } - - /* Encode excessively sparse arrays as objects (if enabled) */ - if (cfg->encode_sparse_ratio > 0 && - max > items * cfg->encode_sparse_ratio && - max > cfg->encode_sparse_safe) { - if (!cfg->encode_sparse_convert) - json_encode_exception(l, cfg, json, -1, "excessively sparse array"); - - return -1; - } - - return max; -} - -static void json_check_encode_depth(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json) -{ - /* Ensure there are enough slots free to traverse a table (key, - * value) and push a string for a potential error message. - * - * Unlike "decode", the key and value are still on the stack when - * lua_checkstack() is called. Hence an extra slot for luaL_error() - * below is required just in case the next check to lua_checkstack() - * fails. - * - * While this won't cause a crash due to the EXTRA_STACK reserve - * slots, it would still be an improper use of the API. */ - if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3)) - return; - - if (!cfg->encode_keep_buffer) - strbuf_free(json); - - luaL_error(l, "Cannot serialise, excessive nesting (%d)", - current_depth); -} - -static void json_append_data(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json); - -/* json_append_array args: - * - lua_State - * - JSON strbuf - * - Size of passwd Lua array (top of stack) */ -static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth, - strbuf_t *json, int array_length) -{ - int comma, i; - - strbuf_append_char(json, '['); - - comma = 0; - for (i = 1; i <= array_length; i++) { - if (comma) - strbuf_append_char(json, ','); - else - comma = 1; - - lua_rawgeti(l, -1, i); - json_append_data(l, cfg, current_depth, json); - lua_pop(l, 1); - } - - strbuf_append_char(json, ']'); -} - -static void json_append_number(lua_State *l, json_config_t *cfg, - strbuf_t *json, int lindex) -{ - double num = lua_tonumber(l, lindex); - int len; - - if (cfg->encode_invalid_numbers == 0) { - /* Prevent encoding invalid numbers */ - if (isinf(num) || isnan(num)) - json_encode_exception(l, cfg, json, lindex, - "must not be NaN or Infinity"); - } else if (cfg->encode_invalid_numbers == 1) { - /* Encode NaN/Infinity separately to ensure Javascript compatible - * values are used. */ - if (isnan(num)) { - strbuf_append_mem(json, "NaN", 3); - return; - } - if (isinf(num)) { - if (num < 0) - strbuf_append_mem(json, "-Infinity", 9); - else - strbuf_append_mem(json, "Infinity", 8); - return; - } - } else { - /* Encode invalid numbers as "null" */ - if (isinf(num) || isnan(num)) { - strbuf_append_mem(json, "null", 4); - return; - } - } - - strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); - len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision); - strbuf_extend_length(json, len); -} - -static void json_append_object(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json) -{ - int comma, keytype; - - /* Object */ - strbuf_append_char(json, '{'); - - lua_pushnil(l); - /* table, startkey */ - comma = 0; - while (lua_next(l, -2) != 0) { - if (comma) - strbuf_append_char(json, ','); - else - comma = 1; - - /* table, key, value */ - keytype = lua_type(l, -2); - if (keytype == LUA_TNUMBER) { - strbuf_append_char(json, '"'); - json_append_number(l, cfg, json, -2); - strbuf_append_mem(json, "\":", 2); - } else if (keytype == LUA_TSTRING) { - json_append_string(l, json, -2); - strbuf_append_char(json, ':'); - } else { - json_encode_exception(l, cfg, json, -2, - "table key must be a number or string"); - /* never returns */ - } - - /* table, key, value */ - json_append_data(l, cfg, current_depth, json); - lua_pop(l, 1); - /* table, key */ - } - - strbuf_append_char(json, '}'); -} - -/* Serialise Lua data into JSON string. */ -static void json_append_data(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json) -{ - int len; - - switch (lua_type(l, -1)) { - case LUA_TSTRING: - json_append_string(l, json, -1); - break; - case LUA_TNUMBER: - json_append_number(l, cfg, json, -1); - break; - case LUA_TBOOLEAN: - if (lua_toboolean(l, -1)) - strbuf_append_mem(json, "true", 4); - else - strbuf_append_mem(json, "false", 5); - break; - case LUA_TTABLE: - current_depth++; - json_check_encode_depth(l, cfg, current_depth, json); - len = lua_array_length(l, cfg, json); - if (len > 0) - json_append_array(l, cfg, current_depth, json, len); - else - json_append_object(l, cfg, current_depth, json); - break; - case LUA_TNIL: - strbuf_append_mem(json, "null", 4); - break; - case LUA_TLIGHTUSERDATA: - if (lua_touserdata(l, -1) == NULL) { - strbuf_append_mem(json, "null", 4); - break; - } - default: - /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, - * and LUA_TLIGHTUSERDATA) cannot be serialised */ - json_encode_exception(l, cfg, json, -1, "type not supported"); - /* never returns */ - } -} - -static int json_encode(lua_State *l) -{ - json_config_t *cfg = json_fetch_config(l); - strbuf_t local_encode_buf; - strbuf_t *encode_buf; - char *json; - int len; - - luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); - - if (!cfg->encode_keep_buffer) { - /* Use private buffer */ - encode_buf = &local_encode_buf; - strbuf_init(encode_buf, 0); - } else { - /* Reuse existing buffer */ - encode_buf = &cfg->encode_buf; - strbuf_reset(encode_buf); - } - - json_append_data(l, cfg, 0, encode_buf); - json = strbuf_string(encode_buf, &len); - - lua_pushlstring(l, json, len); - - if (!cfg->encode_keep_buffer) - strbuf_free(encode_buf); - - return 1; -} - -/* ===== DECODING ===== */ - -static void json_process_value(lua_State *l, json_parse_t *json, - json_token_t *token); - -static int hexdigit2int(char hex) -{ - if ('0' <= hex && hex <= '9') - return hex - '0'; - - /* Force lowercase */ - hex |= 0x20; - if ('a' <= hex && hex <= 'f') - return 10 + hex - 'a'; - - return -1; -} - -static int decode_hex4(const char *hex) -{ - int digit[4]; - int i; - - /* Convert ASCII hex digit to numeric digit - * Note: this returns an error for invalid hex digits, including - * NULL */ - for (i = 0; i < 4; i++) { - digit[i] = hexdigit2int(hex[i]); - if (digit[i] < 0) { - return -1; - } - } - - return (digit[0] << 12) + - (digit[1] << 8) + - (digit[2] << 4) + - digit[3]; -} - -/* Converts a Unicode codepoint to UTF-8. - * Returns UTF-8 string length, and up to 4 bytes in *utf8 */ -static int codepoint_to_utf8(char *utf8, int codepoint) -{ - /* 0xxxxxxx */ - if (codepoint <= 0x7F) { - utf8[0] = codepoint; - return 1; - } - - /* 110xxxxx 10xxxxxx */ - if (codepoint <= 0x7FF) { - utf8[0] = (codepoint >> 6) | 0xC0; - utf8[1] = (codepoint & 0x3F) | 0x80; - return 2; - } - - /* 1110xxxx 10xxxxxx 10xxxxxx */ - if (codepoint <= 0xFFFF) { - utf8[0] = (codepoint >> 12) | 0xE0; - utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80; - utf8[2] = (codepoint & 0x3F) | 0x80; - return 3; - } - - /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint <= 0x1FFFFF) { - utf8[0] = (codepoint >> 18) | 0xF0; - utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80; - utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80; - utf8[3] = (codepoint & 0x3F) | 0x80; - return 4; - } - - return 0; -} - - -/* Called when index pointing to beginning of UTF-16 code escape: \uXXXX - * \u is guaranteed to exist, but the remaining hex characters may be - * missing. - * Translate to UTF-8 and append to temporary token string. - * Must advance index to the next character to be processed. - * Returns: 0 success - * -1 error - */ -static int json_append_unicode_escape(json_parse_t *json) -{ - char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */ - int codepoint; - int surrogate_low; - int len; - int escape_len = 6; - - /* Fetch UTF-16 code unit */ - codepoint = decode_hex4(json->ptr + 2); - if (codepoint < 0) - return -1; - - /* UTF-16 surrogate pairs take the following 2 byte form: - * 11011 x yyyyyyyyyy - * When x = 0: y is the high 10 bits of the codepoint - * x = 1: y is the low 10 bits of the codepoint - * - * Check for a surrogate pair (high or low) */ - if ((codepoint & 0xF800) == 0xD800) { - /* Error if the 1st surrogate is not high */ - if (codepoint & 0x400) - return -1; - - /* Ensure the next code is a unicode escape */ - if (*(json->ptr + escape_len) != '\\' || - *(json->ptr + escape_len + 1) != 'u') { - return -1; - } - - /* Fetch the next codepoint */ - surrogate_low = decode_hex4(json->ptr + 2 + escape_len); - if (surrogate_low < 0) - return -1; - - /* Error if the 2nd code is not a low surrogate */ - if ((surrogate_low & 0xFC00) != 0xDC00) - return -1; - - /* Calculate Unicode codepoint */ - codepoint = (codepoint & 0x3FF) << 10; - surrogate_low &= 0x3FF; - codepoint = (codepoint | surrogate_low) + 0x10000; - escape_len = 12; - } - - /* Convert codepoint to UTF-8 */ - len = codepoint_to_utf8(utf8, codepoint); - if (!len) - return -1; - - /* Append bytes and advance parse index */ - strbuf_append_mem_unsafe(json->tmp, utf8, len); - json->ptr += escape_len; - - return 0; -} - -static void json_set_token_error(json_token_t *token, json_parse_t *json, - const char *errtype) -{ - token->type = T_ERROR; - token->index = json->ptr - json->data; - token->value.string = errtype; -} - -static void json_next_string_token(json_parse_t *json, json_token_t *token) -{ - char *escape2char = json->cfg->escape2char; - char ch; - - /* Caller must ensure a string is next */ - assert(*json->ptr == '"'); - - /* Skip " */ - json->ptr++; - - /* json->tmp is the temporary strbuf used to accumulate the - * decoded string value. - * json->tmp is sized to handle JSON containing only a string value. - */ - strbuf_reset(json->tmp); - - while ((ch = *json->ptr) != '"') { - if (!ch) { - /* Premature end of the string */ - json_set_token_error(token, json, "unexpected end of string"); - return; - } - - /* Handle escapes */ - if (ch == '\\') { - /* Fetch escape character */ - ch = *(json->ptr + 1); - - /* Translate escape code and append to tmp string */ - ch = escape2char[(unsigned char)ch]; - if (ch == 'u') { - if (json_append_unicode_escape(json) == 0) - continue; - - json_set_token_error(token, json, - "invalid unicode escape code"); - return; - } - if (!ch) { - json_set_token_error(token, json, "invalid escape code"); - return; - } - - /* Skip '\' */ - json->ptr++; - } - /* Append normal character or translated single character - * Unicode escapes are handled above */ - strbuf_append_char_unsafe(json->tmp, ch); - json->ptr++; - } - json->ptr++; /* Eat final quote (") */ - - strbuf_ensure_null(json->tmp); - - token->type = T_STRING; - token->value.string = strbuf_string(json->tmp, &token->string_len); -} - -/* JSON numbers should take the following form: - * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)? - * - * json_next_number_token() uses strtod() which allows other forms: - * - numbers starting with '+' - * - NaN, -NaN, infinity, -infinity - * - hexadecimal numbers - * - numbers with leading zeros - * - * json_is_invalid_number() detects "numbers" which may pass strtod()'s - * error checking, but should not be allowed with strict JSON. - * - * json_is_invalid_number() may pass numbers which cause strtod() - * to generate an error. - */ -static int json_is_invalid_number(json_parse_t *json) -{ - const char *p = json->ptr; - - /* Reject numbers starting with + */ - if (*p == '+') - return 1; - - /* Skip minus sign if it exists */ - if (*p == '-') - p++; - - /* Reject numbers starting with 0x, or leading zeros */ - if (*p == '0') { - int ch2 = *(p + 1); - - if ((ch2 | 0x20) == 'x' || /* Hex */ - ('0' <= ch2 && ch2 <= '9')) /* Leading zero */ - return 1; - - return 0; - } else if (*p <= '9') { - return 0; /* Ordinary number */ - } - - /* Reject inf/nan */ - if (!strncasecmp(p, "inf", 3)) - return 1; - if (!strncasecmp(p, "nan", 3)) - return 1; - - /* Pass all other numbers which may still be invalid, but - * strtod() will catch them. */ - return 0; -} - -static void json_next_number_token(json_parse_t *json, json_token_t *token) -{ - char *endptr; - - token->type = T_NUMBER; - token->value.number = fpconv_strtod(json->ptr, &endptr); - if (json->ptr == endptr) - json_set_token_error(token, json, "invalid number"); - else - json->ptr = endptr; /* Skip the processed number */ - - return; -} - -/* Fills in the token struct. - * T_STRING will return a pointer to the json_parse_t temporary string - * T_ERROR will leave the json->ptr pointer at the error. - */ -static void json_next_token(json_parse_t *json, json_token_t *token) -{ - const json_token_type_t *ch2token = json->cfg->ch2token; - int ch; - - /* Eat whitespace. */ - while (1) { - ch = (unsigned char)*(json->ptr); - token->type = ch2token[ch]; - if (token->type != T_WHITESPACE) - break; - json->ptr++; - } - - /* Store location of new token. Required when throwing errors - * for unexpected tokens (syntax errors). */ - token->index = json->ptr - json->data; - - /* Don't advance the pointer for an error or the end */ - if (token->type == T_ERROR) { - json_set_token_error(token, json, "invalid token"); - return; - } - - if (token->type == T_END) { - return; - } - - /* Found a known single character token, advance index and return */ - if (token->type != T_UNKNOWN) { - json->ptr++; - return; - } - - /* Process characters which triggered T_UNKNOWN - * - * Must use strncmp() to match the front of the JSON string. - * JSON identifier must be lowercase. - * When strict_numbers if disabled, either case is allowed for - * Infinity/NaN (since we are no longer following the spec..) */ - if (ch == '"') { - json_next_string_token(json, token); - return; - } else if (ch == '-' || ('0' <= ch && ch <= '9')) { - if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) { - json_set_token_error(token, json, "invalid number"); - return; - } - json_next_number_token(json, token); - return; - } else if (!strncmp(json->ptr, "true", 4)) { - token->type = T_BOOLEAN; - token->value.boolean = 1; - json->ptr += 4; - return; - } else if (!strncmp(json->ptr, "false", 5)) { - token->type = T_BOOLEAN; - token->value.boolean = 0; - json->ptr += 5; - return; - } else if (!strncmp(json->ptr, "null", 4)) { - token->type = T_NULL; - json->ptr += 4; - return; - } else if (json->cfg->decode_invalid_numbers && - json_is_invalid_number(json)) { - /* When decode_invalid_numbers is enabled, only attempt to process - * numbers we know are invalid JSON (Inf, NaN, hex) - * This is required to generate an appropriate token error, - * otherwise all bad tokens will register as "invalid number" - */ - json_next_number_token(json, token); - return; - } - - /* Token starts with t/f/n but isn't recognised above. */ - json_set_token_error(token, json, "invalid token"); -} - -/* This function does not return. - * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED. - * The only supported exception is the temporary parser string - * json->tmp struct. - * json and token should exist on the stack somewhere. - * luaL_error() will long_jmp and release the stack */ -static void json_throw_parse_error(lua_State *l, json_parse_t *json, - const char *exp, json_token_t *token) -{ - const char *found; - - strbuf_free(json->tmp); - - if (token->type == T_ERROR) - found = token->value.string; - else - found = json_token_type_name[token->type]; - - /* Note: token->index is 0 based, display starting from 1 */ - luaL_error(l, "Expected %s but found %s at character %d", - exp, found, token->index + 1); -} - -static inline void json_decode_ascend(json_parse_t *json) -{ - json->current_depth--; -} - -static void json_decode_descend(lua_State *l, json_parse_t *json, int slots) -{ - json->current_depth++; - - if (json->current_depth <= json->cfg->decode_max_depth && - lua_checkstack(l, slots)) { - return; - } - - strbuf_free(json->tmp); - luaL_error(l, "Found too many nested data structures (%d) at character %d", - json->current_depth, json->ptr - json->data); -} - -static void json_parse_object_context(lua_State *l, json_parse_t *json) -{ - json_token_t token; - - /* 3 slots required: - * .., table, key, value */ - json_decode_descend(l, json, 3); - - lua_newtable(l); - - json_next_token(json, &token); - - /* Handle empty objects */ - if (token.type == T_OBJ_END) { - json_decode_ascend(json); - return; - } - - while (1) { - if (token.type != T_STRING) - json_throw_parse_error(l, json, "object key string", &token); - - /* Push key */ - lua_pushlstring(l, token.value.string, token.string_len); - - json_next_token(json, &token); - if (token.type != T_COLON) - json_throw_parse_error(l, json, "colon", &token); - - /* Fetch value */ - json_next_token(json, &token); - json_process_value(l, json, &token); - - /* Set key = value */ - lua_rawset(l, -3); - - json_next_token(json, &token); - - if (token.type == T_OBJ_END) { - json_decode_ascend(json); - return; - } - - if (token.type != T_COMMA) - json_throw_parse_error(l, json, "comma or object end", &token); - - json_next_token(json, &token); - } -} - -/* Handle the array context */ -static void json_parse_array_context(lua_State *l, json_parse_t *json) -{ - json_token_t token; - int i; - - /* 2 slots required: - * .., table, value */ - json_decode_descend(l, json, 2); - - lua_newtable(l); - - json_next_token(json, &token); - - /* Handle empty arrays */ - if (token.type == T_ARR_END) { - json_decode_ascend(json); - return; - } - - for (i = 1; ; i++) { - json_process_value(l, json, &token); - lua_rawseti(l, -2, i); /* arr[i] = value */ - - json_next_token(json, &token); - - if (token.type == T_ARR_END) { - json_decode_ascend(json); - return; - } - - if (token.type != T_COMMA) - json_throw_parse_error(l, json, "comma or array end", &token); - - json_next_token(json, &token); - } -} - -/* Handle the "value" context */ -static void json_process_value(lua_State *l, json_parse_t *json, - json_token_t *token) -{ - switch (token->type) { - case T_STRING: - lua_pushlstring(l, token->value.string, token->string_len); - break;; - case T_NUMBER: - lua_pushnumber(l, token->value.number); - break;; - case T_BOOLEAN: - lua_pushboolean(l, token->value.boolean); - break;; - case T_OBJ_BEGIN: - json_parse_object_context(l, json); - break;; - case T_ARR_BEGIN: - json_parse_array_context(l, json); - break;; - case T_NULL: - /* In Lua, setting "t[k] = nil" will delete k from the table. - * Hence a NULL pointer lightuserdata object is used instead */ - lua_pushlightuserdata(l, NULL); - break;; - default: - json_throw_parse_error(l, json, "value", token); - } -} - -static int json_decode(lua_State *l) -{ - json_parse_t json; - json_token_t token; - size_t json_len; - - luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); - - json.cfg = json_fetch_config(l); - json.data = luaL_checklstring(l, 1, &json_len); - json.current_depth = 0; - json.ptr = json.data; - - /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3) - * - * CJSON can support any simple data type, hence only the first - * character is guaranteed to be ASCII (at worst: '"'). This is - * still enough to detect whether the wrong encoding is in use. */ - if (json_len >= 2 && (!json.data[0] || !json.data[1])) - luaL_error(l, "JSON parser does not support UTF-16 or UTF-32"); - - /* Ensure the temporary buffer can hold the entire string. - * This means we no longer need to do length checks since the decoded - * string must be smaller than the entire json string */ - json.tmp = strbuf_new((int) json_len); - - json_next_token(&json, &token); - json_process_value(l, &json, &token); - - /* Ensure there is no more input left */ - json_next_token(&json, &token); - - if (token.type != T_END) - json_throw_parse_error(l, &json, "the end", &token); - - strbuf_free(json.tmp); - - return 1; -} - -/* ===== INITIALISATION ===== */ - -/* Compatibility for Lua 5.1. - * - * luaL_setfuncs() is used to create a module table where the functions have - * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */ -static void json_luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup) -{ - int i; - - luaL_checkstack(l, nup, "too many upvalues"); - for (; reg->name != NULL; reg++) { /* fill the table with given functions */ - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(l, -nup); - lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ - lua_setfield(l, -(nup + 2), reg->name); - } - lua_pop(l, nup); /* remove upvalues */ -} - -/* Call target function in protected mode with all supplied args. - * Assumes target function only returns a single non-nil value. - * Convert and return thrown errors as: nil, "error message" */ -static int json_protect_conversion(lua_State *l) -{ - int err; - - /* Deliberately throw an error for invalid arguments */ - luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); - - /* pcall() the function stored as upvalue(1) */ - lua_pushvalue(l, lua_upvalueindex(1)); - lua_insert(l, 1); - err = lua_pcall(l, 1, 1, 0); - if (!err) - return 1; - - if (err == LUA_ERRRUN) { - lua_pushnil(l); - lua_insert(l, -2); - return 2; - } - - /* Since we are not using a custom error handler, the only remaining - * errors are memory related */ - return luaL_error(l, "Memory allocation error in CJSON protected call"); -} - -/* Return cjson module table */ -static int lua_cjson_new(lua_State *l) -{ - luaL_Reg reg[] = { - { "encode", json_encode }, - { "decode", json_decode }, - { "encode_sparse_array", json_cfg_encode_sparse_array }, - { "encode_max_depth", json_cfg_encode_max_depth }, - { "decode_max_depth", json_cfg_decode_max_depth }, - { "encode_number_precision", json_cfg_encode_number_precision }, - { "encode_keep_buffer", json_cfg_encode_keep_buffer }, - { "encode_invalid_numbers", json_cfg_encode_invalid_numbers }, - { "decode_invalid_numbers", json_cfg_decode_invalid_numbers }, - { "new", lua_cjson_new }, - { NULL, NULL } - }; - - /* Initialise number conversions */ - fpconv_init(); - - /* cjson module table */ - lua_newtable(l); - - /* Register functions with config data as upvalue */ - json_create_config(l); - json_luaL_setfuncs(l, reg, 1); - - /* Set cjson.null */ - lua_pushlightuserdata(l, NULL); - lua_setfield(l, -2, "null"); - - /* Set module name / version fields */ - lua_pushliteral(l, CJSON_MODNAME); - lua_setfield(l, -2, "_NAME"); - lua_pushliteral(l, CJSON_VERSION); - lua_setfield(l, -2, "_VERSION"); - - return 1; -} - -/* Return cjson.safe module table */ -static int lua_cjson_safe_new(lua_State *l) -{ - const char *func[] = { "decode", "encode", NULL }; - int i; - - lua_cjson_new(l); - - /* Fix new() method */ - lua_pushcfunction(l, lua_cjson_safe_new); - lua_setfield(l, -2, "new"); - - for (i = 0; func[i]; i++) { - lua_getfield(l, -1, func[i]); - lua_pushcclosure(l, json_protect_conversion, 1); - lua_setfield(l, -2, func[i]); - } - - return 1; -} - -CJSON_EXPORT int luaopen_cjson(lua_State *l) -{ - lua_cjson_new(l); - -#ifdef ENABLE_CJSON_GLOBAL - /* Register a global "cjson" table. */ - lua_pushvalue(l, -1); - lua_setglobal(l, CJSON_MODNAME); -#endif - - /* Return cjson table */ - return 1; -} - -CJSON_EXPORT int luaopen_cjson_safe(lua_State *l) -{ - lua_cjson_safe_new(l); - - /* Return cjson.safe table */ - return 1; -} - -/* vi:ai et sw=4 ts=4: - */ diff --git a/src/lib/lua-cjson/lua_cjson.h b/src/lib/lua-cjson/lua_cjson.h deleted file mode 100644 index 9be5d223..00000000 --- a/src/lib/lua-cjson/lua_cjson.h +++ /dev/null @@ -1,5 +0,0 @@ -#include "api/api.h" - -#pragma once - -int luaopen_cjson(lua_State *l); diff --git a/src/lib/lua-cjson/strbuf.c b/src/lib/lua-cjson/strbuf.c deleted file mode 100644 index 5b28e3f0..00000000 --- a/src/lib/lua-cjson/strbuf.c +++ /dev/null @@ -1,252 +0,0 @@ -/* strbuf - String buffer routines - * - * Copyright (c) 2010-2012 Mark Pulford - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -#include "strbuf.h" - -static void die(const char *fmt, ...) -{ - va_list arg; - - va_start(arg, fmt); - vfprintf(stderr, fmt, arg); - va_end(arg); - fprintf(stderr, "\n"); - - exit(-1); -} - -void strbuf_init(strbuf_t *s, int len) -{ - int size; - - if (len <= 0) - size = STRBUF_DEFAULT_SIZE; - else - size = len + 1; /* \0 terminator */ - - s->buf = NULL; - s->size = size; - s->length = 0; - s->increment = STRBUF_DEFAULT_INCREMENT; - s->dynamic = 0; - s->reallocs = 0; - s->debug = 0; - - s->buf = (char *)malloc(size); - if (!s->buf) - die("Out of memory"); - - strbuf_ensure_null(s); -} - -strbuf_t *strbuf_new(int len) -{ - strbuf_t *s; - - s = (strbuf_t*)malloc(sizeof(strbuf_t)); - if (!s) - die("Out of memory"); - - strbuf_init(s, len); - - /* Dynamic strbuf allocation / deallocation */ - s->dynamic = 1; - - return s; -} - -void strbuf_set_increment(strbuf_t *s, int increment) -{ - /* Increment > 0: Linear buffer growth rate - * Increment < -1: Exponential buffer growth rate */ - if (increment == 0 || increment == -1) - die("BUG: Invalid string increment"); - - s->increment = increment; -} - -static inline void debug_stats(strbuf_t *s) -{ - if (s->debug) { - fprintf(stderr, "strbuf(%p) reallocs: %d, length: %d, size: %d\n", - (void*) s, s->reallocs, s->length, s->size); - } -} - -/* If strbuf_t has not been dynamically allocated, strbuf_free() can - * be called any number of times strbuf_init() */ -void strbuf_free(strbuf_t *s) -{ - debug_stats(s); - - if (s->buf) { - free(s->buf); - s->buf = NULL; - } - if (s->dynamic) - free(s); -} - -char *strbuf_free_to_string(strbuf_t *s, int *len) -{ - char *buf; - - debug_stats(s); - - strbuf_ensure_null(s); - - buf = s->buf; - if (len) - *len = s->length; - - if (s->dynamic) - free(s); - - return buf; -} - -static int calculate_new_size(strbuf_t *s, int len) -{ - int reqsize, newsize; - - if (len <= 0) - die("BUG: Invalid strbuf length requested"); - - /* Ensure there is room for optional NULL termination */ - reqsize = len + 1; - - /* If the user has requested to shrink the buffer, do it exactly */ - if (s->size > reqsize) - return reqsize; - - newsize = s->size; - if (s->increment < 0) { - /* Exponential sizing */ - while (newsize < reqsize) - newsize *= -s->increment; - } else { - /* Linear sizing */ - newsize = ((newsize + s->increment - 1) / s->increment) * s->increment; - } - - return newsize; -} - - -/* Ensure strbuf can handle a string length bytes long (ignoring NULL - * optional termination). */ -void strbuf_resize(strbuf_t *s, int len) -{ - int newsize; - - newsize = calculate_new_size(s, len); - - if (s->debug > 1) { - fprintf(stderr, "strbuf(%p) resize: %d => %d\n", - (void*) s, s->size, newsize); - } - - s->size = newsize; - s->buf = (char *)realloc(s->buf, s->size); - if (!s->buf) - die("Out of memory"); - s->reallocs++; -} - -void strbuf_append_string(strbuf_t *s, const char *str) -{ - int space, i; - - space = strbuf_empty_length(s); - - for (i = 0; str[i]; i++) { - if (space < 1) { - strbuf_resize(s, s->length + 1); - space = strbuf_empty_length(s); - } - - s->buf[s->length] = str[i]; - s->length++; - space--; - } -} - -/* strbuf_append_fmt() should only be used when an upper bound - * is known for the output string. */ -void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...) -{ - va_list arg; - int fmt_len; - - strbuf_ensure_empty_length(s, len); - - va_start(arg, fmt); - fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg); - va_end(arg); - - if (fmt_len < 0) - die("BUG: Unable to convert number"); /* This should never happen.. */ - - s->length += fmt_len; -} - -/* strbuf_append_fmt_retry() can be used when the there is no known - * upper bound for the output string. */ -void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...) -{ - va_list arg; - int fmt_len; - int empty_len; - int t; - - /* If the first attempt to append fails, resize the buffer appropriately - * and try again */ - for (t = 0; ; t++) { - va_start(arg, fmt); - /* Append the new formatted string */ - /* fmt_len is the length of the string required, excluding the - * trailing NULL */ - empty_len = strbuf_empty_length(s); - /* Add 1 since there is also space to store the terminating NULL. */ - fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg); - va_end(arg); - - if (fmt_len <= empty_len) - break; /* SUCCESS */ - if (t > 0) - die("BUG: length of formatted string changed"); - - strbuf_resize(s, s->length + fmt_len); - } - - s->length += fmt_len; -} - -/* vi:ai et sw=4 ts=4: - */ diff --git a/src/lib/lua-cjson/strbuf.h b/src/lib/lua-cjson/strbuf.h deleted file mode 100644 index d861108c..00000000 --- a/src/lib/lua-cjson/strbuf.h +++ /dev/null @@ -1,154 +0,0 @@ -/* strbuf - String buffer routines - * - * Copyright (c) 2010-2012 Mark Pulford - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -/* Size: Total bytes allocated to *buf - * Length: String length, excluding optional NULL terminator. - * Increment: Allocation increments when resizing the string buffer. - * Dynamic: True if created via strbuf_new() - */ - -typedef struct { - char *buf; - int size; - int length; - int increment; - int dynamic; - int reallocs; - int debug; -} strbuf_t; - -#ifndef STRBUF_DEFAULT_SIZE -#define STRBUF_DEFAULT_SIZE 1023 -#endif -#ifndef STRBUF_DEFAULT_INCREMENT -#define STRBUF_DEFAULT_INCREMENT -2 -#endif - -/* Initialise */ -extern strbuf_t *strbuf_new(int len); -extern void strbuf_init(strbuf_t *s, int len); -extern void strbuf_set_increment(strbuf_t *s, int increment); - -/* Release */ -extern void strbuf_free(strbuf_t *s); -extern char *strbuf_free_to_string(strbuf_t *s, int *len); - -/* Management */ -extern void strbuf_resize(strbuf_t *s, int len); -static int strbuf_empty_length(strbuf_t *s); -static int strbuf_length(strbuf_t *s); -static char *strbuf_string(strbuf_t *s, int *len); -static void strbuf_ensure_empty_length(strbuf_t *s, int len); -static char *strbuf_empty_ptr(strbuf_t *s); -static void strbuf_extend_length(strbuf_t *s, int len); - -/* Update */ -extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...); -extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...); -static void strbuf_append_mem(strbuf_t *s, const char *c, int len); -extern void strbuf_append_string(strbuf_t *s, const char *str); -static void strbuf_append_char(strbuf_t *s, const char c); -static void strbuf_ensure_null(strbuf_t *s); - -/* Reset string for before use */ -static inline void strbuf_reset(strbuf_t *s) -{ - s->length = 0; -} - -static inline int strbuf_allocated(strbuf_t *s) -{ - return s->buf != NULL; -} - -/* Return bytes remaining in the string buffer - * Ensure there is space for a NULL terminator. */ -static inline int strbuf_empty_length(strbuf_t *s) -{ - return s->size - s->length - 1; -} - -static inline void strbuf_ensure_empty_length(strbuf_t *s, int len) -{ - if (len > strbuf_empty_length(s)) - strbuf_resize(s, s->length + len); -} - -static inline char *strbuf_empty_ptr(strbuf_t *s) -{ - return s->buf + s->length; -} - -static inline void strbuf_extend_length(strbuf_t *s, int len) -{ - s->length += len; -} - -static inline int strbuf_length(strbuf_t *s) -{ - return s->length; -} - -static inline void strbuf_append_char(strbuf_t *s, const char c) -{ - strbuf_ensure_empty_length(s, 1); - s->buf[s->length++] = c; -} - -static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c) -{ - s->buf[s->length++] = c; -} - -static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len) -{ - strbuf_ensure_empty_length(s, len); - memcpy(s->buf + s->length, c, len); - s->length += len; -} - -static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len) -{ - memcpy(s->buf + s->length, c, len); - s->length += len; -} - -static inline void strbuf_ensure_null(strbuf_t *s) -{ - s->buf[s->length] = 0; -} - -static inline char *strbuf_string(strbuf_t *s, int *len) -{ - if (len) - *len = s->length; - - return s->buf; -} - -/* vi:ai et sw=4 ts=4: - */ diff --git a/src/lib/lua-enet/enet.c b/src/lib/lua-enet/enet.c deleted file mode 100644 index 04eaac29..00000000 --- a/src/lib/lua-enet/enet.c +++ /dev/null @@ -1,808 +0,0 @@ -/** - * - * Copyright (C) 2014 by Leaf Corcoran - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING IN - * THE SOFTWARE. - */ - -#include -#include - -// For lua5.2 support, instead we could replace all the luaL_register's with whatever -// lua5.2's equivalent function is, but this is easier so whatever. -#define LUA_COMPAT_MODULE -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -#include -#include - -#define check_host(l, idx)\ - *(ENetHost**)luaL_checkudata(l, idx, "enet_host") - -#define check_peer(l, idx)\ - *(ENetPeer**)luaL_checkudata(l, idx, "enet_peer") - -/** - * Parse address string, eg: - * *:5959 - * 127.0.0.1:* - * website.com:8080 - */ -static void parse_address(lua_State *l, const char *addr_str, ENetAddress *address) { - int host_i = 0, port_i = 0; - char host_str[128] = {0}; - char port_str[32] = {0}; - int scanning_port = 0; - - char *c = (char *)addr_str; - - while (*c != 0) { - if (host_i >= 128 || port_i >= 32 ) luaL_error(l, "Hostname too long"); - if (scanning_port) { - port_str[port_i++] = *c; - } else { - if (*c == ':') { - scanning_port = 1; - } else { - host_str[host_i++] = *c; - } - } - c++; - } - host_str[host_i] = '\0'; - port_str[port_i] = '\0'; - - if (host_i == 0) luaL_error(l, "Failed to parse address"); - if (port_i == 0) luaL_error(l, "Missing port in address"); - - if (strcmp("*", host_str) == 0) { - address->host = ENET_HOST_ANY; - } else { - if (enet_address_set_host(address, host_str) != 0) { - luaL_error(l, "Failed to resolve host name"); - } - } - - if (strcmp("*", port_str) == 0) { - address->port = ENET_PORT_ANY; - } else { - address->port = atoi(port_str); - } -} - -/** - * Find the index of a given peer for which we only have the pointer. - */ -size_t find_peer_index (lua_State *l, ENetHost *enet_host, ENetPeer *peer) { - size_t peer_index; - for (peer_index = 0; peer_index < enet_host->peerCount; peer_index++) { - if (peer == &(enet_host->peers[peer_index])) - return peer_index; - } - - luaL_error (l, "enet: could not find peer id!"); - - return peer_index; -} - -static void push_peer(lua_State *l, ENetPeer *peer) { - // try to find in peer table - lua_getfield(l, LUA_REGISTRYINDEX, "enet_peers"); - lua_pushlightuserdata(l, peer); - lua_gettable(l, -2); - - if (lua_isnil(l, -1)) { - // printf("creating new peer\n"); - lua_pop(l, 1); - - *(ENetPeer**)lua_newuserdata(l, sizeof(void*)) = peer; - luaL_getmetatable(l, "enet_peer"); - lua_setmetatable(l, -2); - - lua_pushlightuserdata(l, peer); - lua_pushvalue(l, -2); - - lua_settable(l, -4); - } - lua_remove(l, -2); // remove enet_peers -} - -static void push_event(lua_State *l, ENetEvent *event) { - lua_newtable(l); // event table - - if (event->peer) { - push_peer(l, event->peer); - lua_setfield(l, -2, "peer"); - } - - switch (event->type) { - case ENET_EVENT_TYPE_CONNECT: - lua_pushinteger(l, event->data); - lua_setfield(l, -2, "data"); - - lua_pushstring(l, "connect"); - break; - case ENET_EVENT_TYPE_DISCONNECT: - lua_pushinteger(l, event->data); - lua_setfield(l, -2, "data"); - - lua_pushstring(l, "disconnect"); - break; - case ENET_EVENT_TYPE_RECEIVE: - lua_pushlstring(l, (const char *)event->packet->data, event->packet->dataLength); - lua_setfield(l, -2, "data"); - - lua_pushinteger(l, event->channelID); - lua_setfield(l, -2, "channel"); - - lua_pushstring(l, "receive"); - - enet_packet_destroy(event->packet); - break; - case ENET_EVENT_TYPE_NONE: - lua_pushstring(l, "none"); - break; - } - - lua_setfield(l, -2, "type"); -} - -/** - * Read a packet off the stack as a string - * idx is position of string - */ -static ENetPacket *read_packet(lua_State *l, int idx, enet_uint8 *channel_id) { - size_t size; - int argc = lua_gettop(l); - const void *data = luaL_checklstring(l, idx, &size); - ENetPacket *packet; - - enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE; - *channel_id = 0; - - if (argc >= idx+2 && !lua_isnil(l, idx+2)) { - const char *flag_str = luaL_checkstring(l, idx+2); - if (strcmp("unsequenced", flag_str) == 0) { - flags = ENET_PACKET_FLAG_UNSEQUENCED; - } else if (strcmp("reliable", flag_str) == 0) { - flags = ENET_PACKET_FLAG_RELIABLE; - } else if (strcmp("unreliable", flag_str) == 0) { - flags = 0; - } else { - luaL_error(l, "Unknown packet flag: %s", flag_str); - } - } - - if (argc >= idx+1 && !lua_isnil(l, idx+1)) { - *channel_id = luaL_checkint(l, idx+1); - } - - packet = enet_packet_create(data, size, flags); - if (packet == NULL) { - luaL_error(l, "Failed to create packet"); - } - - return packet; -} - -/** - * Create a new host - * Args: - * address (nil for client) - * [peer_count = 64] - * [channel_count = 1] - * [in_bandwidth = 0] - * [out_bandwidth = 0] - */ -static int host_create(lua_State *l) { - ENetHost *host; - size_t peer_count = 64, channel_count = 1; - enet_uint32 in_bandwidth = 0, out_bandwidth = 0; - - int have_address = 1; - ENetAddress address; - - if (lua_gettop(l) == 0 || lua_isnil(l, 1)) { - have_address = 0; - } else { - parse_address(l, luaL_checkstring(l, 1), &address); - } - - switch (lua_gettop(l)) { - case 5: - if (!lua_isnil(l, 5)) out_bandwidth = luaL_checkint(l, 5); - case 4: - if (!lua_isnil(l, 4)) in_bandwidth = luaL_checkint(l, 4); - case 3: - if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3); - case 2: - if (!lua_isnil(l, 2)) peer_count = luaL_checkint(l, 2); - } - - // printf("host create, peers=%d, channels=%d, in=%d, out=%d\n", - // peer_count, channel_count, in_bandwidth, out_bandwidth); - host = enet_host_create(have_address ? &address : NULL, peer_count, - channel_count, in_bandwidth, out_bandwidth); - - if (host == NULL) { - lua_pushnil (l); - lua_pushstring(l, "enet: failed to create host (already listening?)"); - return 2; - } - - *(ENetHost**)lua_newuserdata(l, sizeof(void*)) = host; - luaL_getmetatable(l, "enet_host"); - lua_setmetatable(l, -2); - - return 1; -} - -static int linked_version(lua_State *l) { - lua_pushfstring(l, "%d.%d.%d", - ENET_VERSION_GET_MAJOR(enet_linked_version()), - ENET_VERSION_GET_MINOR(enet_linked_version()), - ENET_VERSION_GET_PATCH(enet_linked_version())); - return 1; -} - -/** - * Serice a host - * Args: - * timeout - * - * Return - * nil on no event - * an event table on event - */ -static int host_service(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - ENetEvent event; - int timeout = 0, out; - - if (lua_gettop(l) > 1) - timeout = luaL_checkint(l, 2); - - out = enet_host_service(host, &event, timeout); - if (out == 0) return 0; - if (out < 0) return luaL_error(l, "Error during service"); - - push_event(l, &event); - return 1; -} - -/** - * Dispatch a single event if available - */ -static int host_check_events(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - ENetEvent event; - int out = enet_host_check_events(host, &event); - if (out == 0) return 0; - if (out < 0) return luaL_error(l, "Error checking event"); - - push_event(l, &event); - return 1; -} - -/** - * Enables an adaptive order-2 PPM range coder for the transmitted data of - * all peers. - */ -static int host_compress_with_range_coder(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - int result = enet_host_compress_with_range_coder (host); - if (result == 0) { - lua_pushboolean (l, 1); - } else { - lua_pushboolean (l, 0); - } - - return 1; -} - -/** - * Connect a host to an address - * Args: - * the address - * [channel_count = 1] - * [data = 0] - */ -static int host_connect(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - ENetAddress address; - ENetPeer *peer; - - enet_uint32 data = 0; - size_t channel_count = 1; - - parse_address(l, luaL_checkstring(l, 2), &address); - - switch (lua_gettop(l)) { - case 4: - if (!lua_isnil(l, 4)) data = luaL_checkint(l, 4); - case 3: - if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3); - } - - // printf("host connect, channels=%d, data=%d\n", channel_count, data); - peer = enet_host_connect(host, &address, channel_count, data); - - if (peer == NULL) { - return luaL_error(l, "Failed to create peer"); - } - - push_peer(l, peer); - - return 1; -} - -static int host_flush(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - enet_host_flush(host); - return 0; -} - -static int host_broadcast(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - enet_uint8 channel_id; - ENetPacket *packet = read_packet(l, 2, &channel_id); - enet_host_broadcast(host, channel_id, packet); - return 0; -} - -// Args: limit:number -static int host_channel_limit(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - int limit = luaL_checkint(l, 2); - enet_host_channel_limit(host, limit); - return 0; -} - -static int host_bandwidth_limit(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - enet_uint32 in_bandwidth = luaL_checkint(l, 2); - enet_uint32 out_bandwidth = luaL_checkint(l, 2); - enet_host_bandwidth_limit(host, in_bandwidth, out_bandwidth); - return 0; -} - -static int host_get_socket_address(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - ENetAddress address; - enet_socket_get_address (host->socket, &address); - - lua_pushfstring(l, "%d.%d.%d.%d:%d", - ((address.host) & 0xFF), - ((address.host >> 8) & 0xFF), - ((address.host >> 16) & 0xFF), - (address.host >> 24& 0xFF), - address.port); - - return 1; -} -static int host_total_sent_data(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - lua_pushinteger (l, host->totalSentData); - - return 1; -} - -static int host_total_received_data(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - lua_pushinteger (l, host->totalReceivedData); - - return 1; -} -static int host_service_time(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - lua_pushinteger (l, host->serviceTime); - - return 1; -} - -static int host_peer_count(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - lua_pushinteger (l, host->peerCount); - - return 1; -} - -static int host_get_peer(lua_State *l) { - ENetHost *host = check_host(l, 1); - if (!host) { - return luaL_error(l, "Tried to index a nil host!"); - } - - size_t peer_index = (size_t) luaL_checkint(l, 2) - 1; - - if (peer_index >= host->peerCount) { - luaL_argerror (l, 2, "Invalid peer index"); - } - - ENetPeer *peer = &(host->peers[peer_index]); - - push_peer (l, peer); - return 1; -} - -static int host_gc(lua_State *l) { - // We have to manually grab the userdata so that we can set it to NULL. - ENetHost** host = luaL_checkudata(l, 1, "enet_host"); - // We don't want to crash by destroying a non-existant host. - if (*host) { - enet_host_destroy(*host); - } - *host = NULL; - return 0; -} - -static int peer_tostring(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - char host_str[128]; - enet_address_get_host_ip(&peer->address, host_str, 128); - - lua_pushstring(l, host_str); - lua_pushstring(l, ":"); - lua_pushinteger(l, peer->address.port); - lua_concat(l, 3); - return 1; -} - -static int peer_ping(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - enet_peer_ping(peer); - return 0; -} - -static int peer_throttle_configure(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - enet_uint32 interval = luaL_checkint(l, 2); - enet_uint32 acceleration = luaL_checkint(l, 3); - enet_uint32 deceleration = luaL_checkint(l, 4); - - enet_peer_throttle_configure(peer, interval, acceleration, deceleration); - return 0; -} - -static int peer_round_trip_time(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - if (lua_gettop(l) > 1) { - enet_uint32 round_trip_time = luaL_checkint(l, 2); - peer->roundTripTime = round_trip_time; - } - - lua_pushinteger (l, peer->roundTripTime); - - return 1; -} - -static int peer_last_round_trip_time(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - if (lua_gettop(l) > 1) { - enet_uint32 round_trip_time = luaL_checkint(l, 2); - peer->lastRoundTripTime = round_trip_time; - } - lua_pushinteger (l, peer->lastRoundTripTime); - - return 1; -} - -static int peer_ping_interval(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - if (lua_gettop(l) > 1) { - enet_uint32 interval = luaL_checkint(l, 2); - enet_peer_ping_interval (peer, interval); - } - - lua_pushinteger (l, peer->pingInterval); - - return 1; -} - -static int peer_timeout(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - enet_uint32 timeout_limit = 0; - enet_uint32 timeout_minimum = 0; - enet_uint32 timeout_maximum = 0; - - switch (lua_gettop(l)) { - case 4: - if (!lua_isnil(l, 4)) timeout_maximum = luaL_checkint(l, 4); - case 3: - if (!lua_isnil(l, 3)) timeout_minimum = luaL_checkint(l, 3); - case 2: - if (!lua_isnil(l, 2)) timeout_limit = luaL_checkint(l, 2); - } - - enet_peer_timeout (peer, timeout_limit, timeout_minimum, timeout_maximum); - - lua_pushinteger (l, peer->timeoutLimit); - lua_pushinteger (l, peer->timeoutMinimum); - lua_pushinteger (l, peer->timeoutMaximum); - - return 3; -} - -static int peer_disconnect(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0; - enet_peer_disconnect(peer, data); - return 0; -} - -static int peer_disconnect_now(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0; - enet_peer_disconnect_now(peer, data); - return 0; -} - -static int peer_disconnect_later(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0; - enet_peer_disconnect_later(peer, data); - return 0; -} - -static int peer_index(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - size_t peer_index = find_peer_index (l, peer->host, peer); - lua_pushinteger (l, peer_index + 1); - - return 1; -} - -static int peer_state(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - switch (peer->state) { - case (ENET_PEER_STATE_DISCONNECTED): - lua_pushstring (l, "disconnected"); - break; - case (ENET_PEER_STATE_CONNECTING): - lua_pushstring (l, "connecting"); - break; - case (ENET_PEER_STATE_ACKNOWLEDGING_CONNECT): - lua_pushstring (l, "acknowledging_connect"); - break; - case (ENET_PEER_STATE_CONNECTION_PENDING): - lua_pushstring (l, "connection_pending"); - break; - case (ENET_PEER_STATE_CONNECTION_SUCCEEDED): - lua_pushstring (l, "connection_succeeded"); - break; - case (ENET_PEER_STATE_CONNECTED): - lua_pushstring (l, "connected"); - break; - case (ENET_PEER_STATE_DISCONNECT_LATER): - lua_pushstring (l, "disconnect_later"); - break; - case (ENET_PEER_STATE_DISCONNECTING): - lua_pushstring (l, "disconnecting"); - break; - case (ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT): - lua_pushstring (l, "acknowledging_disconnect"); - break; - case (ENET_PEER_STATE_ZOMBIE): - lua_pushstring (l, "zombie"); - break; - default: - lua_pushstring (l, "unknown"); - } - - return 1; -} - -static int peer_connect_id(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - lua_pushinteger (l, peer->connectID); - - return 1; -} - - -static int peer_reset(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - enet_peer_reset(peer); - return 0; -} - -static int peer_receive(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - ENetPacket *packet; - enet_uint8 channel_id = 0; - - if (lua_gettop(l) > 1) { - channel_id = luaL_checkint(l, 2); - } - - packet = enet_peer_receive(peer, &channel_id); - if (packet == NULL) return 0; - - lua_pushlstring(l, (const char *)packet->data, packet->dataLength); - lua_pushinteger(l, channel_id); - - enet_packet_destroy(packet); - return 2; -} - - -/** - * Send a lua string to a peer - * Args: - * packet data, string - * channel id - * flags ["reliable", nil] - * - */ -static int peer_send(lua_State *l) { - ENetPeer *peer = check_peer(l, 1); - - enet_uint8 channel_id; - ENetPacket *packet = read_packet(l, 2, &channel_id); - - // printf("sending, channel_id=%d\n", channel_id); - enet_peer_send(peer, channel_id, packet); - return 0; -} - -static const struct luaL_Reg enet_funcs [] = { - {"host_create", host_create}, - {"linked_version", linked_version}, - {NULL, NULL} -}; - -static const struct luaL_Reg enet_host_funcs [] = { - {"service", host_service}, - {"check_events", host_check_events}, - {"compress_with_range_coder", host_compress_with_range_coder}, - {"connect", host_connect}, - {"flush", host_flush}, - {"broadcast", host_broadcast}, - {"channel_limit", host_channel_limit}, - {"bandwidth_limit", host_bandwidth_limit}, - // Since ENetSocket isn't part of enet-lua, we should try to keep - // naming conventions the same as the rest of the lib. - {"get_socket_address", host_get_socket_address}, - // We need this function to free up our ports when needed! - {"destroy", host_gc}, - - // additional convenience functions (mostly accessors) - {"total_sent_data", host_total_sent_data}, - {"total_received_data", host_total_received_data}, - {"service_time", host_service_time}, - {"peer_count", host_peer_count}, - {"get_peer", host_get_peer}, - {NULL, NULL} -}; - -static const struct luaL_Reg enet_peer_funcs [] = { - {"disconnect", peer_disconnect}, - {"disconnect_now", peer_disconnect_now}, - {"disconnect_later", peer_disconnect_later}, - {"reset", peer_reset}, - {"ping", peer_ping}, - {"receive", peer_receive}, - {"send", peer_send}, - {"throttle_configure", peer_throttle_configure}, - {"ping_interval", peer_ping_interval}, - {"timeout", peer_timeout}, - - // additional convenience functions to member variables - {"index", peer_index}, - {"state", peer_state}, - {"connect_id", peer_connect_id}, - {"round_trip_time", peer_round_trip_time}, - {"last_round_trip_time", peer_last_round_trip_time}, - {NULL, NULL} -}; - -static bool enitAlreadyInit = false; - -int luaopen_enet(lua_State *l) { - enet_initialize(); - if (!enitAlreadyInit) { - atexit(enet_deinitialize); - enitAlreadyInit = true; - } - - // create metatables - luaL_newmetatable(l, "enet_host"); - lua_newtable(l); // index - luaL_register(l, NULL, enet_host_funcs); - lua_setfield(l, -2, "__index"); - lua_pushcfunction(l, host_gc); - lua_setfield(l, -2, "__gc"); - - luaL_newmetatable(l, "enet_peer"); - lua_newtable(l); - luaL_register(l, NULL, enet_peer_funcs); - lua_setfield(l, -2, "__index"); - lua_pushcfunction(l, peer_tostring); - lua_setfield(l, -2, "__tostring"); - - // set up peer table - lua_newtable(l); - - lua_newtable(l); // metatable - lua_pushstring(l, "v"); - lua_setfield(l, -2, "__mode"); - lua_setmetatable(l, -2); - - lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers"); - - luaL_register(l, "enet", enet_funcs); - return 1; -} diff --git a/src/lib/lua-enet/enet.h b/src/lib/lua-enet/enet.h deleted file mode 100644 index 570f4a1c..00000000 --- a/src/lib/lua-enet/enet.h +++ /dev/null @@ -1,5 +0,0 @@ -#include "api/api.h" - -#pragma once - -int luaopen_enet(lua_State *l); diff --git a/src/modules/filesystem/filesystem.c b/src/modules/filesystem/filesystem.c index fa015c07..8071d86b 100644 --- a/src/modules/filesystem/filesystem.c +++ b/src/modules/filesystem/filesystem.c @@ -59,7 +59,7 @@ static struct { size_t savePathLength; char savePath[1024]; char source[1024]; - char requirePath[2][1024]; + char requirePath[1024]; char identity[64]; bool fused; } state; @@ -116,7 +116,6 @@ bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* arg arr_reserve(&state.archives, 2); lovrFilesystemSetRequirePath("?.lua;?/init.lua"); - lovrFilesystemSetCRequirePath("??"); // First, try to mount a bundled archive const char* root = NULL; @@ -407,19 +406,11 @@ size_t lovrFilesystemGetWorkingDirectory(char* buffer, size_t size) { } const char* lovrFilesystemGetRequirePath() { - return state.requirePath[0]; -} - -const char* lovrFilesystemGetCRequirePath() { - return state.requirePath[1]; + return state.requirePath; } void lovrFilesystemSetRequirePath(const char* requirePath) { - strncpy(state.requirePath[0], requirePath, sizeof(state.requirePath[0]) - 1); -} - -void lovrFilesystemSetCRequirePath(const char* requirePath) { - strncpy(state.requirePath[1], requirePath, sizeof(state.requirePath[1]) - 1); + strncpy(state.requirePath, requirePath, sizeof(state.requirePath) - 1); } // Archive: dir diff --git a/src/modules/filesystem/filesystem.h b/src/modules/filesystem/filesystem.h index ef7f8862..f153b93a 100644 --- a/src/modules/filesystem/filesystem.h +++ b/src/modules/filesystem/filesystem.h @@ -36,6 +36,4 @@ size_t lovrFilesystemGetExecutablePath(char* buffer, size_t size); size_t lovrFilesystemGetUserDirectory(char* buffer, size_t size); size_t lovrFilesystemGetWorkingDirectory(char* buffer, size_t size); const char* lovrFilesystemGetRequirePath(void); -const char* lovrFilesystemGetCRequirePath(void); void lovrFilesystemSetRequirePath(const char* requirePath); -void lovrFilesystemSetCRequirePath(const char* requirePath);