/* The MIT License (MIT) * * Copyright (c) 2021 Stefano Trettel * * Software repository: MoonCCD, https://github.com/stetre/moonccd * * 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 "internal.h" /*------------------------------------------------------------------------------* | Misc utilities | *------------------------------------------------------------------------------*/ int noprintf(const char *fmt, ...) { (void)fmt; return 0; } int notavailable(lua_State *L, ...) { return luaL_error(L, "function not available in this CL version"); } /*------------------------------------------------------------------------------* | Malloc | *------------------------------------------------------------------------------*/ /* We do not use malloc(), free() etc directly. Instead, we inherit the memory * allocator from the main Lua state instead (see lua_getallocf in the Lua manual) * and use that. * * By doing so, we can use an alternative malloc() implementation without recompiling * this library (we have needs to recompile lua only, or execute it with LD_PRELOAD * set to the path to the malloc library we want to use). */ static lua_Alloc Alloc = NULL; static void *AllocUd = NULL; static void malloc_init(lua_State *L) { if (Alloc) unexpected(L); Alloc = lua_getallocf(L, &AllocUd); } static void *Malloc_(size_t size) { return Alloc ? Alloc(AllocUd, NULL, 0, size) : NULL; } static void Free_(void *ptr) { if (Alloc) Alloc(AllocUd, ptr, 0, 0); } void *Malloc(lua_State *L, size_t size) { void *ptr; if (size == 0) { luaL_error(L, errstring(ERR_MALLOC_ZERO)); return NULL; } ptr = Malloc_(size); if (ptr == NULL) { luaL_error(L, errstring(ERR_MEMORY)); return NULL; } memset(ptr, 0, size); //DBG("Malloc %p\n", ptr); return ptr; } void *MallocNoErr(lua_State *L, size_t size) /* do not raise errors (check the retval) */ { void *ptr = Malloc_(size); (void)L; if (ptr == NULL) return NULL; memset(ptr, 0, size); //DBG("MallocNoErr %p\n", ptr); return ptr; } char *Strdup(lua_State *L, const char *s) { size_t len = strnlen(s, 256); char *ptr = (char *)Malloc(L, len + 1); if (len > 0) memcpy(ptr, s, len); ptr[len] = '\0'; return ptr; } void Free(lua_State *L, void *ptr) { (void)L; //DBG("Free %p\n", ptr); if (ptr) Free_(ptr); } /*------------------------------------------------------------------------------* | Time utilities | *------------------------------------------------------------------------------*/ #if defined(LINUX) #if 0 static double tstosec(const struct timespec *ts) { return ts->tv_sec*1.0+ts->tv_nsec*1.0e-9; } #endif static void sectots(struct timespec *ts, double seconds) { ts->tv_sec = (time_t)seconds; ts->tv_nsec = (long)((seconds - ((double)ts->tv_sec)) * 1.0e9); } double now(void) { #if _POSIX_C_SOURCE >= 199309L struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { printf("clock_gettime error\n"); return -1; } return ts.tv_sec + ts.tv_nsec * 1.0e-9; #else struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { printf("gettimeofday error\n"); return -1; } return tv.tv_sec + tv.tv_usec * 1.0e-6; #endif } void sleeep(double seconds) { #if _POSIX_C_SOURCE >= 199309L struct timespec ts, ts1; struct timespec *req, *rem, *tmp; sectots(&ts, seconds); req = &ts; rem = &ts1; while (1) { if (nanosleep(req, rem) == 0) return; tmp = req; req = rem; rem = tmp; } #else usleep((useconds_t)(seconds * 1.0e6)); #endif } #define time_init(L) \ do \ { \ (void)L; /* do nothing */ \ } while (0) #elif defined(MINGW) #include static LARGE_INTEGER Frequency; double now(void) { LARGE_INTEGER ts; QueryPerformanceCounter(&ts); return ((double)(ts.QuadPart)) / Frequency.QuadPart; } void sleeep(double seconds) { DWORD msec = (DWORD)seconds * 1000; //if(msec < 0) return; DWORD seems to be unsigned Sleep(msec); } static void time_init(lua_State *L) { (void)L; QueryPerformanceFrequency(&Frequency); } #endif /*------------------------------------------------------------------------------* | Light userdata | *------------------------------------------------------------------------------*/ void *checklightuserdata(lua_State *L, int arg) { if (lua_type(L, arg) != LUA_TLIGHTUSERDATA) { luaL_argerror(L, arg, "expected lightuserdata"); return NULL; } return lua_touserdata(L, arg); } void *optlightuserdata(lua_State *L, int arg) { if (lua_isnoneornil(L, arg)) return NULL; return checklightuserdata(L, arg); } void *checklightuserdataorzero(lua_State *L, int arg) { int val, isnum; val = lua_tointegerx(L, arg, &isnum); if (!isnum) return checklightuserdata(L, arg); if (val != 0) luaL_argerror(L, arg, "expected lightuserdata or 0"); return NULL; } /*------------------------------------------------------------------------------* | Deep copy of a table | *------------------------------------------------------------------------------*/ int copytable(lua_State *L) /* Deep-copies the contents of the table at arg=-1 to the table at arg=-2 * Leaves them on the stack. */ { int src = lua_gettop(L); int dst = src - 1; lua_pushnil(L); while (lua_next(L, src)) { lua_pushvalue(L, -2); // key if (lua_type(L, -1) == LUA_TTABLE) /* nested */ { lua_newtable(L); //dst lua_pushvalue(L, -3); // value copytable(L); lua_pop(L, 1); } else lua_pushvalue(L, -2); // value lua_rawset(L, dst); lua_pop(L, 1); // value } return 0; } /*------------------------------------------------------------------------------* | Custom luaL_checkxxx() style functions | *------------------------------------------------------------------------------*/ int checkboolean(lua_State *L, int arg) { if (!lua_isboolean(L, arg)) return (int)luaL_argerror(L, arg, "boolean expected"); return lua_toboolean(L, arg); // ? 1 : 0; } int testboolean(lua_State *L, int arg, int *err) { if (!lua_isboolean(L, arg)) { *err = ERR_TYPE; return 0; } *err = 0; return lua_toboolean(L, arg); // ? 1 : 0; } int optboolean(lua_State *L, int arg, int d) { if (!lua_isboolean(L, arg)) return d; return lua_toboolean(L, arg); } /* 1-based index to 0-based ------------------------------------------*/ int testindex(lua_State *L, int arg, int *err) { int val; if (!lua_isinteger(L, arg)) { *err = ERR_TYPE; return 0; } val = lua_tointeger(L, arg); if (val < 1) { *err = ERR_GENERIC; return 0; } *err = 0; return val - 1; } int checkindex(lua_State *L, int arg) { int val = luaL_checkinteger(L, arg); if (val < 1) return luaL_argerror(L, arg, "positive integer expected"); return val - 1; } int optindex(lua_State *L, int arg, int optval /* 0-based */) { int val = luaL_optinteger(L, arg, optval + 1); if (val < 1) return luaL_argerror(L, arg, "positive integer expected"); return val - 1; } void pushindex(lua_State *L, int val) { lua_pushinteger((L), (val) + 1); } /*------------------------------------------------------------------------------* | Internal error codes | *------------------------------------------------------------------------------*/ const char *errstring(int err) { switch (err) { case ERR_NOTPRESENT: return "missing"; case ERR_SUCCESS: return "success"; case ERR_GENERIC: return "generic error"; case ERR_TABLE: return "not a table"; case ERR_FUNCTION: return "not a function"; case ERR_EMPTY: return "empty list"; case ERR_TYPE: return "invalid type"; case ERR_ELEMTYPE: return "invalid element type"; case ERR_VALUE: return "invalid value"; case ERR_ELEMVALUE: return "invalid element value"; case ERR_MEMORY: return "out of memory"; case ERR_MALLOC_ZERO: return "zero bytes malloc"; case ERR_LENGTH: return "invalid length"; case ERR_POOL: return "elements are not from the same pool"; case ERR_BOUNDARIES: return "invalid boundaries"; case ERR_RANGE: return "out of range"; case ERR_FOPEN: return "cannot open file"; case ERR_OPERATION: return "operation failed"; case ERR_UNKNOWN: return "unknown field name"; default: return "???"; } return NULL; /* unreachable */ } /*------------------------------------------------------------------------------* | Inits | *------------------------------------------------------------------------------*/ void moonccd_utils_init(lua_State *L) { malloc_init(L); time_init(L); }