pax_global_header00006660000000000000000000000064133220042030014477gustar00rootroot0000000000000052 comment=6804f8f7b58da5a2f2ba148b7ffe8ac7f4a1c9ac lua-compat53-0.7/000077500000000000000000000000001332200420300135575ustar00rootroot00000000000000lua-compat53-0.7/.gitignore000066400000000000000000000001101332200420300155370ustar00rootroot00000000000000# generated files *.so *.dll *.o *.obj HISTO # vim temporaries .*.swp lua-compat53-0.7/.travis.yml000066400000000000000000000025141332200420300156720ustar00rootroot00000000000000language: c compiler: gcc sudo: false env: - LUA="lua=5.1" - LUA="lua=5.1" EXTERNAL=true - LUA="lua=5.1" COMPILER="g++" - LUA="lua=5.1" EXTERNAL=true COMPILER="g++" - LUA="luajit=@v2.1 --compat=none" - LUA="luajit=@v2.1 --compat=none" EXTERNAL=true - LUA="luajit=@v2.1 --compat=all" - LUA="luajit=@v2.1 --compat=all" EXTERNAL=true - LUA="lua=5.2" - LUA="lua=5.2" EXTERNAL=true - LUA="lua=5.2" COMPILER="g++" - LUA="lua=5.2" EXTERNAL=true COMPILER="g++" branches: only: - master git: depth: 3 notifications: email: false before_install: - pip install --user hererocks - hererocks old --$LUA - test -e old/bin/lua || (cd old/bin && ln -s luajit* lua) - hererocks new --lua=5.3 install: - export CC="${COMPILER:-gcc}" DEF="" SRC="" CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC" - if [ "x${EXTERNAL:-}" = xtrue ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC} - ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC} - gcc ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c ${SRC} script: - (cd old && bin/lua ../tests/test.lua) > old.txt - (cd new && bin/lua ../tests/test.lua) > new.txt - diff old.txt new.txt || true lua-compat53-0.7/LICENSE000066400000000000000000000020721332200420300145650ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Kepler Project. 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. lua-compat53-0.7/README.md000066400000000000000000000226631332200420300150470ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/keplerproject/lua-compat-5.3.svg?branch=master)](https://travis-ci.org/keplerproject/lua-compat-5.3) # lua-compat-5.3 Lua-5.3-style APIs for Lua 5.2 and 5.1. ## What is it This is a small module that aims to make it easier to write code in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua 5.3. This does *not* make Lua 5.2 (or even Lua 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. It includes: * _For writing Lua_: The Lua module `compat53`, which can be require'd from Lua scripts and run in Lua 5.1, 5.2, and 5.3, including a backport of the `utf8` module, the 5.3 `table` module, and the string packing functions straight from the Lua 5.3 sources. * _For writing C_: A C header and file which can be linked to your Lua module written in C, providing some functions from the C API of Lua 5.3 that do not exist in Lua 5.2 or 5.1, making it easier to write C code that compiles with all three versions of liblua. ## How to use it ### Lua module ```lua require("compat53") ``` `compat53` makes changes to your global environment and does not return a meaningful return value, so the usual idiom of storing the return of `require` in a local variable makes no sense. When run under Lua 5.3, this module does nothing. When run under Lua 5.2 or 5.1, it replaces some of your standard functions and adds new ones to bring your environment closer to that of Lua 5.3. It also tries to load the backported `utf8`, `table`, and string packing modules automatically. If unsuccessful, pure Lua versions of the new `table` functions are used as a fallback, and [Roberto's struct library][1] is tried for string packing. #### Lua submodules ```lua local _ENV = require("compat53.module") if setfenv then setfenv(1, _ENV) end ``` The `compat53.module` module does not modify the global environment, and so it is safe to use in modules without affecting other Lua files. It is supposed to be set as the current environment (see above), i.e. cherry picking individual functions from this module is expressly *not* supported!). Not all features are available when using this module (e.g. yieldable (x)pcall support, string/file methods, etc.), so it is recommended to use plain `require("compat53")` whenever possible. ### C code There are two ways of adding the C API compatibility functions/macros to your project: * If `COMPAT53_PREFIX` is *not* `#define`d, `compat-5.3.h` `#include`s `compat-5.3.c`, and all functions are made `static`. You don't have to compile/link/add `compat-5.3.c` yourself. This is useful for one-file projects. * If `COMPAT53_PREFIX` is `#define`d, all exported functions are renamed behind the scenes using this prefix to avoid linker conflicts with other code using this package. This doesn't change the way you call the compatibility functions in your code. You have to compile and link `compat-5.3.c` to your project yourself. You can change the way the functions are exported using the `COMPAT53_API` macro (e.g. if you need some `__declspec` magic). While it is technically possible to use the "lua" prefix (and it looks better in the debugger), this is discouraged because LuaJIT has started to implement its own Lua 5.2+ C API functions, and with the "lua" prefix you'd violate the one-definition rule with recent LuaJIT versions. ## What's implemented ### Lua * the `utf8` module backported from the Lua 5.3 sources * `string.pack`, `string.packsize`, and `string.unpack` from the Lua 5.3 sources or from the `struct` module. (`struct` is not 100% compatible to Lua 5.3's string packing!) (See [here][4]) * `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`, and `math.ult` (see [here][5]) * `assert` accepts non-string error messages * `ipairs` respects `__index` metamethod * `table.move` * `table` library respects metamethods For Lua 5.1 additionally: * `load` and `loadfile` accept `mode` and `env` parameters * `table.pack` and `table.unpack` * string patterns may contain embedded zeros (but see [here][6]) * `string.rep` accepts `sep` argument * `string.format` calls `tostring` on arguments for `%s` * `math.log` accepts base argument * `xpcall` takes additional arguments * `pcall` and `xpcall` can execute functions that yield (see [here][22] for a possible problem with `coroutine.running`) * `pairs` respects `__pairs` metamethod (see [here][7]) * `rawlen` (but `#` still doesn't respect `__len` for tables) * `package.searchers` as alias for `package.loaders` * `package.searchpath` (see [here][8]) * `coroutine` functions dealing with the main coroutine (see [here][22] for a possible problem with `coroutine.running`) * `coroutine.create` accepts functions written in C * return code of `os.execute` (see [here][9]) * `io.write` and `file:write` return file handle * `io.lines` and `file:lines` accept format arguments (like `io.read`) (see [here][10] and [here][11]) * `debug.setmetatable` returns object * `debug.getuservalue` (see [here][12]) * `debug.setuservalue` (see [here][13]) ### C * `lua_KContext` (see [here][14]) * `lua_KFunction` (see [here][14]) * `lua_dump` (extra `strip` parameter, ignored, see [here][15]) * `lua_getfield` (return value) * `lua_geti` and `lua_seti` * `lua_getglobal` (return value) * `lua_getmetafield` (return value) * `lua_gettable` (return value) * `lua_getuservalue` (limited compatibility, see [here][16]) * `lua_setuservalue` (limited compatibility, see [here][17]) * `lua_isinteger` * `lua_numbertointeger` * `lua_callk` and `lua_pcallk` (limited compatibility, see [here][14]) * `lua_resume` * `lua_rawget` and `lua_rawgeti` (return values) * `lua_rawgetp` and `lua_rawsetp` * `luaL_requiref` (now checks `package.loaded` first) * `lua_rotate` * `lua_stringtonumber` (see [here][18]) For Lua 5.1 additionally: * `LUA_OK` * `LUA_ERRGCMM` * `LUA_OP*` macros for `lua_arith` and `lua_compare` * `LUA_FILEHANDLE` * `lua_Unsigned` * `luaL_Stream` (limited compatibility, see [here][19]) * `lua_absindex` * `lua_arith` (see [here][20]) * `lua_compare` * `lua_len`, `lua_rawlen`, and `luaL_len` * `lua_load` (mode argument) * `lua_pushstring`, `lua_pushlstring` (return value) * `lua_copy` * `lua_pushglobaltable` * `luaL_testudata` * `luaL_setfuncs`, `luaL_newlibtable`, and `luaL_newlib` * `luaL_setmetatable` * `luaL_getsubtable` * `luaL_traceback` * `luaL_execresult` * `luaL_fileresult` * `luaL_loadbufferx` * `luaL_loadfilex` * `luaL_checkversion` (with empty body, only to avoid compile errors, see [here][21]) * `luaL_tolstring` * `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize` (see [here][22]) * `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`, `luaL_checkunsigned`, `luaL_optunsigned`, if `LUA_COMPAT_APIINTCASTS` is defined. ## What's not implemented * bit operators * integer division operator * utf8 escape sequences * 64 bit integers * `coroutine.isyieldable` * Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See [`lua-compat-5.2`][2] for a detailed list. * the following C API functions/macros: * `lua_isyieldable` * `lua_getextraspace` * `lua_arith` (new operators missing) * `lua_push(v)fstring` (new formats missing) * `lua_upvalueid` (5.1) * `lua_upvaluejoin` (5.1) * `lua_version` (5.1) * `lua_yieldk` (5.1) ## See also * For Lua-5.2-style APIs under Lua 5.1, see [lua-compat-5.2][2], which also is the basis for most of the code in this project. * For Lua-5.1-style APIs under Lua 5.0, see [Compat-5.1][3] ## Credits This package contains code written by: * [The Lua Team](http://www.lua.org) * Philipp Janda ([@siffiejoe](http://github.com/siffiejoe)) * Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola)) * Hisham Muhammad ([@hishamhm](http://github.com/hishamhm)) * Renato Maia ([@renatomaia](http://github.com/renatomaia)) * [@ThePhD](http://github.com/ThePhD) * [@Daurnimator](http://github.com/Daurnimator) [1]: http://www.inf.puc-rio.br/~roberto/struct/ [2]: http://github.com/keplerproject/lua-compat-5.2/ [3]: http://keplerproject.org/compat/ [4]: https://github.com/keplerproject/lua-compat-5.3/wiki/string_packing [5]: https://github.com/keplerproject/lua-compat-5.3/wiki/math.type [6]: https://github.com/keplerproject/lua-compat-5.3/wiki/pattern_matching [7]: https://github.com/keplerproject/lua-compat-5.3/wiki/pairs [8]: https://github.com/keplerproject/lua-compat-5.3/wiki/package.searchpath [9]: https://github.com/keplerproject/lua-compat-5.3/wiki/os.execute [10]: https://github.com/keplerproject/lua-compat-5.3/wiki/io.lines [11]: https://github.com/keplerproject/lua-compat-5.3/wiki/file.lines [12]: https://github.com/keplerproject/lua-compat-5.3/wiki/debug.getuservalue [13]: https://github.com/keplerproject/lua-compat-5.3/wiki/debug.setuservalue [14]: https://github.com/keplerproject/lua-compat-5.3/wiki/yieldable_c_functions [15]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_dump [16]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_getuservalue [17]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_setuservalue [18]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_stringtonumber [19]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Stream [20]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_arith [21]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_checkversion [22]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Buffer [23]: https://github.com/keplerproject/lua-compat-5.3/wiki/coroutine.running lua-compat53-0.7/c-api/000077500000000000000000000000001332200420300145505ustar00rootroot00000000000000lua-compat53-0.7/c-api/compat-5.3.c000066400000000000000000000651001332200420300165040ustar00rootroot00000000000000#include #include #include #include #include #include #include "compat-5.3.h" /* don't compile it again if it already is included via compat53.h */ #ifndef COMPAT53_C_ #define COMPAT53_C_ /* definitions for Lua 5.1 only */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 #ifndef COMPAT53_FOPEN_NO_LOCK # if defined(_MSC_VER) # define COMPAT53_FOPEN_NO_LOCK 1 # else /* otherwise */ # define COMPAT53_FOPEN_NO_LOCK 0 # endif /* VC++ only so far */ #endif /* No-lock fopen_s usage if possible */ #if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK # include #endif /* VC++ _fsopen for share-allowed file read */ #ifndef COMPAT53_HAVE_STRERROR_R # if defined(__GLIBC__) || defined(_POSIX_VERSION) || defined(__APPLE__) || \ (!defined (__MINGW32__) && defined(__GNUC__) && (__GNUC__ < 6)) # define COMPAT53_HAVE_STRERROR_R 1 # else /* none of the defines matched: define to 0 */ # define COMPAT53_HAVE_STRERROR_R 0 # endif /* have strerror_r of some form */ #endif /* strerror_r */ #ifndef COMPAT53_HAVE_STRERROR_S # if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \ defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__) # define COMPAT53_HAVE_STRERROR_S 1 # else /* not VC++ or C11 */ # define COMPAT53_HAVE_STRERROR_S 0 # endif /* strerror_s from VC++ or C11 */ #endif /* strerror_s */ #ifndef COMPAT53_LUA_FILE_BUFFER_SIZE # define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 #endif /* Lua File Buffer Size */ static char* compat53_strerror (int en, char* buff, size_t sz) { #if COMPAT53_HAVE_STRERROR_R /* use strerror_r here, because it's available on these specific platforms */ if (sz > 0) { buff[0] = '\0'; /* we don't care whether the GNU version or the XSI version is used: */ if (strerror_r(en, buff, sz)) { /* Yes, we really DO want to ignore the return value! * GCC makes that extra hard, not even a (void) cast will do. */ } if (buff[0] == '\0') { /* Buffer is unchanged, so we probably have called GNU strerror_r which * returned a static constant string. Chances are that strerror will * return the same static constant string and therefore be thread-safe. */ return strerror(en); } } return buff; /* sz is 0 *or* strerror_r wrote into the buffer */ #elif COMPAT53_HAVE_STRERROR_S /* for MSVC and other C11 implementations, use strerror_s since it's * provided by default by the libraries */ strerror_s(buff, sz, en); return buff; #else /* fallback, but strerror is not guaranteed to be threadsafe due to modifying * errno itself and some impls not locking a static buffer for it ... but most * known systems have threadsafe errno: this might only change if the locale * is changed out from under someone while this function is being called */ (void)buff; (void)sz; return strerror(en); #endif } COMPAT53_API int lua_absindex (lua_State *L, int i) { if (i < 0 && i > LUA_REGISTRYINDEX) i += lua_gettop(L) + 1; return i; } static void compat53_call_lua (lua_State *L, char const code[], size_t len, int nargs, int nret) { lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); if (lua_type(L, -1) != LUA_TFUNCTION) { lua_pop(L, 1); if (luaL_loadbuffer(L, code, len, "=none")) lua_error(L); lua_pushvalue(L, -1); lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); } lua_insert(L, -nargs-1); lua_call(L, nargs, nret); } static const char compat53_arith_code[] = "local op,a,b=...\n" "if op==0 then return a+b\n" "elseif op==1 then return a-b\n" "elseif op==2 then return a*b\n" "elseif op==3 then return a/b\n" "elseif op==4 then return a%b\n" "elseif op==5 then return a^b\n" "elseif op==6 then return -a\n" "end\n"; COMPAT53_API void lua_arith (lua_State *L, int op) { if (op < LUA_OPADD || op > LUA_OPUNM) luaL_error(L, "invalid 'op' argument for lua_arith"); luaL_checkstack(L, 5, "not enough stack slots"); if (op == LUA_OPUNM) lua_pushvalue(L, -1); lua_pushnumber(L, op); lua_insert(L, -3); compat53_call_lua(L, compat53_arith_code, sizeof(compat53_arith_code)-1, 3, 1); } static const char compat53_compare_code[] = "local a,b=...\n" "return a<=b\n"; COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op) { int result = 0; switch (op) { case LUA_OPEQ: return lua_equal(L, idx1, idx2); case LUA_OPLT: return lua_lessthan(L, idx1, idx2); case LUA_OPLE: luaL_checkstack(L, 5, "not enough stack slots"); idx1 = lua_absindex(L, idx1); idx2 = lua_absindex(L, idx2); lua_pushvalue(L, idx1); lua_pushvalue(L, idx2); compat53_call_lua(L, compat53_compare_code, sizeof(compat53_compare_code)-1, 2, 1); result = lua_toboolean(L, -1); lua_pop(L, 1); return result; default: luaL_error(L, "invalid 'op' argument for lua_compare"); } return 0; } COMPAT53_API void lua_copy (lua_State *L, int from, int to) { int abs_to = lua_absindex(L, to); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushvalue(L, from); lua_replace(L, abs_to); } COMPAT53_API void lua_len (lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TSTRING: lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); break; case LUA_TTABLE: if (!luaL_callmeta(L, i, "__len")) lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); break; case LUA_TUSERDATA: if (luaL_callmeta(L, i, "__len")) break; /* FALLTHROUGH */ default: luaL_error(L, "attempt to get length of a %s value", lua_typename(L, lua_type(L, i))); } } COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p) { int abs_i = lua_absindex(L, i); lua_pushlightuserdata(L, (void*)p); lua_rawget(L, abs_i); return lua_type(L, -1); } COMPAT53_API void lua_rawsetp (lua_State *L, int i, const void *p) { int abs_i = lua_absindex(L, i); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushlightuserdata(L, (void*)p); lua_insert(L, -2); lua_rawset(L, abs_i); } COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) { lua_Number n = lua_tonumber(L, i); if (isnum != NULL) { *isnum = (n != 0 || lua_isnumber(L, i)); } return n; } COMPAT53_API void luaL_checkversion (lua_State *L) { (void)L; } COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg) { if (!lua_checkstack(L, sp+LUA_MINSTACK)) { if (msg != NULL) luaL_error(L, "stack overflow (%s)", msg); else { lua_pushliteral(L, "stack overflow"); lua_error(L); } } } COMPAT53_API int luaL_getsubtable (lua_State *L, int i, const char *name) { int abs_i = lua_absindex(L, i); luaL_checkstack(L, 3, "not enough stack slots"); lua_pushstring(L, name); lua_gettable(L, abs_i); if (lua_istable(L, -1)) return 1; lua_pop(L, 1); lua_newtable(L); lua_pushstring(L, name); lua_pushvalue(L, -2); lua_settable(L, abs_i); return 0; } COMPAT53_API lua_Integer luaL_len (lua_State *L, int i) { lua_Integer res = 0; int isnum = 0; luaL_checkstack(L, 1, "not enough stack slots"); lua_len(L, i); res = lua_tointegerx(L, -1, &isnum); lua_pop(L, 1); if (!isnum) luaL_error(L, "object length is not an integer"); return res; } COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup+1, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; lua_pushstring(L, l->name); for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -(nup + 1)); lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ } lua_pop(L, nup); /* remove upvalues */ } COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname) { luaL_checkstack(L, 1, "not enough stack slots"); luaL_getmetatable(L, tname); lua_setmetatable(L, -2); } COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname) { void *p = lua_touserdata(L, i); luaL_checkstack(L, 2, "not enough stack slots"); if (p == NULL || !lua_getmetatable(L, i)) return NULL; else { int res = 0; luaL_getmetatable(L, tname); res = lua_rawequal(L, -1, -2); lua_pop(L, 2); if (!res) p = NULL; } return p; } static int compat53_countlevels (lua_State *L) { lua_Debug ar; int li = 1, le = 1; /* find an upper bound */ while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } /* do a binary search */ while (li < le) { int m = (li + le)/2; if (lua_getstack(L, m, &ar)) li = m + 1; else le = m; } return le - 1; } static int compat53_findfield (lua_State *L, int objidx, int level) { if (level == 0 || !lua_istable(L, -1)) return 0; /* not found */ lua_pushnil(L); /* start 'next' loop */ while (lua_next(L, -2)) { /* for each pair in table */ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ if (lua_rawequal(L, objidx, -1)) { /* found object? */ lua_pop(L, 1); /* remove value (but keep name) */ return 1; } else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ lua_remove(L, -2); /* remove table (but keep name) */ lua_pushliteral(L, "."); lua_insert(L, -2); /* place '.' between the two names */ lua_concat(L, 3); return 1; } } lua_pop(L, 1); /* remove value */ } return 0; /* not found */ } static int compat53_pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_pushvalue(L, LUA_GLOBALSINDEX); if (compat53_findfield(L, top + 1, 2)) { lua_copy(L, -1, top + 1); /* move name to proper place */ lua_pop(L, 2); /* remove pushed values */ return 1; } else { lua_settop(L, top); /* remove function and global table */ return 0; } } static void compat53_pushfuncname (lua_State *L, lua_Debug *ar) { if (*ar->namewhat != '\0') /* is there a name? */ lua_pushfstring(L, "function " LUA_QS, ar->name); else if (*ar->what == 'm') /* main? */ lua_pushliteral(L, "main chunk"); else if (*ar->what == 'C') { if (compat53_pushglobalfuncname(L, ar)) { lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); lua_remove(L, -2); /* remove name */ } else lua_pushliteral(L, "?"); } else lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); } #define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ #define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); int numlevels = compat53_countlevels(L1); int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; if (msg) lua_pushfstring(L, "%s\n", msg); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (level == mark) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); lua_pushfstring(L, "\n\t%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); lua_pushliteral(L, " in "); compat53_pushfuncname(L, &ar); lua_concat(L, lua_gettop(L) - top); } } lua_concat(L, lua_gettop(L) - top); } COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { const char *serr = NULL; int en = errno; /* calls to Lua API may change this value */ char buf[512] = { 0 }; if (stat) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); serr = compat53_strerror(en, buf, sizeof(buf)); if (fname) lua_pushfstring(L, "%s: %s", fname, serr); else lua_pushstring(L, serr); lua_pushnumber(L, (lua_Number)en); return 3; } } static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) { if (mode && strchr(mode, modename[0]) == NULL) { lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); return err; } return LUA_OK; } typedef struct { lua_Reader reader; void *ud; int has_peeked_data; const char *peeked_data; size_t peeked_data_size; } compat53_reader_data; static const char *compat53_reader (lua_State *L, void *ud, size_t *size) { compat53_reader_data *data = (compat53_reader_data *)ud; if (data->has_peeked_data) { data->has_peeked_data = 0; *size = data->peeked_data_size; return data->peeked_data; } else return data->reader(L, data->ud, size); } COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) { int status = LUA_OK; compat53_reader_data compat53_data = { reader, data, 1, 0, 0 }; compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size)); if (compat53_data.peeked_data && compat53_data.peeked_data_size && compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); else status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); if (status != LUA_OK) return status; /* we need to call the original 5.1 version of lua_load! */ #undef lua_load return lua_load(L, compat53_reader, &compat53_data, source); #define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) } typedef struct { int n; /* number of pre-read characters */ FILE *f; /* file being read */ char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */ } compat53_LoadF; static const char *compat53_getF (lua_State *L, void *ud, size_t *size) { compat53_LoadF *lf = (compat53_LoadF *)ud; (void)L; /* not used */ if (lf->n > 0) { /* are there pre-read characters to be read? */ *size = lf->n; /* return them (chars already in buffer) */ lf->n = 0; /* no more pre-read characters */ } else { /* read a block from file */ /* 'fread' can return > 0 *and* set the EOF flag. If next call to 'compat53_getF' called 'fread', it might still wait for user input. The next check avoids this problem. */ if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ } return lf->buff; } static int compat53_errfile (lua_State *L, const char *what, int fnameindex) { char buf[512] = {0}; const char *serr = compat53_strerror(errno, buf, sizeof(buf)); const char *filename = lua_tostring(L, fnameindex) + 1; lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } static int compat53_skipBOM (compat53_LoadF *lf) { const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ int c; lf->n = 0; do { c = getc(lf->f); if (c == EOF || c != *(const unsigned char *)p++) return c; lf->buff[lf->n++] = (char)c; /* to be read by the parser */ } while (*p != '\0'); lf->n = 0; /* prefix matched; discard it */ return getc(lf->f); /* return next character */ } /* ** reads the first character of file 'f' and skips an optional BOM mark ** in its beginning plus its first line if it starts with '#'. Returns ** true if it skipped the first line. In any case, '*cp' has the ** first "valid" character of the file (after the optional BOM and ** a first-line comment). */ static int compat53_skipcomment (compat53_LoadF *lf, int *cp) { int c = *cp = compat53_skipBOM(lf); if (c == '#') { /* first line is a comment (Unix exec. file)? */ do { /* skip first line */ c = getc(lf->f); } while (c != EOF && c != '\n'); *cp = getc(lf->f); /* skip end-of-line, if present */ return 1; /* there was a comment */ } else return 0; /* no comment */ } COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { compat53_LoadF lf; int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; } else { lua_pushfstring(L, "@%s", filename); #if defined(_MSC_VER) /* This code is here to stop a deprecation error that stops builds * if a certain macro is defined. While normally not caring would * be best, some header-only libraries and builds can't afford to * dictate this to the user. A quick check shows that fopen_s this * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET, * possibly even before that so we don't need to do any version * number checks, since this has been there since forever. */ /* TO USER: if you want the behavior of typical fopen_s/fopen, * which does lock the file on VC++, define the macro used below to 0 */ #if COMPAT53_FOPEN_NO_LOCK lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */ if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); #else /* use default locking version */ if (fopen_s(&lf.f, filename, "r") != 0) return compat53_errfile(L, "open", fnameindex); #endif /* Locking vs. No-locking fopen variants */ #else lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */ if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); #endif } if (compat53_skipcomment(&lf, &c)) /* read initial portion */ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ #if defined(_MSC_VER) if (freopen_s(&lf.f, filename, "rb", lf.f) != 0) return compat53_errfile(L, "reopen", fnameindex); #else lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex); #endif compat53_skipcomment(&lf, &c); /* re-read initial portion */ } if (c != EOF) lf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */ status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ return compat53_errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; } COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) { int status = LUA_OK; if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); } else { status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); } if (status != LUA_OK) return status; return luaL_loadbuffer(L, buff, sz, name); } #if !defined(l_inspectstat) && \ (defined(unix) || defined(__unix) || defined(__unix__) || \ defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ (defined(__APPLE__) && defined(__MACH__))) /* some form of unix; check feature macros in unistd.h for details */ # include /* check posix version; the relevant include files and macros probably * were available before 2001, but I'm not sure */ # if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L # include # define l_inspectstat(stat,what) \ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } # endif #endif /* provide default (no-op) version */ #if !defined(l_inspectstat) # define l_inspectstat(stat,what) ((void)0) #endif COMPAT53_API int luaL_execresult (lua_State *L, int stat) { const char *what = "exit"; if (stat == -1) return luaL_fileresult(L, 0, NULL); else { l_inspectstat(stat, what); if (*what == 'e' && stat == 0) lua_pushboolean(L, 1); else lua_pushnil(L); lua_pushstring(L, what); lua_pushinteger(L, stat); return 3; } } COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) { /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ B->b.p = NULL; B->b.L = NULL; B->b.lvl = 0; /* reuse the buffer from the 5.1-style luaL_Buffer though! */ B->ptr = B->b.buffer; B->capacity = LUAL_BUFFERSIZE; B->nelems = 0; B->L2 = L; } COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s) { if (B->capacity - B->nelems < s) { /* needs to grow */ char* newptr = NULL; size_t newcap = B->capacity * 2; if (newcap - B->nelems < s) newcap = B->nelems + s; if (newcap < B->capacity) /* overflow */ luaL_error(B->L2, "buffer too large"); newptr = (char*)lua_newuserdata(B->L2, newcap); memcpy(newptr, B->ptr, B->nelems); if (B->ptr != B->b.buffer) lua_replace(B->L2, -2); /* remove old buffer */ B->ptr = newptr; B->capacity = newcap; } return B->ptr+B->nelems; } COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l) { memcpy(luaL_prepbuffsize(B, l), s, l); luaL_addsize(B, l); } COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B) { size_t len = 0; const char *s = lua_tolstring(B->L2, -1, &len); if (!s) luaL_error(B->L2, "cannot convert value to string"); if (B->ptr != B->b.buffer) lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ luaL_addlstring(B, s, len); lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); } void luaL_pushresult (luaL_Buffer_53 *B) { lua_pushlstring(B->L2, B->ptr, B->nelems); if (B->ptr != B->b.buffer) lua_replace(B->L2, -2); /* remove userdata buffer */ } #endif /* Lua 5.1 */ /* definitions for Lua 5.1 and Lua 5.2 */ #if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502 COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i) { index = lua_absindex(L, index); lua_pushinteger(L, i); lua_gettable(L, index); return lua_type(L, -1); } COMPAT53_API int lua_isinteger (lua_State *L, int index) { if (lua_type(L, index) == LUA_TNUMBER) { lua_Number n = lua_tonumber(L, index); lua_Integer i = lua_tointeger(L, index); if (i == n) return 1; } return 0; } COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) { int ok = 0; lua_Number n = lua_tonumberx(L, i, &ok); if (ok) { if (n == (lua_Integer)n) { if (isnum) *isnum = 1; return (lua_Integer)n; } } if (isnum) *isnum = 0; return 0; } static void compat53_reverse (lua_State *L, int a, int b) { for (; a < b; ++a, --b) { lua_pushvalue(L, a); lua_pushvalue(L, b); lua_replace(L, a); lua_replace(L, b); } } COMPAT53_API void lua_rotate (lua_State *L, int idx, int n) { int n_elems = 0; idx = lua_absindex(L, idx); n_elems = lua_gettop(L)-idx+1; if (n < 0) n += n_elems; if ( n > 0 && n < n_elems) { luaL_checkstack(L, 2, "not enough stack slots available"); n = n_elems - n; compat53_reverse(L, idx, idx+n-1); compat53_reverse(L, idx+n, idx+n_elems-1); compat53_reverse(L, idx, idx+n_elems-1); } } COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i) { luaL_checkstack(L, 1, "not enough stack slots available"); index = lua_absindex(L, index); lua_pushinteger(L, i); lua_insert(L, -2); lua_settable(L, index); } #if !defined(lua_str2number) # define lua_str2number(s, p) strtod((s), (p)) #endif COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) { char* endptr; lua_Number n = lua_str2number(s, &endptr); if (endptr != s) { while (*endptr != '\0' && isspace((unsigned char)*endptr)) ++endptr; if (*endptr == '\0') { lua_pushnumber(L, n); return endptr - s + 1; } } return 0; } COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { if (!luaL_callmeta(L, idx, "__tostring")) { int t = lua_type(L, idx), tt = 0; char const* name = NULL; switch (t) { case LUA_TNIL: lua_pushliteral(L, "nil"); break; case LUA_TSTRING: case LUA_TNUMBER: lua_pushvalue(L, idx); break; case LUA_TBOOLEAN: if (lua_toboolean(L, idx)) lua_pushliteral(L, "true"); else lua_pushliteral(L, "false"); break; default: tt = luaL_getmetafield(L, idx, "__name"); name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); if (tt != LUA_TNIL) lua_replace(L, -2); break; } } else { if (!lua_isstring(L, -1)) luaL_error(L, "'__tostring' must return a string"); } return lua_tolstring(L, -1, len); } COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) { luaL_checkstack(L, 3, "not enough stack slots available"); luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); if (lua_getfield(L, -1, modname) == LUA_TNIL) { lua_pop(L, 1); lua_pushcfunction(L, openf); lua_pushstring(L, modname); lua_call(L, 1, 1); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); } if (glb) { lua_pushvalue(L, -1); lua_setglobal(L, modname); } lua_replace(L, -2); } #endif /* Lua 5.1 and 5.2 */ #endif /* COMPAT53_C_ */ /********************************************************************* * This file contains parts of Lua 5.2's and Lua 5.3's source code: * * Copyright (C) 1994-2014 Lua.org, PUC-Rio. * * 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. *********************************************************************/ lua-compat53-0.7/c-api/compat-5.3.h000066400000000000000000000307561332200420300165220ustar00rootroot00000000000000#ifndef COMPAT53_H_ #define COMPAT53_H_ #include #include #include #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) extern "C" { #endif #include #include #include #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) } #endif #undef COMPAT53_INCLUDE_SOURCE #if defined(COMPAT53_PREFIX) /* - change the symbol names of functions to avoid linker conflicts * - compat-5.3.c needs to be compiled (and linked) separately */ # if !defined(COMPAT53_API) # define COMPAT53_API extern # endif #else /* COMPAT53_PREFIX */ /* - make all functions static and include the source. * - compat-5.3.c doesn't need to be compiled (and linked) separately */ # define COMPAT53_PREFIX compat53 # undef COMPAT53_API # if defined(__GNUC__) || defined(__clang__) # define COMPAT53_API __attribute__((__unused__)) static # else # define COMPAT53_API static # endif # define COMPAT53_INCLUDE_SOURCE #endif /* COMPAT53_PREFIX */ #define COMPAT53_CONCAT_HELPER(a, b) a##b #define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) /* declarations for Lua 5.1 */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 /* XXX not implemented: * lua_arith (new operators) * lua_upvalueid * lua_upvaluejoin * lua_version * lua_yieldk */ #ifndef LUA_OK # define LUA_OK 0 #endif #ifndef LUA_OPADD # define LUA_OPADD 0 #endif #ifndef LUA_OPSUB # define LUA_OPSUB 1 #endif #ifndef LUA_OPMUL # define LUA_OPMUL 2 #endif #ifndef LUA_OPDIV # define LUA_OPDIV 3 #endif #ifndef LUA_OPMOD # define LUA_OPMOD 4 #endif #ifndef LUA_OPPOW # define LUA_OPPOW 5 #endif #ifndef LUA_OPUNM # define LUA_OPUNM 6 #endif #ifndef LUA_OPEQ # define LUA_OPEQ 0 #endif #ifndef LUA_OPLT # define LUA_OPLT 1 #endif #ifndef LUA_OPLE # define LUA_OPLE 2 #endif /* LuaJIT/Lua 5.1 does not have the updated * error codes for thread status/function returns (but some patched versions do) * define it only if it's not found */ #if !defined(LUA_ERRGCMM) /* Use + 2 because in some versions of Lua (Lua 5.1) * LUA_ERRFILE is defined as (LUA_ERRERR+1) * so we need to avoid it (LuaJIT might have something at this * integer value too) */ # define LUA_ERRGCMM (LUA_ERRERR + 2) #endif /* LUA_ERRGCMM define */ typedef size_t lua_Unsigned; typedef struct luaL_Buffer_53 { luaL_Buffer b; /* make incorrect code crash! */ char *ptr; size_t nelems; size_t capacity; lua_State *L2; } luaL_Buffer_53; #define luaL_Buffer luaL_Buffer_53 /* In PUC-Rio 5.1, userdata is a simple FILE* * In LuaJIT, it's a struct where the first member is a FILE* * We can't support the `closef` member */ typedef struct luaL_Stream { FILE *f; } luaL_Stream; #define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) COMPAT53_API int lua_absindex (lua_State *L, int i); #define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) COMPAT53_API void lua_arith (lua_State *L, int op); #define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op); #define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) COMPAT53_API void lua_copy (lua_State *L, int from, int to); #define lua_getuservalue(L, i) \ (lua_getfenv((L), (i)), lua_type((L), -1)) #define lua_setuservalue(L, i) \ (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) #define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) COMPAT53_API void lua_len (lua_State *L, int i); #define lua_pushstring(L, s) \ (lua_pushstring((L), (s)), lua_tostring((L), -1)) #define lua_pushlstring(L, s, len) \ ((((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1)) #ifndef luaL_newlibtable # define luaL_newlibtable(L, l) \ (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) #endif #ifndef luaL_newlib # define luaL_newlib(L, l) \ (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) #endif #define lua_pushglobaltable(L) \ lua_pushvalue((L), LUA_GLOBALSINDEX) #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p); #define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); #define lua_rawlen(L, i) lua_objlen((L), (i)) #define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL) #define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) COMPAT53_API void luaL_checkversion (lua_State *L); #define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode); #define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode); #define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); #define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name); #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) COMPAT53_API lua_Integer luaL_len (lua_State *L, int i); #define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); #define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname); #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname); #define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); #define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname); #define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) COMPAT53_API int luaL_execresult (lua_State *L, int stat); #define lua_callk(L, na, nr, ctx, cont) \ ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) #define lua_pcallk(L, na, nr, err, ctx, cont) \ ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) #define lua_resume(L, from, nargs) \ ((void)(from), lua_resume((L), (nargs))) #define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B); #define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s); #define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l); #define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B); #define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B); #undef luaL_buffinitsize #define luaL_buffinitsize(L, B, s) \ (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) #undef luaL_prepbuffer #define luaL_prepbuffer(B) \ luaL_prepbuffsize((B), LUAL_BUFFERSIZE) #undef luaL_addchar #define luaL_addchar(B, c) \ ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ ((B)->ptr[(B)->nelems++] = (c))) #undef luaL_addsize #define luaL_addsize(B, s) \ ((B)->nelems += (s)) #undef luaL_addstring #define luaL_addstring(B, s) \ luaL_addlstring((B), (s), strlen((s))) #undef luaL_pushresultsize #define luaL_pushresultsize(B, s) \ (luaL_addsize((B), (s)), luaL_pushresult((B))) #if defined(LUA_COMPAT_APIINTCASTS) #define lua_pushunsigned(L, n) \ lua_pushinteger((L), (lua_Integer)(n)) #define lua_tounsignedx(L, i, is) \ ((lua_Unsigned)lua_tointegerx((L), (i), (is))) #define lua_tounsigned(L, i) \ lua_tounsignedx((L), (i), NULL) #define luaL_checkunsigned(L, a) \ ((lua_Unsigned)luaL_checkinteger((L), (a))) #define luaL_optunsigned(L, a, d) \ ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) #endif #endif /* Lua 5.1 only */ /* declarations for Lua 5.1 and 5.2 */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 typedef int lua_KContext; typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); #define lua_dump(L, w, d, s) \ ((void)(s), lua_dump((L), (w), (d))) #define lua_getfield(L, i, k) \ (lua_getfield((L), (i), (k)), lua_type((L), -1)) #define lua_gettable(L, i) \ (lua_gettable((L), (i)), lua_type((L), -1)) #define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i); #define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) COMPAT53_API int lua_isinteger (lua_State *L, int index); #define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53) COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum); #define lua_numbertointeger(n, p) \ ((*(p) = (lua_Integer)(n)), 1) #define lua_rawget(L, i) \ (lua_rawget((L), (i)), lua_type((L), -1)) #define lua_rawgeti(L, i, n) \ (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) #define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) COMPAT53_API void lua_rotate (lua_State *L, int idx, int n); #define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i); #define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s); #define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); #define luaL_getmetafield(L, o, e) \ (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) #define luaL_newmetatable(L, tn) \ (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) #define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb ); #endif /* Lua 5.1 and Lua 5.2 */ /* declarations for Lua 5.2 */ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 /* XXX not implemented: * lua_isyieldable * lua_getextraspace * lua_arith (new operators) * lua_pushfstring (new formats) */ #define lua_getglobal(L, n) \ (lua_getglobal((L), (n)), lua_type((L), -1)) #define lua_getuservalue(L, i) \ (lua_getuservalue((L), (i)), lua_type((L), -1)) #define lua_pushlstring(L, s, len) \ (((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))) #define lua_rawgetp(L, i, p) \ (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) #define LUA_KFUNCTION(_name) \ static int (_name)(lua_State *L, int status, lua_KContext ctx); \ static int (_name ## _52)(lua_State *L) { \ lua_KContext ctx; \ int status = lua_getctx(L, &ctx); \ return (_name)(L, status, ctx); \ } \ static int (_name)(lua_State *L, int status, lua_KContext ctx) #define lua_pcallk(L, na, nr, err, ctx, cont) \ lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) #define lua_callk(L, na, nr, ctx, cont) \ lua_callk((L), (na), (nr), (ctx), cont ## _52) #define lua_yieldk(L, nr, ctx, cont) \ lua_yieldk((L), (nr), (ctx), cont ## _52) #ifdef lua_call # undef lua_call # define lua_call(L, na, nr) \ (lua_callk)((L), (na), (nr), 0, NULL) #endif #ifdef lua_pcall # undef lua_pcall # define lua_pcall(L, na, nr, err) \ (lua_pcallk)((L), (na), (nr), (err), 0, NULL) #endif #ifdef lua_yield # undef lua_yield # define lua_yield(L, nr) \ (lua_yieldk)((L), (nr), 0, NULL) #endif #endif /* Lua 5.2 only */ /* other Lua versions */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 503 # error "unsupported Lua version (i.e. not Lua 5.1, 5.2, or 5.3)" #endif /* other Lua versions except 5.1, 5.2, and 5.3 */ /* helper macro for defining continuation functions (for every version * *except* Lua 5.2) */ #ifndef LUA_KFUNCTION #define LUA_KFUNCTION(_name) \ static int (_name)(lua_State *L, int status, lua_KContext ctx) #endif #if defined(COMPAT53_INCLUDE_SOURCE) # include "compat-5.3.c" #endif #endif /* COMPAT53_H_ */ lua-compat53-0.7/compat53/000077500000000000000000000000001332200420300152125ustar00rootroot00000000000000lua-compat53-0.7/compat53/init.lua000066400000000000000000000323061332200420300166640ustar00rootroot00000000000000local lua_version = _VERSION:sub(-3) if lua_version < "5.3" then local _G, pairs, require, select, type = _G, pairs, require, select, type local debug, io = debug, io local unpack = lua_version == "5.1" and unpack or table.unpack local M = require("compat53.module") -- select the most powerful getmetatable function available local gmt = type(debug) == "table" and debug.getmetatable or getmetatable or function() return false end -- metatable for file objects from Lua's standard io library local file_meta = gmt(io.stdout) -- make '*' optional for file:read and file:lines if type(file_meta) == "table" and type(file_meta.__index) == "table" then local function addasterisk(fmt) if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then return "*"..fmt else return fmt end end local file_lines = file_meta.__index.lines file_meta.__index.lines = function(self, ...) local n = select('#', ...) for i = 1, n do local a = select(i, ...) local b = addasterisk(a) -- as an optimization we only allocate a table for the -- modified format arguments when we have a '*' somewhere if a ~= b then local args = { ... } args[i] = b for j = i+1, n do args[j] = addasterisk(args[j]) end return file_lines(self, unpack(args, 1, n)) end end return file_lines(self, ...) end local file_read = file_meta.__index.read file_meta.__index.read = function(self, ...) local n = select('#', ...) for i = 1, n do local a = select(i, ...) local b = addasterisk(a) -- as an optimization we only allocate a table for the -- modified format arguments when we have a '*' somewhere if a ~= b then local args = { ... } args[i] = b for j = i+1, n do args[j] = addasterisk(args[j]) end return file_read(self, unpack(args, 1, n)) end end return file_read(self, ...) end end -- got a valid metatable for file objects -- changes for Lua 5.1 only if lua_version == "5.1" then -- cache globals local error, pcall, rawset, setmetatable, tostring, xpcall = error, pcall, rawset, setmetatable, tostring, xpcall local coroutine, package, string = coroutine, package, string local coroutine_resume = coroutine.resume local coroutine_running = coroutine.running local coroutine_status = coroutine.status local coroutine_yield = coroutine.yield local io_type = io.type -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" local is_luajit52 = is_luajit and #setmetatable({}, { __len = function() return 1 end }) == 1 -- make package.searchers available as an alias for package.loaders local p_index = { searchers = package.loaders } setmetatable(package, { __index = p_index, __newindex = function(p, k, v) if k == "searchers" then rawset(p, "loaders", v) p_index.searchers = v else rawset(p, k, v) end end }) if type(file_meta) == "table" and type(file_meta.__index) == "table" then if not is_luajit then local function helper(_, var_1, ...) if var_1 == nil then if (...) ~= nil then error((...), 2) end end return var_1, ... end local function lines_iterator(st) return helper(st, st.f:read(unpack(st, 1, st.n))) end local file_write = file_meta.__index.write file_meta.__index.write = function(self, ...) local res, msg, errno = file_write(self, ...) if res then return self else return nil, msg, errno end end file_meta.__index.lines = function(self, ...) if io_type(self) == "closed file" then error("attempt to use a closed file", 2) end local st = { f=self, n=select('#', ...), ... } for i = 1, st.n do local t = type(st[i]) if t == "string" then local fmt = st[i]:match("^*?([aln])") if not fmt then error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) end st[i] = "*"..fmt elseif t ~= "number" then error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) end end return lines_iterator, st end end -- not luajit end -- file_meta valid -- the (x)pcall implementations start a new coroutine internally -- to allow yielding even in Lua 5.1. to allow for accurate -- stack traces we keep track of the nested coroutine activations -- in the weak tables below: local weak_meta = { __mode = "kv" } -- maps the internal pcall coroutines to the user coroutine that -- *should* be running if pcall didn't use coroutines internally local pcall_mainOf = setmetatable({}, weak_meta) -- table that maps each running coroutine started by pcall to -- the coroutine that resumed it (user coroutine *or* pcall -- coroutine!) local pcall_previous = setmetatable({}, weak_meta) -- reverse of `pcall_mainOf`. maps a user coroutine to the -- currently active pcall coroutine started within it local pcall_callOf = setmetatable({}, weak_meta) -- similar to `pcall_mainOf` but is used only while executing -- the error handler of xpcall (thus no nesting is necessary!) local xpcall_running = setmetatable({}, weak_meta) -- handle debug functions if type(debug) == "table" then local debug_getinfo = debug.getinfo local debug_traceback = debug.traceback if not is_luajit then local function calculate_trace_level(co, level) if level ~= nil then for out = 1, 1/0 do local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") if info == nil then local max = out-1 if level <= max then return level end return nil, level-max end end end return 1 end local stack_pattern = "\nstack traceback:" local stack_replace = "" function debug.traceback(co, msg, level) local lvl local nilmsg if type(co) ~= "thread" then co, msg, level = coroutine_running(), co, msg end if msg == nil then msg = "" nilmsg = true elseif type(msg) ~= "string" then return msg end if co == nil then msg = debug_traceback(msg, level or 1) else local xpco = xpcall_running[co] if xpco ~= nil then lvl, level = calculate_trace_level(xpco, level) if lvl then msg = debug_traceback(xpco, msg, lvl) else msg = msg..stack_pattern end lvl, level = calculate_trace_level(co, level) if lvl then local trace = debug_traceback(co, "", lvl) msg = msg..trace:gsub(stack_pattern, stack_replace) end else co = pcall_callOf[co] or co lvl, level = calculate_trace_level(co, level) if lvl then msg = debug_traceback(co, msg, lvl) else msg = msg..stack_pattern end end co = pcall_previous[co] while co ~= nil do lvl, level = calculate_trace_level(co, level) if lvl then local trace = debug_traceback(co, "", lvl) msg = msg..trace:gsub(stack_pattern, stack_replace) end co = pcall_previous[co] end end if nilmsg then msg = msg:gsub("^\n", "") end msg = msg:gsub("\n\t%(tail call%): %?", "\000") msg = msg:gsub("\n\t%.%.%.\n", "\001\n") msg = msg:gsub("\n\t%.%.%.$", "\001") msg = msg:gsub("(%z+)\001(%z+)", function(some, other) return "\n\t(..."..#some+#other.."+ tail call(s)...)" end) msg = msg:gsub("\001(%z+)", function(zeros) return "\n\t(..."..#zeros.."+ tail call(s)...)" end) msg = msg:gsub("(%z+)\001", function(zeros) return "\n\t(..."..#zeros.."+ tail call(s)...)" end) msg = msg:gsub("%z+", function(zeros) return "\n\t(..."..#zeros.." tail call(s)...)" end) msg = msg:gsub("\001", function() return "\n\t..." end) return msg end end -- is not luajit end -- debug table available if not is_luajit52 then local coroutine_running52 = M.coroutine.running function M.coroutine.running() local co, ismain = coroutine_running52() if ismain then return co, true else return pcall_mainOf[co] or co, false end end end if not is_luajit then local function pcall_results(current, call, success, ...) if coroutine_status(call) == "suspended" then return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) end if pcall_previous then pcall_previous[call] = nil local main = pcall_mainOf[call] if main == current then current = nil end pcall_callOf[main] = current end pcall_mainOf[call] = nil return success, ... end local function pcall_exec(current, call, ...) local main = pcall_mainOf[current] or current pcall_mainOf[call] = main if pcall_previous then pcall_previous[call] = current pcall_callOf[main] = call end return pcall_results(current, call, coroutine_resume(call, ...)) end local coroutine_create52 = M.coroutine.create local function pcall_coroutine(func) if type(func) ~= "function" then local callable = func func = function (...) return callable(...) end end return coroutine_create52(func) end function M.pcall(func, ...) local current = coroutine_running() if not current then return pcall(func, ...) end return pcall_exec(current, pcall_coroutine(func), ...) end local function xpcall_catch(current, call, msgh, success, ...) if not success then xpcall_running[current] = call local ok, result = pcall(msgh, ...) xpcall_running[current] = nil if not ok then return false, "error in error handling ("..tostring(result)..")" end return false, result end return true, ... end function M.xpcall(f, msgh, ...) local current = coroutine_running() if not current then local args, n = { ... }, select('#', ...) return xpcall(function() return f(unpack(args, 1, n)) end, msgh) end local call = pcall_coroutine(f) return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) end end -- not luajit end -- lua 5.1 -- handle exporting to global scope local function extend_table(from, to) if from ~= to then for k,v in pairs(from) do if type(v) == "table" and type(to[k]) == "table" and v ~= to[k] then extend_table(v, to[k]) else to[k] = v end end end end extend_table(M, _G) end -- lua < 5.3 -- vi: set expandtab softtabstop=3 shiftwidth=3 : lua-compat53-0.7/compat53/module.lua000066400000000000000000000612641332200420300172130ustar00rootroot00000000000000local _G, _VERSION = _G, _VERSION local lua_version = _VERSION:sub(-3) local M = _G if lua_version < "5.3" then -- cache globals in upvalues local error, ipairs, pairs, pcall, require, select, setmetatable, type = error, ipairs, pairs, pcall, require, select, setmetatable, type local debug, io, math, package, string, table = debug, io, math, package, string, table local io_lines = io.lines local io_read = io.read local unpack = lua_version == "5.1" and unpack or table.unpack -- create module table M = {} local M_meta = { __index = _G, -- __newindex is set at the end } setmetatable(M, M_meta) -- create subtables M.io = setmetatable({}, { __index = io }) M.math = setmetatable({}, { __index = math }) M.string = setmetatable({}, { __index = string }) M.table = setmetatable({}, { __index = table }) M.utf8 = {} -- select the most powerful getmetatable function available local gmt = type(debug) == "table" and debug.getmetatable or getmetatable or function() return false end -- type checking functions local checkinteger -- forward declararation local function argcheck(cond, i, f, extra) if not cond then error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0) end end -- load utf8 library local utf8_ok, utf8lib = pcall(require, "compat53.utf8") if utf8_ok then if lua_version == "5.1" then utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" end for k,v in pairs(utf8lib) do M.utf8[k] = v end package.loaded["utf8"] = M.utf8 end -- load table library local table_ok, tablib = pcall(require, "compat53.table") if table_ok then for k,v in pairs(tablib) do M.table[k] = v end end -- load string packing functions local str_ok, strlib = pcall(require, "compat53.string") if str_ok then for k,v in pairs(strlib) do M.string[k] = v end end -- try Roberto's struct module for string packing/unpacking if -- compat53.string is unavailable if not str_ok then local struct_ok, struct = pcall(require, "struct") if struct_ok then M.string.pack = struct.pack M.string.packsize = struct.size M.string.unpack = struct.unpack end end -- update math library do local maxint, minint = 1 while maxint+1 > maxint and 2*maxint > maxint do maxint = maxint * 2 end if 2*maxint <= maxint then maxint = 2*maxint-1 minint = -maxint-1 else maxint = maxint minint = -maxint end M.math.maxinteger = maxint M.math.mininteger = minint function M.math.tointeger(n) if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then return n end return nil end function M.math.type(n) if type(n) == "number" then if n <= maxint and n >= minint and n % 1 == 0 then return "integer" else return "float" end else return nil end end function checkinteger(x, i, f) local t = type(x) if t ~= "number" then error("bad argument #"..i.." to '"..f.. "' (number expected, got "..t..")", 0) elseif x > maxint or x < minint or x % 1 ~= 0 then error("bad argument #"..i.." to '"..f.. "' (number has no integer representation)", 0) else return x end end function M.math.ult(m, n) m = checkinteger(m, "1", "math.ult") n = checkinteger(n, "2", "math.ult") if m >= 0 and n < 0 then return true elseif m < 0 and n >= 0 then return false else return m < n end end end -- assert should allow non-string error objects function M.assert(cond, ...) if cond then return cond, ... elseif select('#', ...) > 0 then error((...), 0) else error("assertion failed!", 0) end end -- ipairs should respect __index metamethod do local function ipairs_iterator(st, var) var = var + 1 local val = st[var] if val ~= nil then return var, st[var] end end function M.ipairs(t) if gmt(t) ~= nil then -- t has metatable return ipairs_iterator, t, 0 else return ipairs(t) end end end -- make '*' optional for io.read and io.lines do local function addasterisk(fmt) if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then return "*"..fmt else return fmt end end function M.io.read(...) local n = select('#', ...) for i = 1, n do local a = select(i, ...) local b = addasterisk(a) -- as an optimization we only allocate a table for the -- modified format arguments when we have a '*' somewhere. if a ~= b then local args = { ... } args[i] = b for j = i+1, n do args[j] = addasterisk(args[j]) end return io_read(unpack(args, 1, n)) end end return io_read(...) end -- PUC-Rio Lua 5.1 uses a different implementation for io.lines! function M.io.lines(...) local n = select('#', ...) for i = 2, n do local a = select(i, ...) local b = addasterisk(a) -- as an optimization we only allocate a table for the -- modified format arguments when we have a '*' somewhere. if a ~= b then local args = { ... } args[i] = b for j = i+1, n do args[j] = addasterisk(args[j]) end return io_lines(unpack(args, 1, n)) end end return io_lines(...) end end -- update table library (if C module not available) if not table_ok then local table_concat = table.concat local table_insert = table.insert local table_remove = table.remove local table_sort = table.sort function M.table.concat(list, sep, i, j) local mt = gmt(list) if type(mt) == "table" and type(mt.__len) == "function" then local src = list list, i, j = {}, i or 1, j or mt.__len(src) for k = i, j do list[k] = src[k] end end return table_concat(list, sep, i, j) end function M.table.insert(list, ...) local mt = gmt(list) local has_mt = type(mt) == "table" local has_len = has_mt and type(mt.__len) == "function" if has_mt and (has_len or mt.__index or mt.__newindex) then local e = (has_len and mt.__len(list) or #list)+1 local nargs, pos, value = select('#', ...), ... if nargs == 1 then pos, value = e, pos elseif nargs == 2 then pos = checkinteger(pos, "2", "table.insert") argcheck(1 <= pos and pos <= e, "2", "table.insert", "position out of bounds" ) else error("wrong number of arguments to 'insert'", 0) end for i = e-1, pos, -1 do list[i+1] = list[i] end list[pos] = value else return table_insert(list, ...) end end function M.table.move(a1, f, e, t, a2) a2 = a2 or a1 f = checkinteger(f, "2", "table.move") argcheck(f > 0, "2", "table.move", "initial position must be positive") e = checkinteger(e, "3", "table.move") t = checkinteger(t, "4", "table.move") if e >= f then local m, n, d = 0, e-f, 1 if t > f then m, n, d = n, m, -1 end for i = m, n, d do a2[t+i] = a1[f+i] end end return a2 end function M.table.remove(list, pos) local mt = gmt(list) local has_mt = type(mt) == "table" local has_len = has_mt and type(mt.__len) == "function" if has_mt and (has_len or mt.__index or mt.__newindex) then local e = (has_len and mt.__len(list) or #list) pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e if pos ~= e then argcheck(1 <= pos and pos <= e+1, "2", "table.remove", "position out of bounds" ) end local result = list[pos] while pos < e do list[pos] = list[pos+1] pos = pos + 1 end list[pos] = nil return result else return table_remove(list, pos) end end do local function pivot(list, cmp, a, b) local m = b - a if m > 2 then local c = a + (m-m%2)/2 local x, y, z = list[a], list[b], list[c] if not cmp(x, y) then x, y, a, b = y, x, b, a end if not cmp(y, z) then y, b = z, c end if not cmp(x, y) then y, b = x, a end return b, y else return b, list[b] end end local function lt_cmp(a, b) return a < b end local function qsort(list, cmp, b, e) if b < e then local i, j, k, val = b, e, pivot(list, cmp, b, e) while i < j do while i < j and cmp(list[i], val) do i = i + 1 end while i < j and not cmp(list[j], val) do j = j - 1 end if i < j then list[i], list[j] = list[j], list[i] if i == k then k = j end -- update pivot position i, j = i+1, j-1 end end if i ~= k and not cmp(list[i], val) then list[i], list[k] = val, list[i] k = i -- update pivot position end qsort(list, cmp, b, i == k and i-1 or i) return qsort(list, cmp, i+1, e) end end function M.table.sort(list, cmp) local mt = gmt(list) local has_mt = type(mt) == "table" local has_len = has_mt and type(mt.__len) == "function" if has_len then cmp = cmp or lt_cmp local len = mt.__len(list) return qsort(list, cmp, 1, len) else return table_sort(list, cmp) end end end local function unpack_helper(list, i, j, ...) if j < i then return ... else return unpack_helper(list, i, j-1, list[j], ...) end end function M.table.unpack(list, i, j) local mt = gmt(list) local has_mt = type(mt) == "table" local has_len = has_mt and type(mt.__len) == "function" if has_mt and (has_len or mt.__index) then i, j = i or 1, j or (has_len and mt.__len(list)) or #list return unpack_helper(list, i, j) else return unpack(list, i, j) end end end -- update table library -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 if lua_version == "5.1" then -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" local is_luajit52 = is_luajit and #setmetatable({}, { __len = function() return 1 end }) == 1 -- cache globals in upvalues local load, loadfile, loadstring, setfenv, xpcall = load, loadfile, loadstring, setfenv, xpcall local coroutine, os = coroutine, os local coroutine_create = coroutine.create local coroutine_resume = coroutine.resume local coroutine_running = coroutine.running local coroutine_status = coroutine.status local coroutine_yield = coroutine.yield local io_input = io.input local io_open = io.open local io_output = io.output local io_write = io.write local math_log = math.log local os_execute = os.execute local string_find = string.find local string_format = string.format local string_gmatch = string.gmatch local string_gsub = string.gsub local string_match = string.match local string_rep = string.rep local table_concat = table.concat -- create subtables M.coroutine = setmetatable({}, { __index = coroutine }) M.os = setmetatable({}, { __index = os }) M.package = setmetatable({}, { __index = package }) -- handle debug functions if type(debug) == "table" then local debug_setfenv = debug.setfenv local debug_getfenv = debug.getfenv local debug_setmetatable = debug.setmetatable M.debug = setmetatable({}, { __index = debug }) if not is_luajit52 then function M.debug.setuservalue(obj, value) if type(obj) ~= "userdata" then error("bad argument #1 to 'setuservalue' (userdata expected, got ".. type(obj)..")", 2) end if value == nil then value = _G end if type(value) ~= "table" then error("bad argument #2 to 'setuservalue' (table expected, got ".. type(value)..")", 2) end return debug_setfenv(obj, value) end function M.debug.getuservalue(obj) if type(obj) ~= "userdata" then return nil else local v = debug_getfenv(obj) if v == _G or v == package then return nil end return v end end function M.debug.setmetatable(value, tab) debug_setmetatable(value, tab) return value end end -- not luajit with compat52 enabled end -- debug table available if not is_luajit52 then function M.pairs(t) local mt = gmt(t) if type(mt) == "table" and type(mt.__pairs) == "function" then return mt.__pairs(t) else return pairs(t) end end end if not is_luajit then local function check_mode(mode, prefix) local has = { text = false, binary = false } for i = 1,#mode do local c = mode:sub(i, i) if c == "t" then has.text = true end if c == "b" then has.binary = true end end local t = prefix:sub(1, 1) == "\27" and "binary" or "text" if not has[t] then return "attempt to load a "..t.." chunk (mode is '"..mode.."')" end end function M.load(ld, source, mode, env) mode = mode or "bt" local chunk, msg if type( ld ) == "string" then if mode ~= "bt" then local merr = check_mode(mode, ld) if merr then return nil, merr end end chunk, msg = loadstring(ld, source) else local ld_type = type(ld) if ld_type ~= "function" then error("bad argument #1 to 'load' (function expected, got ".. ld_type..")", 2) end if mode ~= "bt" then local checked, merr = false, nil local function checked_ld() if checked then return ld() else checked = true local v = ld() merr = check_mode(mode, v or "") if merr then return nil end return v end end chunk, msg = load(checked_ld, source) if merr then return nil, merr end else chunk, msg = load(ld, source) end end if not chunk then return chunk, msg end if env ~= nil then setfenv(chunk, env) end return chunk end M.loadstring = M.load function M.loadfile(file, mode, env) mode = mode or "bt" if mode ~= "bt" then local f = io_open(file, "rb") if f then local prefix = f:read(1) f:close() if prefix then local merr = check_mode(mode, prefix) if merr then return nil, merr end end end end local chunk, msg = loadfile(file) if not chunk then return chunk, msg end if env ~= nil then setfenv(chunk, env) end return chunk end end -- not luajit if not is_luajit52 then function M.rawlen(v) local t = type(v) if t ~= "string" and t ~= "table" then error("bad argument #1 to 'rawlen' (table or string expected)", 2) end return #v end end if not is_luajit then function M.xpcall(f, msgh, ...) local args, n = { ... }, select('#', ...) return xpcall(function() return f(unpack(args, 1, n)) end, msgh) end end if not is_luajit52 then function M.os.execute(cmd) local code = os_execute(cmd) -- Lua 5.1 does not report exit by signal. if code == 0 then return true, "exit", code else if package.config:sub(1, 1) == '/' then code = code/256 -- only correct on Linux! end return nil, "exit", code end end end if not table_ok and not is_luajit52 then M.table.pack = function(...) return { n = select('#', ...), ... } end end local main_coroutine = coroutine_create(function() end) function M.coroutine.create(func) local success, result = pcall(coroutine_create, func) if not success then if type(func) ~= "function" then error("bad argument #1 (function expected)", 0) end result = coroutine_create(function(...) return func(...) end) end return result end if not is_luajit52 then function M.coroutine.running() local co = coroutine_running() if co then return co, false else return main_coroutine, true end end end function M.coroutine.yield(...) local co, flag = coroutine_running() if co and not flag then return coroutine_yield(...) else error("attempt to yield from outside a coroutine", 0) end end if not is_luajit then function M.coroutine.resume(co, ...) if co == main_coroutine then return false, "cannot resume non-suspended coroutine" else return coroutine_resume(co, ...) end end function M.coroutine.status(co) local notmain = coroutine_running() if co == main_coroutine then return notmain and "normal" or "running" else return coroutine_status(co) end end end -- not luajit if not is_luajit then M.math.log = function(x, base) if base ~= nil then return math_log(x)/math_log(base) else return math_log(x) end end end if not is_luajit then function M.package.searchpath(name, path, sep, rep) sep = (sep or "."):gsub("(%p)", "%%%1") rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") local msg = {} for subpath in path:gmatch("[^;]+") do local fpath = subpath:gsub("%?", pname) local f = io_open(fpath, "r") if f then f:close() return fpath end msg[#msg+1] = "\n\tno file '" .. fpath .. "'" end return nil, table_concat(msg) end end local function fix_pattern(pattern) return (string_gsub(pattern, "%z", "%%z")) end function M.string.find(s, pattern, ...) return string_find(s, fix_pattern(pattern), ...) end function M.string.gmatch(s, pattern) return string_gmatch(s, fix_pattern(pattern)) end function M.string.gsub(s, pattern, ...) return string_gsub(s, fix_pattern(pattern), ...) end function M.string.match(s, pattern, ...) return string_match(s, fix_pattern(pattern), ...) end if not is_luajit then function M.string.rep(s, n, sep) if sep ~= nil and sep ~= "" and n >= 2 then return s .. string_rep(sep..s, n-1) else return string_rep(s, n) end end end if not is_luajit then do local addqt = { ["\n"] = "\\\n", ["\\"] = "\\\\", ["\""] = "\\\"" } local function addquoted(c, d) return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d end function M.string.format(fmt, ...) local args, n = { ... }, select('#', ...) local i = 0 local function adjust_fmt(lead, mods, kind) if #lead % 2 == 0 then i = i + 1 if kind == "s" then args[i] = _G.tostring(args[i]) elseif kind == "q" then args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"' return lead.."%"..mods.."s" end end end fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) return string_format(fmt, unpack(args, 1, n)) end end end function M.io.write(...) local res, msg, errno = io_write(...) if res then return io_output() else return nil, msg, errno end end if not is_luajit then local function helper(st, var_1, ...) if var_1 == nil then if st.doclose then st.f:close() end if (...) ~= nil then error((...), 2) end end return var_1, ... end local function lines_iterator(st) return helper(st, st.f:read(unpack(st, 1, st.n))) end function M.io.lines(fname, ...) local doclose, file, msg if fname ~= nil then doclose, file, msg = true, io_open(fname, "r") if not file then error(msg, 2) end else doclose, file = false, io_input() end local st = { f=file, doclose=doclose, n=select('#', ...), ... } for i = 1, st.n do local t = type(st[i]) if t == "string" then local fmt = st[i]:match("^%*?([aln])") if not fmt then error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) end st[i] = "*"..fmt elseif t ~= "number" then error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) end end return lines_iterator, st end end -- not luajit end -- lua 5.1 -- further write should be forwarded to _G M_meta.__newindex = _G end -- lua < 5.3 -- return module table return M -- vi: set expandtab softtabstop=3 shiftwidth=3 : lua-compat53-0.7/lprefix.h000066400000000000000000000103561332200420300154060ustar00rootroot00000000000000/* ** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ ** Definitions for Lua code that must come before any other header file ** See Copyright Notice in lua.h */ #ifndef lprefix_h #define lprefix_h /* ** Allows POSIX/XSI stuff */ #if !defined(LUA_USE_C89) /* { */ #if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE 600 #elif _XOPEN_SOURCE == 0 #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ #endif /* ** Allows manipulation of large files in gcc and some other compilers */ #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) #define _LARGEFILE_SOURCE 1 #define _FILE_OFFSET_BITS 64 #endif #endif /* } */ /* ** Windows stuff */ #if defined(_WIN32) /* { */ #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ #endif #endif /* } */ /* COMPAT53 adaptation */ #include "c-api/compat-5.3.h" #undef LUAMOD_API #define LUAMOD_API extern #ifdef lutf8lib_c # define luaopen_utf8 luaopen_compat53_utf8 /* we don't support the %U format string of lua_pushfstring! * code below adapted from the Lua 5.3 sources: */ static const char *compat53_utf8_escape (lua_State* L, long x) { if (x < 0x80) { /* ASCII */ char c = (char)x; lua_pushlstring(L, &c, 1); } else { char buff[8] = { 0 }; unsigned int mfb = 0x3f; int n = 1; do { buff[8 - (n++)] = (char)(0x80|(x & 0x3f)); x >>= 6; mfb >>= 1; } while (x > mfb); buff[8-n] = (char)((~mfb << 1) | x); lua_pushlstring(L, buff+8-n, n); } return lua_tostring(L, -1); } # define lua_pushfstring(L, fmt, l) \ compat53_utf8_escape(L, l) #endif #ifdef ltablib_c # define luaopen_table luaopen_compat53_table # ifndef LUA_MAXINTEGER /* conservative estimate: */ # define LUA_MAXINTEGER INT_MAX # endif #endif /* ltablib_c */ #ifdef lstrlib_c #include #include /* move the string library open function out of the way (we only take * the string packing functions)! */ # define luaopen_string luaopen_string_XXX /* used in string.format implementation, which we don't use: */ # ifndef LUA_INTEGER_FRMLEN # define LUA_INTEGER_FRMLEN "" # define LUA_NUMBER_FRMLEN "" # endif # ifndef LUA_MININTEGER # define LUA_MININTEGER 0 # endif # ifndef LUA_INTEGER_FMT # define LUA_INTEGER_FMT "%d" # endif # ifndef LUAI_UACINT # define LUAI_UACINT lua_Integer # endif /* different Lua 5.3 versions have conflicting variants of this macro * in luaconf.h, there's a fallback implementation in lstrlib.c, and * the macro isn't used for string (un)packing anyway! * */ # undef lua_number2strx # if LUA_VERSION_NUM < 503 /* lstrlib assumes that lua_Integer and lua_Unsigned have the same * size, so we use the unsigned equivalent of ptrdiff_t! */ # define lua_Unsigned size_t # endif # ifndef l_mathlim # ifdef LUA_NUMBER_DOUBLE # define l_mathlim(n) (DBL_##n) # else # define l_mathlim(n) (FLT_##n) # endif # endif # ifndef l_mathop # ifdef LUA_NUMBER_DOUBLE # define l_mathop(op) op # else # define l_mathop(op) op##f # endif # endif # ifndef lua_getlocaledecpoint # define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) # endif # ifndef l_sprintf # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L # define l_sprintf(s,sz,f,i) (snprintf(s, sz, f, i)) # else # define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s, f, i)) # endif # endif static int str_pack (lua_State *L); static int str_packsize (lua_State *L); static int str_unpack (lua_State *L); LUAMOD_API int luaopen_compat53_string (lua_State *L) { luaL_Reg const funcs[] = { { "pack", str_pack }, { "packsize", str_packsize }, { "unpack", str_unpack }, { NULL, NULL } }; luaL_newlib(L, funcs); return 1; } /* fake CLANG feature detection on other compilers */ # ifndef __has_attribute # define __has_attribute(x) 0 # endif /* make luaopen_string(_XXX) static, so it (and all other referenced * string functions) won't be included in the resulting dll * (hopefully). */ # undef LUAMOD_API # if defined(__GNUC__) || __has_attribute(__unused__) # define LUAMOD_API __attribute__((__unused__)) static # else # define LUAMOD_API static # endif #endif /* lstrlib.c */ #endif lua-compat53-0.7/lstrlib.c000066400000000000000000001340561332200420300154070ustar00rootroot00000000000000/* ** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #define lstrlib_c #define LUA_LIB #include "lprefix.h" #include #include #include #include #include #include #include #include #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** maximum number of captures that a pattern can do during ** pattern-matching. This limit is arbitrary, but must fit in ** an unsigned char. */ #if !defined(LUA_MAXCAPTURES) #define LUA_MAXCAPTURES 32 #endif /* macro to 'unsign' a character */ #define uchar(c) ((unsigned char)(c)) /* ** Some sizes are better limited to fit in 'int', but must also fit in ** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) */ #define MAX_SIZET ((size_t)(~(size_t)0)) #define MAXSIZE \ (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); lua_pushinteger(L, (lua_Integer)l); return 1; } /* translate a relative string position: negative means back from end */ static lua_Integer posrelat (lua_Integer pos, size_t len) { if (pos >= 0) return pos; else if (0u - (size_t)pos > len) return 0; else return (lua_Integer)len + pos + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > (lua_Integer)l) end = l; if (start <= end) lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); else lua_pushliteral(L, ""); return 1; } static int str_reverse (lua_State *L) { size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i = 0; i < l; i++) p[i] = s[l - i - 1]; luaL_pushresultsize(&b, l); return 1; } static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i=0; i MAXSIZE / n) /* may overflow? */ return luaL_error(L, "resulting string too large"); else { size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; if (lsep > 0) { /* empty 'memcpy' is not that cheap */ memcpy(p, sep, lsep * sizeof(char)); p += lsep; } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ luaL_pushresultsize(&b, totallen); } return 1; } static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi < 1) posi = 1; if (pose > (lua_Integer)l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= INT_MAX) /* arithmetic overflow? */ return luaL_error(L, "string slice too long"); n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } static int capture_to_close (MatchState *ms) { int level = ms->level; for (level--; level>=0; level--) if (ms->capture[level].len == CAP_UNFINISHED) return level; return luaL_error(ms->L, "invalid pattern capture"); } static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (ends with '%%')"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a ']' */ if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (missing ']')"); if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. '%]') */ } while (*p != ']'); return p+1; } default: { return p; } } } static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; case 'g' : res = isgraph(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; case 'z' : res = (c == 0); break; /* deprecated option */ default: return (cl == c); } return (islower(cl) ? res : !res); } static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the '^' */ } while (++p < ec) { if (*p == L_ESC) { p++; if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } else if (uchar(*p) == c) return sig; } return !sig; } static int singlematch (MatchState *ms, const char *s, const char *p, const char *ep) { if (s >= ms->src_end) return 0; else { int c = uchar(*s); switch (*p) { case '.': return 1; /* matches any char */ case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } } } static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } else if (*s == b) cont++; } } return NULL; /* string ends out of balance */ } static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ while (singlematch(ms, s + i, p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; } static const char *min_expand (MatchState *ms, const char *s, const char *p, const char *ep) { for (;;) { const char *res = match(ms, s, ep+1); if (res != NULL) return res; else if (singlematch(ms, s, p, ep)) s++; /* try with one more repetition */ else return NULL; } } static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; if ((res=match(ms, s, p)) == NULL) /* match failed? */ ms->level--; /* undo capture */ return res; } static const char *end_capture (MatchState *ms, const char *s, const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } static const char *match_capture (MatchState *ms, const char *s, int l) { size_t len; l = check_capture(ms, l); len = ms->capture[l].len; if ((size_t)(ms->src_end-s) >= len && memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } static const char *match (MatchState *ms, const char *s, const char *p) { if (ms->matchdepth-- == 0) luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ if (p != ms->p_end) { /* end of pattern? */ switch (*p) { case '(': { /* start capture */ if (*(p + 1) == ')') /* position capture? */ s = start_capture(ms, s, p + 2, CAP_POSITION); else s = start_capture(ms, s, p + 1, CAP_UNFINISHED); break; } case ')': { /* end capture */ s = end_capture(ms, s, p + 1); break; } case '$': { if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ goto dflt; /* no; go to default */ s = (s == ms->src_end) ? s : NULL; /* check end of string */ break; } case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p + 1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p + 2); if (s != NULL) { p += 4; goto init; /* return match(ms, s, p + 4); */ } /* else fail (s == NULL) */ break; } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing '[' after '%%f' in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && matchbracketclass(uchar(*s), p, ep - 1)) { p = ep; goto init; /* return match(ms, s, ep); */ } s = NULL; /* match failed */ break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p + 1))); if (s != NULL) { p += 2; goto init; /* return match(ms, s, p + 2) */ } break; } default: goto dflt; } break; } default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to optional suffix */ /* does not match at least once? */ if (!singlematch(ms, s, p, ep)) { if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ } else /* '+' or no suffix */ s = NULL; /* fail */ } else { /* matched once */ switch (*ep) { /* handle optional suffix */ case '?': { /* optional */ const char *res; if ((res = match(ms, s + 1, ep + 1)) != NULL) s = res; else { p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ } break; } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ /* FALLTHROUGH */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; case '-': /* 0 or more repetitions (minimum) */ s = min_expand(ms, s, p, ep); break; default: /* no suffix */ s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ } } break; } } } ms->matchdepth++; return s; } static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ else { const char *init; /* to search for a '*s2' inside 's1' */ l2--; /* 1st char will be checked by 'memchr' */ l1 = l1-l2; /* 's2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; else { /* correct 'l1' and 's1' to try again */ l1 -= init-s1; s1 = init; } } return NULL; /* not found */ } } static void push_onecapture (MatchState *ms, int i, const char *s, const char *e) { if (i >= ms->level) { if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else luaL_error(ms->L, "invalid capture index %%%d", i + 1); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; int nlevels = (ms->level == 0 && s) ? 1 : ms->level; luaL_checkstack(ms->L, nlevels, "too many captures"); for (i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); return nlevels; /* number of strings pushed */ } /* check whether pattern has no special characters */ static int nospecials (const char *p, size_t l) { size_t upto = 0; do { if (strpbrk(p + upto, SPECIALS)) return 0; /* pattern has a special character */ upto += strlen(p + upto) + 1; /* may have more after \0 */ } while (upto <= l); return 1; /* no special chars found */ } static void prepstate (MatchState *ms, lua_State *L, const char *s, size_t ls, const char *p, size_t lp) { ms->L = L; ms->matchdepth = MAXCCALLS; ms->src_init = s; ms->src_end = s + ls; ms->p_end = p + lp; } static void reprepstate (MatchState *ms) { ms->level = 0; lua_assert(ms->matchdepth == MAXCCALLS); } static int str_find_aux (lua_State *L, int find) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } /* explicit request or no special characters? */ if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); if (s2) { lua_pushinteger(L, (s2 - s) + 1); lua_pushinteger(L, (s2 - s) + lp); return 2; } } else { MatchState ms; const char *s1 = s + init - 1; int anchor = (*p == '^'); if (anchor) { p++; lp--; /* skip anchor character */ } prepstate(&ms, L, s, ls, p, lp); do { const char *res; reprepstate(&ms); if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, (s1 - s) + 1); /* start */ lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else return push_captures(&ms, s1, res); } } while (s1++ < ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } static int str_find (lua_State *L) { return str_find_aux(L, 1); } static int str_match (lua_State *L) { return str_find_aux(L, 0); } /* state for 'gmatch' */ typedef struct GMatchState { const char *src; /* current position */ const char *p; /* pattern */ const char *lastmatch; /* end of last match */ MatchState ms; /* match state */ } GMatchState; static int gmatch_aux (lua_State *L) { GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); const char *src; gm->ms.L = L; for (src = gm->src; src <= gm->ms.src_end; src++) { const char *e; reprepstate(&gm->ms); if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { gm->src = gm->lastmatch = e; return push_captures(&gm->ms, src, e); } } return 0; /* not found */ } static int gmatch (lua_State *L) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); GMatchState *gm; lua_settop(L, 2); /* keep them on closure to avoid being collected */ gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); prepstate(&gm->ms, L, s, ls, p, lp); gm->src = s; gm->p = p; gm->lastmatch = NULL; lua_pushcclosure(L, gmatch_aux, 3); return 1; } static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; lua_State *L = ms->L; const char *news = lua_tolstring(L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) { if (news[i] != L_ESC) luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); luaL_addchar(b, news[i]); } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ lua_remove(L, -2); /* remove original value */ luaL_addvalue(b); /* add capture to accumulated result */ } } } } static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, const char *e, int tr) { lua_State *L = ms->L; switch (tr) { case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); n = push_captures(ms, s, e); lua_call(L, n, 1); break; } case LUA_TTABLE: { push_onecapture(ms, 0, s, e); lua_gettable(L, 3); break; } default: { /* LUA_TNUMBER or LUA_TSTRING */ add_s(ms, b, s, e); return; } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } static int str_gsub (lua_State *L) { size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ const char *lastmatch = NULL; /* end of last match */ int tr = lua_type(L, 3); /* replacement type */ lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ int anchor = (*p == '^'); lua_Integer n = 0; /* replacement count */ MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, "string/function/table expected"); luaL_buffinit(L, &b); if (anchor) { p++; lp--; /* skip anchor character */ } prepstate(&ms, L, src, srcl, p, lp); while (n < max_s) { const char *e; reprepstate(&ms); /* (re)prepare state for new match */ if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ n++; add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ src = lastmatch = e; } else if (src < ms.src_end) /* otherwise, skip one character */ luaL_addchar(&b, *src++); else break; /* end of subject */ if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); lua_pushinteger(L, n); /* number of substitutions */ return 2; } /* }====================================================== */ /* ** {====================================================== ** STRING FORMAT ** ======================================================= */ #if !defined(lua_number2strx) /* { */ /* ** Hexadecimal floating-point formatter */ #include #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) /* ** Number of bits that goes into the first digit. It can be any value ** between 1 and 4; the following definition tries to align the number ** to nibble boundaries by making what is left after that first digit a ** multiple of 4. */ #define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) /* ** Add integer part of 'x' to buffer and return new 'x' */ static lua_Number adddigit (char *buff, int n, lua_Number x) { lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ int d = (int)dd; buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ return x - dd; /* return what is left */ } static int num2straux (char *buff, int sz, lua_Number x) { /* if 'inf' or 'NaN', format it like '%g' */ if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); else if (x == 0) { /* can be -0... */ /* create "0" or "-0" followed by exponent */ return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); } else { int e; lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ int n = 0; /* character count */ if (m < 0) { /* is number negative? */ buff[n++] = '-'; /* add signal */ m = -m; /* make it positive */ } buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ e -= L_NBFD; /* this digit goes before the radix point */ if (m > 0) { /* more digits? */ buff[n++] = lua_getlocaledecpoint(); /* add radix point */ do { /* add as many digits as needed */ m = adddigit(buff, n++, m * 16); } while (m > 0); } n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ lua_assert(n < sz); return n; } } static int lua_number2strx (lua_State *L, char *buff, int sz, const char *fmt, lua_Number x) { int n = num2straux(buff, sz, x); if (fmt[SIZELENMOD] == 'A') { int i; for (i = 0; i < n; i++) buff[i] = toupper(uchar(buff[i])); } else if (fmt[SIZELENMOD] != 'a') luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); return n; } #endif /* } */ /* ** Maximum size of each formatted item. This maximum size is produced ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', ** and '\0') + number of decimal digits to represent maxfloat (which ** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra ** expenses", such as locale-dependent stuff) */ #define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) /* valid flags in a format specification */ #define FLAGS "-+ #0" /* ** maximum size of each format specification (such as "%-099.99d") */ #define MAX_FORMAT 32 static void addquoted (luaL_Buffer *b, const char *s, size_t len) { luaL_addchar(b, '"'); while (len--) { if (*s == '"' || *s == '\\' || *s == '\n') { luaL_addchar(b, '\\'); luaL_addchar(b, *s); } else if (iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); else l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); } /* ** Ensures the 'buff' string uses a dot as the radix character. */ static void checkdp (char *buff, int nb) { if (memchr(buff, '.', nb) == NULL) { /* no dot? */ char point = lua_getlocaledecpoint(); /* try locale point */ char *ppoint = (char *)memchr(buff, point, nb); if (ppoint) *ppoint = '.'; /* change it to a dot */ } } static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { switch (lua_type(L, arg)) { case LUA_TSTRING: { size_t len; const char *s = lua_tolstring(L, arg, &len); addquoted(b, s, len); break; } case LUA_TNUMBER: { char *buff = luaL_prepbuffsize(b, MAX_ITEM); int nb; if (!lua_isinteger(L, arg)) { /* float? */ lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); checkdp(buff, nb); /* ensure it uses a dot */ } else { /* integers */ lua_Integer n = lua_tointeger(L, arg); const char *format = (n == LUA_MININTEGER) /* corner case? */ ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ : LUA_INTEGER_FMT; /* else use default format */ nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); } luaL_addsize(b, nb); break; } case LUA_TNIL: case LUA_TBOOLEAN: { luaL_tolstring(L, arg, NULL); luaL_addvalue(b); break; } default: { luaL_argerror(L, arg, "value has no literal form"); } } } static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); form += (p - strfrmt) + 1; *form = '\0'; return p; } /* ** add length modifier into formats */ static void addlenmod (char *form, const char *lenmod) { size_t l = strlen(form); size_t lm = strlen(lenmod); char spec = form[l - 1]; strcpy(form + l - 1, lenmod); form[l + lm - 1] = spec; form[l + lm] = '\0'; } static int str_format (lua_State *L) { int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) luaL_addchar(&b, *strfrmt++); else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format ('%...') */ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ int nb = 0; /* number of bytes in added item */ if (++arg > top) luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); break; } case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { lua_Integer n = luaL_checkinteger(L, arg); addlenmod(form, LUA_INTEGER_FRMLEN); nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); break; } case 'a': case 'A': addlenmod(form, LUA_NUMBER_FRMLEN); nb = lua_number2strx(L, buff, MAX_ITEM, form, luaL_checknumber(L, arg)); break; case 'e': case 'E': case 'f': case 'g': case 'G': { lua_Number n = luaL_checknumber(L, arg); addlenmod(form, LUA_NUMBER_FRMLEN); nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); break; } case 'q': { addliteral(L, &b, arg); break; } case 's': { size_t l; const char *s = luaL_tolstring(L, arg, &l); if (form[2] == '\0') /* no modifiers? */ luaL_addvalue(&b); /* keep entire string */ else { luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted */ luaL_addvalue(&b); /* keep entire string */ } else { /* format the string into 'buff' */ nb = l_sprintf(buff, MAX_ITEM, form, s); lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ } } break; } default: { /* also treat cases 'pnLlh' */ return luaL_error(L, "invalid option '%%%c' to 'format'", *(strfrmt - 1)); } } lua_assert(nb < MAX_ITEM); luaL_addsize(&b, nb); } } luaL_pushresult(&b); return 1; } /* }====================================================== */ /* ** {====================================================== ** PACK/UNPACK ** ======================================================= */ /* value used for padding */ #if !defined(LUAL_PACKPADBYTE) #define LUAL_PACKPADBYTE 0x00 #endif /* maximum size for the binary representation of an integer */ #define MAXINTSIZE 16 /* number of bits in a character */ #define NB CHAR_BIT /* mask for one character (NB 1's) */ #define MC ((1 << NB) - 1) /* size of a lua_Integer */ #define SZINT ((int)sizeof(lua_Integer)) /* dummy union to get native endianness */ static const union { int dummy; char little; /* true iff machine is little endian */ } nativeendian = {1}; /* dummy structure to get native alignment requirements */ struct cD { char c; union { double d; void *p; lua_Integer i; lua_Number n; } u; }; #define MAXALIGN (offsetof(struct cD, u)) /* ** Union for serializing floats */ typedef union Ftypes { float f; double d; lua_Number n; char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ } Ftypes; /* ** information to pack/unpack stuff */ typedef struct Header { lua_State *L; int islittle; int maxalign; } Header; /* ** options for pack/unpack */ typedef enum KOption { Kint, /* signed integers */ Kuint, /* unsigned integers */ Kfloat, /* floating-point numbers */ Kchar, /* fixed-length strings */ Kstring, /* strings with prefixed length */ Kzstr, /* zero-terminated strings */ Kpadding, /* padding */ Kpaddalign, /* padding for alignment */ Knop /* no-op (configuration or spaces) */ } KOption; /* ** Read an integer numeral from string 'fmt' or return 'df' if ** there is no numeral */ static int digit (int c) { return '0' <= c && c <= '9'; } static int getnum (const char **fmt, int df) { if (!digit(**fmt)) /* no number? */ return df; /* return default value */ else { int a = 0; do { a = a*10 + (*((*fmt)++) - '0'); } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); return a; } } /* ** Read an integer numeral and raises an error if it is larger ** than the maximum size for integers. */ static int getnumlimit (Header *h, const char **fmt, int df) { int sz = getnum(fmt, df); if (sz > MAXINTSIZE || sz <= 0) luaL_error(h->L, "integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE); return sz; } /* ** Initialize Header */ static void initheader (lua_State *L, Header *h) { h->L = L; h->islittle = nativeendian.little; h->maxalign = 1; } /* ** Read and classify next option. 'size' is filled with option's size. */ static KOption getoption (Header *h, const char **fmt, int *size) { int opt = *((*fmt)++); *size = 0; /* default */ switch (opt) { case 'b': *size = sizeof(char); return Kint; case 'B': *size = sizeof(char); return Kuint; case 'h': *size = sizeof(short); return Kint; case 'H': *size = sizeof(short); return Kuint; case 'l': *size = sizeof(long); return Kint; case 'L': *size = sizeof(long); return Kuint; case 'j': *size = sizeof(lua_Integer); return Kint; case 'J': *size = sizeof(lua_Integer); return Kuint; case 'T': *size = sizeof(size_t); return Kuint; case 'f': *size = sizeof(float); return Kfloat; case 'd': *size = sizeof(double); return Kfloat; case 'n': *size = sizeof(lua_Number); return Kfloat; case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; case 'c': *size = getnum(fmt, -1); if (*size == -1) luaL_error(h->L, "missing size for format option 'c'"); return Kchar; case 'z': return Kzstr; case 'x': *size = 1; return Kpadding; case 'X': return Kpaddalign; case ' ': break; case '<': h->islittle = 1; break; case '>': h->islittle = 0; break; case '=': h->islittle = nativeendian.little; break; case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; default: luaL_error(h->L, "invalid format option '%c'", opt); } return Knop; } /* ** Read, classify, and fill other details about the next option. ** 'psize' is filled with option's size, 'notoalign' with its ** alignment requirements. ** Local variable 'size' gets the size to be aligned. (Kpadal option ** always gets its full alignment, other options are limited by ** the maximum alignment ('maxalign'). Kchar option needs no alignment ** despite its size. */ static KOption getdetails (Header *h, size_t totalsize, const char **fmt, int *psize, int *ntoalign) { KOption opt = getoption(h, fmt, psize); int align = *psize; /* usually, alignment follows size */ if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) luaL_argerror(h->L, 1, "invalid next option for option 'X'"); } if (align <= 1 || opt == Kchar) /* need no alignment? */ *ntoalign = 0; else { if (align > h->maxalign) /* enforce maximum alignment */ align = h->maxalign; if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); } return opt; } /* ** Pack integer 'n' with 'size' bytes and 'islittle' endianness. ** The final 'if' handles the case when 'size' is larger than ** the size of a Lua integer, correcting the extra sign-extension ** bytes if necessary (by default they would be zeros). */ static void packint (luaL_Buffer *b, lua_Unsigned n, int islittle, int size, int neg) { char *buff = luaL_prepbuffsize(b, size); int i; buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ for (i = 1; i < size; i++) { n >>= NB; buff[islittle ? i : size - 1 - i] = (char)(n & MC); } if (neg && size > SZINT) { /* negative number need sign extension? */ for (i = SZINT; i < size; i++) /* correct extra bytes */ buff[islittle ? i : size - 1 - i] = (char)MC; } luaL_addsize(b, size); /* add result to buffer */ } /* ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if ** given 'islittle' is different from native endianness. */ static void copywithendian (volatile char *dest, volatile const char *src, int size, int islittle) { if (islittle == nativeendian.little) { while (size-- != 0) *(dest++) = *(src++); } else { dest += size - 1; while (size-- != 0) *(dest--) = *(src++); } } static int str_pack (lua_State *L) { luaL_Buffer b; Header h; const char *fmt = luaL_checkstring(L, 1); /* format string */ int arg = 1; /* current argument to pack */ size_t totalsize = 0; /* accumulate total size of result */ initheader(L, &h); lua_pushnil(L); /* mark to separate arguments from string buffer */ luaL_buffinit(L, &b); while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); totalsize += ntoalign + size; while (ntoalign-- > 0) luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ arg++; switch (opt) { case Kint: { /* signed integers */ lua_Integer n = luaL_checkinteger(L, arg); if (size < SZINT) { /* need overflow check? */ lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); } packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); break; } case Kuint: { /* unsigned integers */ lua_Integer n = luaL_checkinteger(L, arg); if (size < SZINT) /* need overflow check? */ luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), arg, "unsigned overflow"); packint(&b, (lua_Unsigned)n, h.islittle, size, 0); break; } case Kfloat: { /* floating-point options */ volatile Ftypes u; char *buff = luaL_prepbuffsize(&b, size); lua_Number n = luaL_checknumber(L, arg); /* get argument */ if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ else if (size == sizeof(u.d)) u.d = (double)n; else u.n = n; /* move 'u' to final result, correcting endianness if needed */ copywithendian(buff, u.buff, size, h.islittle); luaL_addsize(&b, size); break; } case Kchar: { /* fixed-size string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); luaL_argcheck(L, len <= (size_t)size, arg, "string longer than given size"); luaL_addlstring(&b, s, len); /* add string */ while (len++ < (size_t)size) /* pad extra space */ luaL_addchar(&b, LUAL_PACKPADBYTE); break; } case Kstring: { /* strings with length count */ size_t len; const char *s = luaL_checklstring(L, arg, &len); luaL_argcheck(L, size >= (int)sizeof(size_t) || len < ((size_t)1 << (size * NB)), arg, "string length does not fit in given size"); packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ luaL_addlstring(&b, s, len); totalsize += len; break; } case Kzstr: { /* zero-terminated string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); luaL_addlstring(&b, s, len); luaL_addchar(&b, '\0'); /* add zero at the end */ totalsize += len + 1; break; } case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ case Kpaddalign: case Knop: arg--; /* undo increment */ break; } } luaL_pushresult(&b); return 1; } static int str_packsize (lua_State *L) { Header h; const char *fmt = luaL_checkstring(L, 1); /* format string */ size_t totalsize = 0; /* accumulate total size of result */ initheader(L, &h); while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); size += ntoalign; /* total space used by option */ luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, "format result too large"); totalsize += size; switch (opt) { case Kstring: /* strings with length count */ case Kzstr: /* zero-terminated string */ luaL_argerror(L, 1, "variable-length format"); /* call never return, but to avoid warnings: *//* FALLTHROUGH */ default: break; } } lua_pushinteger(L, (lua_Integer)totalsize); return 1; } /* ** Unpack an integer with 'size' bytes and 'islittle' endianness. ** If size is smaller than the size of a Lua integer and integer ** is signed, must do sign extension (propagating the sign to the ** higher bits); if size is larger than the size of a Lua integer, ** it must check the unread bytes to see whether they do not cause an ** overflow. */ static lua_Integer unpackint (lua_State *L, const char *str, int islittle, int size, int issigned) { lua_Unsigned res = 0; int i; int limit = (size <= SZINT) ? size : SZINT; for (i = limit - 1; i >= 0; i--) { res <<= NB; res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; } if (size < SZINT) { /* real size smaller than lua_Integer? */ if (issigned) { /* needs sign extension? */ lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); res = ((res ^ mask) - mask); /* do sign extension */ } } else if (size > SZINT) { /* must check unread bytes */ int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; for (i = limit; i < size; i++) { if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); } } return (lua_Integer)res; } static int str_unpack (lua_State *L) { Header h; const char *fmt = luaL_checkstring(L, 1); size_t ld; const char *data = luaL_checklstring(L, 2, &ld); size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; int n = 0; /* number of results */ luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); initheader(L, &h); while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) luaL_argerror(L, 2, "data string too short"); pos += ntoalign; /* skip alignment */ /* stack space for item + next position */ luaL_checkstack(L, 2, "too many results"); n++; switch (opt) { case Kint: case Kuint: { lua_Integer res = unpackint(L, data + pos, h.islittle, size, (opt == Kint)); lua_pushinteger(L, res); break; } case Kfloat: { volatile Ftypes u; lua_Number num; copywithendian(u.buff, data + pos, size, h.islittle); if (size == sizeof(u.f)) num = (lua_Number)u.f; else if (size == sizeof(u.d)) num = (lua_Number)u.d; else num = u.n; lua_pushnumber(L, num); break; } case Kchar: { lua_pushlstring(L, data + pos, size); break; } case Kstring: { size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); lua_pushlstring(L, data + pos + size, len); pos += len; /* skip string */ break; } case Kzstr: { size_t len = (int)strlen(data + pos); lua_pushlstring(L, data + pos, len); pos += len + 1; /* skip string plus final '\0' */ break; } case Kpaddalign: case Kpadding: case Knop: n--; /* undo increment */ break; } pos += size; } lua_pushinteger(L, pos + 1); /* next position */ return n + 1; } /* }====================================================== */ static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, {"dump", str_dump}, {"find", str_find}, {"format", str_format}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, {"lower", str_lower}, {"match", str_match}, {"rep", str_rep}, {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, {"pack", str_pack}, {"packsize", str_packsize}, {"unpack", str_unpack}, {NULL, NULL} }; static void createmetatable (lua_State *L) { lua_createtable(L, 0, 1); /* table to be metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); /* copy table */ lua_setmetatable(L, -2); /* set table as metatable for strings */ lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2); /* get string library */ lua_setfield(L, -2, "__index"); /* metatable.__index = string */ lua_pop(L, 1); /* pop metatable */ } /* ** Open string library */ LUAMOD_API int luaopen_string (lua_State *L) { luaL_newlib(L, strlib); createmetatable(L); return 1; } lua-compat53-0.7/ltablib.c000066400000000000000000000323521332200420300153410ustar00rootroot00000000000000/* ** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #define ltablib_c #define LUA_LIB #include "lprefix.h" #include #include #include #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** Operations that an object must define to mimic a table ** (some functions only need some of them) */ #define TAB_R 1 /* read */ #define TAB_W 2 /* write */ #define TAB_L 4 /* length */ #define TAB_RW (TAB_R | TAB_W) /* read/write */ #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) static int checkfield (lua_State *L, const char *key, int n) { lua_pushstring(L, key); return (lua_rawget(L, -n) != LUA_TNIL); } /* ** Check that 'arg' either is a table or can behave like one (that is, ** has a metatable with the required metamethods) */ static void checktab (lua_State *L, int arg, int what) { if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ int n = 1; /* number of elements to pop */ if (lua_getmetatable(L, arg) && /* must have metatable */ (!(what & TAB_R) || checkfield(L, "__index", ++n)) && (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && (!(what & TAB_L) || checkfield(L, "__len", ++n))) { lua_pop(L, n); /* pop metatable and tested metamethods */ } else luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ } } #if defined(LUA_COMPAT_MAXN) static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pop(L, 1); /* remove value */ if (lua_type(L, -1) == LUA_TNUMBER) { lua_Number v = lua_tonumber(L, -1); if (v > max) max = v; } } lua_pushnumber(L, max); return 1; } #endif static int tinsert (lua_State *L) { lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ lua_Integer pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { lua_Integer i; pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ lua_geti(L, 1, i - 1); lua_seti(L, 1, i); /* t[i] = t[i - 1] */ } break; } default: { return luaL_error(L, "wrong number of arguments to 'insert'"); } } lua_seti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { lua_Integer size = aux_getn(L, 1, TAB_RW); lua_Integer pos = luaL_optinteger(L, 2, size); if (pos != size) /* validate 'pos' if given */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); lua_geti(L, 1, pos); /* result = t[pos] */ for ( ; pos < size; pos++) { lua_geti(L, 1, pos + 1); lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ } lua_pushnil(L); lua_seti(L, 1, pos); /* t[pos] = nil */ return 1; } /* ** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever ** possible, copy in increasing order, which is better for rehashing. ** "possible" means destination after original range, or smaller ** than origin, or copying to another table. */ static int tmove (lua_State *L) { lua_Integer f = luaL_checkinteger(L, 2); lua_Integer e = luaL_checkinteger(L, 3); lua_Integer t = luaL_checkinteger(L, 4); int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ checktab(L, 1, TAB_R); checktab(L, tt, TAB_W); if (e >= f) { /* otherwise, nothing to move */ lua_Integer n, i; luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, "too many elements to move"); n = e - f + 1; /* number of elements to move */ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, "destination wrap around"); if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { for (i = 0; i < n; i++) { lua_geti(L, 1, f + i); lua_seti(L, tt, t + i); } } else { for (i = n - 1; i >= 0; i--) { lua_geti(L, 1, f + i); lua_seti(L, tt, t + i); } } } lua_pushvalue(L, tt); /* return destination table */ return 1; } static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { lua_geti(L, 1, i); if (!lua_isstring(L, -1)) luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", luaL_typename(L, -1), i); luaL_addvalue(b); } static int tconcat (lua_State *L) { luaL_Buffer b; lua_Integer last = aux_getn(L, 1, TAB_R); size_t lsep; const char *sep = luaL_optlstring(L, 2, "", &lsep); lua_Integer i = luaL_optinteger(L, 3, 1); last = luaL_optinteger(L, 4, last); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); luaL_addlstring(&b, sep, lsep); } if (i == last) /* add last value (if interval was not empty) */ addfield(L, &b, i); luaL_pushresult(&b); return 1; } /* ** {====================================================== ** Pack/unpack ** ======================================================= */ static int pack (lua_State *L) { int i; int n = lua_gettop(L); /* number of elements to pack */ lua_createtable(L, n, 1); /* create result table */ lua_insert(L, 1); /* put it at index 1 */ for (i = n; i >= 1; i--) /* assign elements */ lua_seti(L, 1, i); lua_pushinteger(L, n); lua_setfield(L, 1, "n"); /* t.n = number of elements */ return 1; /* return table */ } static int unpack (lua_State *L) { lua_Unsigned n; lua_Integer i = luaL_optinteger(L, 2, 1); lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) return luaL_error(L, "too many results to unpack"); for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ lua_geti(L, 1, i); } lua_geti(L, 1, e); /* push last element */ return (int)n; } /* }====================================================== */ /* ** {====================================================== ** Quicksort ** (based on 'Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) ** ======================================================= */ /* type for array indices */ typedef unsigned int IdxT; /* ** Produce a "random" 'unsigned int' to randomize pivot choice. This ** macro is used only when 'sort' detects a big imbalance in the result ** of a partition. (If you don't want/need this "randomness", ~0 is a ** good choice.) */ #if !defined(l_randomizePivot) /* { */ #include /* size of 'e' measured in number of 'unsigned int's */ #define sof(e) (sizeof(e) / sizeof(unsigned int)) /* ** Use 'time' and 'clock' as sources of "randomness". Because we don't ** know the types 'clock_t' and 'time_t', we cannot cast them to ** anything without risking overflows. A safe way to use their values ** is to copy them to an array of a known type and use the array values. */ static unsigned int l_randomizePivot (void) { clock_t c = clock(); time_t t = time(NULL); unsigned int buff[sof(c) + sof(t)]; unsigned int i, rnd = 0; memcpy(buff, &c, sof(c) * sizeof(unsigned int)); memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); for (i = 0; i < sof(buff); i++) rnd += buff[i]; return rnd; } #endif /* } */ /* arrays larger than 'RANLIMIT' may use randomized pivots */ #define RANLIMIT 100u static void set2 (lua_State *L, IdxT i, IdxT j) { lua_seti(L, 1, i); lua_seti(L, 1, j); } /* ** Return true iff value at stack index 'a' is less than the value at ** index 'b' (according to the order of the sort). */ static int sort_comp (lua_State *L, int a, int b) { if (lua_isnil(L, 2)) /* no function? */ return lua_compare(L, a, b, LUA_OPLT); /* a < b */ else { /* function */ int res; lua_pushvalue(L, 2); /* push function */ lua_pushvalue(L, a-1); /* -1 to compensate function */ lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ lua_call(L, 2, 1); /* call function */ res = lua_toboolean(L, -1); /* get result */ lua_pop(L, 1); /* pop result */ return res; } } /* ** Does the partition: Pivot P is at the top of the stack. ** precondition: a[lo] <= P == a[up-1] <= a[up], ** so it only needs to do the partition from lo + 1 to up - 2. ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** returns 'i'. */ static IdxT partition (lua_State *L, IdxT lo, IdxT up) { IdxT i = lo; /* will be incremented before first use */ IdxT j = up - 1; /* will be decremented before first use */ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ for (;;) { /* next loop: repeat ++i while a[i] < P */ while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ /* next loop: repeat --j while P < a[j] */ while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { if (j < i) /* j < i but a[j] > P ?? */ luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[j] */ } /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ if (j < i) { /* no elements out of place? */ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ lua_pop(L, 1); /* pop a[j] */ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ set2(L, up - 1, i); return i; } /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ set2(L, i, j); } } /* ** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** "randomized" by 'rnd' */ static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { IdxT r4 = (up - lo) / 4; /* range/4 */ IdxT p = rnd % (r4 * 2) + (lo + r4); lua_assert(lo + r4 <= p && p <= up - r4); return p; } /* ** QuickSort algorithm (recursive function) */ static void auxsort (lua_State *L, IdxT lo, IdxT up, unsigned int rnd) { while (lo < up) { /* loop for tail recursion */ IdxT p; /* Pivot index */ IdxT n; /* to be used later */ /* sort elements 'lo', 'p', and 'up' */ lua_geti(L, 1, lo); lua_geti(L, 1, up); if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ set2(L, lo, up); /* swap a[lo] - a[up] */ else lua_pop(L, 2); /* remove both values */ if (up - lo == 1) /* only 2 elements? */ return; /* already sorted */ if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ p = (lo + up)/2; /* middle element is a good pivot */ else /* for larger intervals, it is worth a random pivot */ p = choosePivot(lo, up, rnd); lua_geti(L, 1, p); lua_geti(L, 1, lo); if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ set2(L, p, lo); /* swap a[p] - a[lo] */ else { lua_pop(L, 1); /* remove a[lo] */ lua_geti(L, 1, up); if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ set2(L, p, up); /* swap a[up] - a[p] */ else lua_pop(L, 2); } if (up - lo == 2) /* only 3 elements? */ return; /* already sorted */ lua_geti(L, 1, p); /* get middle element (Pivot) */ lua_pushvalue(L, -1); /* push Pivot */ lua_geti(L, 1, up - 1); /* push a[up - 1] */ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ p = partition(L, lo, up); /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ if (p - lo < up - p) { /* lower interval is smaller? */ auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ n = p - lo; /* size of smaller interval */ lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ } else { auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ n = up - p; /* size of smaller interval */ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ } if ((up - lo) / 128 > n) /* partition too imbalanced? */ rnd = l_randomizePivot(); /* try a new randomization */ } /* tail call auxsort(L, lo, up, rnd) */ } static int sort (lua_State *L) { lua_Integer n = aux_getn(L, 1, TAB_RW); if (n > 1) { /* non-trivial interval? */ luaL_argcheck(L, n < INT_MAX, 1, "array too big"); if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ lua_settop(L, 2); /* make sure there are two arguments */ auxsort(L, 1, (IdxT)n, 0); } return 0; } /* }====================================================== */ static const luaL_Reg tab_funcs[] = { {"concat", tconcat}, #if defined(LUA_COMPAT_MAXN) {"maxn", maxn}, #endif {"insert", tinsert}, {"pack", pack}, {"unpack", unpack}, {"remove", tremove}, {"move", tmove}, {"sort", sort}, {NULL, NULL} }; LUAMOD_API int luaopen_table (lua_State *L) { luaL_newlib(L, tab_funcs); #if defined(LUA_COMPAT_UNPACK) /* _G.unpack = table.unpack */ lua_getfield(L, -1, "unpack"); lua_setglobal(L, "unpack"); #endif return 1; } lua-compat53-0.7/lutf8lib.c000066400000000000000000000156301332200420300154610ustar00rootroot00000000000000/* ** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $ ** Standard library for UTF-8 manipulation ** See Copyright Notice in lua.h */ #define lutf8lib_c #define LUA_LIB #include "lprefix.h" #include #include #include #include #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define MAXUNICODE 0x10FFFF #define iscont(p) ((*(p) & 0xC0) == 0x80) /* from strlib */ /* translate a relative string position: negative means back from end */ static lua_Integer u_posrelat (lua_Integer pos, size_t len) { if (pos >= 0) return pos; else if (0u - (size_t)pos > len) return 0; else return (lua_Integer)len + pos + 1; } /* ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. */ static const char *utf8_decode (const char *o, int *val) { static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; const unsigned char *s = (const unsigned char *)o; unsigned int c = s[0]; unsigned int res = 0; /* final result */ if (c < 0x80) /* ascii? */ res = c; else { int count = 0; /* to count number of continuation bytes */ while (c & 0x40) { /* still have continuation bytes? */ int cc = s[++count]; /* read next byte */ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ return NULL; /* invalid byte sequence */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ c <<= 1; /* to test next bit */ } res |= ((c & 0x7F) << (count * 5)); /* add first byte */ if (count > 3 || res > MAXUNICODE || res <= limits[count]) return NULL; /* invalid byte sequence */ s += count; /* skip continuation bytes read */ } if (val) *val = res; return (const char *)s + 1; /* +1 to include first byte */ } /* ** utf8len(s [, i [, j]]) --> number of characters that start in the ** range [i,j], or nil + current position if 's' is not well formed in ** that interval */ static int utflen (lua_State *L) { int n = 0; size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, "initial position out of string"); luaL_argcheck(L, --posj < (lua_Integer)len, 3, "final position out of string"); while (posi <= posj) { const char *s1 = utf8_decode(s + posi, NULL); if (s1 == NULL) { /* conversion error? */ lua_pushnil(L); /* return nil ... */ lua_pushinteger(L, posi + 1); /* ... and current position */ return 2; } posi = s1 - s; n++; } lua_pushinteger(L, n); return 1; } /* ** codepoint(s, [i, [j]]) -> returns codepoints for all characters ** that start in the range [i,j] */ static int codepoint (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); int n; const char *se; luaL_argcheck(L, posi >= 1, 2, "out of range"); luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ return luaL_error(L, "string slice too long"); n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); n = 0; se = s + pose; for (s += posi - 1; s < se;) { int code; s = utf8_decode(s, &code); if (s == NULL) return luaL_error(L, "invalid UTF-8 code"); lua_pushinteger(L, code); n++; } return n; } static void pushutfchar (lua_State *L, int arg) { lua_Integer code = luaL_checkinteger(L, arg); luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); lua_pushfstring(L, "%U", (long)code); } /* ** utfchar(n1, n2, ...) -> char(n1)..char(n2)... */ static int utfchar (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ if (n == 1) /* optimize common case of single char */ pushutfchar(L, 1); else { int i; luaL_Buffer b; luaL_buffinit(L, &b); for (i = 1; i <= n; i++) { pushutfchar(L, i); luaL_addvalue(&b); } luaL_pushresult(&b); } return 1; } /* ** offset(s, n, [i]) -> index where n-th character counting from ** position 'i' starts; 0 means character at 'i'. */ static int byteoffset (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer n = luaL_checkinteger(L, 2); lua_Integer posi = (n >= 0) ? 1 : len + 1; posi = u_posrelat(luaL_optinteger(L, 3, posi), len); luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, "position out of range"); if (n == 0) { /* find beginning of current byte sequence */ while (posi > 0 && iscont(s + posi)) posi--; } else { if (iscont(s + posi)) luaL_error(L, "initial position is a continuation byte"); if (n < 0) { while (n < 0 && posi > 0) { /* move back */ do { /* find beginning of previous character */ posi--; } while (posi > 0 && iscont(s + posi)); n++; } } else { n--; /* do not move for 1st character */ while (n > 0 && posi < (lua_Integer)len) { do { /* find beginning of next character */ posi++; } while (iscont(s + posi)); /* (cannot pass final '\0') */ n--; } } } if (n == 0) /* did it find given character? */ lua_pushinteger(L, posi + 1); else /* no such character */ lua_pushnil(L); return 1; } static int iter_aux (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer n = lua_tointeger(L, 2) - 1; if (n < 0) /* first iteration? */ n = 0; /* start from here */ else if (n < (lua_Integer)len) { n++; /* skip current byte */ while (iscont(s + n)) n++; /* and its continuations */ } if (n >= (lua_Integer)len) return 0; /* no more codepoints */ else { int code; const char *next = utf8_decode(s + n, &code); if (next == NULL || iscont(next)) return luaL_error(L, "invalid UTF-8 code"); lua_pushinteger(L, n + 1); lua_pushinteger(L, code); return 2; } } static int iter_codes (lua_State *L) { luaL_checkstring(L, 1); lua_pushcfunction(L, iter_aux); lua_pushvalue(L, 1); lua_pushinteger(L, 0); return 3; } /* pattern to match a single UTF-8 character */ #define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" static const luaL_Reg funcs[] = { {"offset", byteoffset}, {"codepoint", codepoint}, {"char", utfchar}, {"len", utflen}, {"codes", iter_codes}, /* placeholders */ {"charpattern", NULL}, {NULL, NULL} }; LUAMOD_API int luaopen_utf8 (lua_State *L) { luaL_newlib(L, funcs); lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); lua_setfield(L, -2, "charpattern"); return 1; } lua-compat53-0.7/rockspecs/000077500000000000000000000000001332200420300155535ustar00rootroot00000000000000lua-compat53-0.7/rockspecs/compat53-0.1-1.rockspec000066400000000000000000000016721332200420300214010ustar00rootroot00000000000000package = "compat53" version = "0.1-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.1.zip", dir = "lua-compat-5.3-0.1", } description = { summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", detailed = [[ This is a small module that aims to make it easier to write Lua code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. It does *not* make Lua 5.2 (or even 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. ]], homepage = "https://github.com/keplerproject/lua-compat-5.3", license = "MIT" } dependencies = { "lua >= 5.1, < 5.4", --"struct" -- make Roberto's struct module optional } build = { type = "builtin", modules = { ["compat53"] = "compat53.lua", ["compat53.utf8"] = "lutf8lib.c", ["compat53.table"] = "ltablib.c", ["compat53.string"] = "lstrlib.c", } } lua-compat53-0.7/rockspecs/compat53-0.2-1.rockspec000066400000000000000000000017671332200420300214070ustar00rootroot00000000000000package = "compat53" version = "0.2-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.2.zip", dir = "lua-compat-5.3-0.2", } description = { summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", detailed = [[ This is a small module that aims to make it easier to write Lua code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. It does *not* make Lua 5.2 (or even 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. ]], homepage = "https://github.com/keplerproject/lua-compat-5.3", license = "MIT" } dependencies = { "lua >= 5.1, < 5.4", --"struct" -- make Roberto's struct module optional } build = { type = "builtin", modules = { ["compat53.init"] = "compat53/init.lua", ["compat53.module"] = "compat53/module.lua", ["compat53.utf8"] = "lutf8lib.c", ["compat53.table"] = "ltablib.c", ["compat53.string"] = "lstrlib.c", } } lua-compat53-0.7/rockspecs/compat53-0.3-1.rockspec000066400000000000000000000017671332200420300214100ustar00rootroot00000000000000package = "compat53" version = "0.3-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.3.zip", dir = "lua-compat-5.3-0.3", } description = { summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", detailed = [[ This is a small module that aims to make it easier to write Lua code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. It does *not* make Lua 5.2 (or even 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. ]], homepage = "https://github.com/keplerproject/lua-compat-5.3", license = "MIT" } dependencies = { "lua >= 5.1, < 5.4", --"struct" -- make Roberto's struct module optional } build = { type = "builtin", modules = { ["compat53.init"] = "compat53/init.lua", ["compat53.module"] = "compat53/module.lua", ["compat53.utf8"] = "lutf8lib.c", ["compat53.table"] = "ltablib.c", ["compat53.string"] = "lstrlib.c", } } lua-compat53-0.7/rockspecs/compat53-0.4-1.rockspec000066400000000000000000000017671332200420300214110ustar00rootroot00000000000000package = "compat53" version = "0.4-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.4.zip", dir = "lua-compat-5.3-0.4", } description = { summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", detailed = [[ This is a small module that aims to make it easier to write Lua code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. It does *not* make Lua 5.2 (or even 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. ]], homepage = "https://github.com/keplerproject/lua-compat-5.3", license = "MIT" } dependencies = { "lua >= 5.1, < 5.4", --"struct" -- make Roberto's struct module optional } build = { type = "builtin", modules = { ["compat53.init"] = "compat53/init.lua", ["compat53.module"] = "compat53/module.lua", ["compat53.utf8"] = "lutf8lib.c", ["compat53.table"] = "ltablib.c", ["compat53.string"] = "lstrlib.c", } } lua-compat53-0.7/rockspecs/compat53-0.5-1.rockspec000066400000000000000000000017671332200420300214120ustar00rootroot00000000000000package = "compat53" version = "0.5-1" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.5.zip", dir = "lua-compat-5.3-0.5", } description = { summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", detailed = [[ This is a small module that aims to make it easier to write Lua code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. It does *not* make Lua 5.2 (or even 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. ]], homepage = "https://github.com/keplerproject/lua-compat-5.3", license = "MIT" } dependencies = { "lua >= 5.1, < 5.4", --"struct" -- make Roberto's struct module optional } build = { type = "builtin", modules = { ["compat53.init"] = "compat53/init.lua", ["compat53.module"] = "compat53/module.lua", ["compat53.utf8"] = "lutf8lib.c", ["compat53.table"] = "ltablib.c", ["compat53.string"] = "lstrlib.c", } } lua-compat53-0.7/rockspecs/compat53-scm-0.rockspec000066400000000000000000000017741332200420300216670ustar00rootroot00000000000000package = "compat53" version = "scm-0" source = { url = "https://github.com/keplerproject/lua-compat-5.3/archive/master.zip", dir = "lua-compat-5.3-master", } description = { summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", detailed = [[ This is a small module that aims to make it easier to write Lua code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. It does *not* make Lua 5.2 (or even 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3. ]], homepage = "https://github.com/keplerproject/lua-compat-5.3", license = "MIT" } dependencies = { "lua >= 5.1, < 5.4", --"struct" -- make Roberto's struct module optional } build = { type = "builtin", modules = { ["compat53.init"] = "compat53/init.lua", ["compat53.module"] = "compat53/module.lua", ["compat53.utf8"] = "lutf8lib.c", ["compat53.table"] = "ltablib.c", ["compat53.string"] = "lstrlib.c", } } lua-compat53-0.7/tests/000077500000000000000000000000001332200420300147215ustar00rootroot00000000000000lua-compat53-0.7/tests/test.lua000077500000000000000000000560771332200420300164250ustar00rootroot00000000000000#!/usr/bin/env lua local F, tproxy, writefile, noprint, ___ do local type, unpack = type, table.unpack or unpack local assert, io = assert, io function F(...) local args, n = { ... }, select('#', ...) for i = 1, n do local t = type(args[i]) if t ~= "string" and t ~= "number" and t ~= "boolean" then args[i] = t end end return unpack(args, 1, n) end function tproxy(t) return setmetatable({}, { __index = t, __newindex = t, __len = function() return #t end, }), t end function writefile(name, contents, bin) local f = assert(io.open(name, bin and "wb" or "w")) f:write(contents) f:close() end function noprint() end local sep = ("="):rep(70) function ___() print(sep) end end local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") if jit then V = "jit" end local mode = "global" if arg[1] == "module" then mode = "module" end local self = arg[0] package.path = "../?.lua;../?/init.lua" package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" if mode == "module" then print("testing Lua API using `compat53.module` ...") _ENV = require("compat53.module") if setfenv then setfenv(1, _ENV) end else print("testing Lua API using `compat53` ...") require("compat53") end ___'' do print("assert", F(pcall(assert, false))) print("assert", F(pcall(assert, false, nil))) print("assert", F(pcall(assert, false, "error msg"))) print("assert", F(pcall(assert, nil, {}))) print("assert", F(pcall(assert, 1, 2, 3))) end ___'' do local t = setmetatable({}, { __index = { 1, false, "three" } }) for i,v in ipairs(t) do print("ipairs", i, v) end end ___'' do local p, t = tproxy{ "a", "b", "c" } print("table.concat", table.concat(p)) print("table.concat", table.concat(p, ",", 2)) print("table.concat", table.concat(p, ".", 1, 2)) print("table.concat", table.concat(t)) print("table.concat", table.concat(t, ",", 2)) print("table.concat", table.concat(t, ".", 1, 2)) end ___'' do local p, t = tproxy{ "a", "b", "c" } table.insert(p, "d") print("table.insert", next(p), t[4]) table.insert(p, 1, "z") print("table.insert", next(p), t[1], t[2]) table.insert(p, 2, "y") print("table.insert", next(p), t[1], t[2], p[3]) t = { "a", "b", "c" } table.insert(t, "d") print("table.insert", t[1], t[2], t[3], t[4]) table.insert(t, 1, "z") print("table.insert", t[1], t[2], t[3], t[4], t[5]) table.insert(t, 2, "y") print("table.insert", t[1], t[2], t[3], t[4], t[5]) end ___'' do local ps, s = tproxy{ "a", "b", "c", "d" } local pd, d = tproxy{ "A", "B", "C", "D" } table.move(ps, 1, 4, 1, pd) print("table.move", next(pd), d[1], d[2], d[3], d[4]) pd, d = tproxy{ "A", "B", "C", "D" } table.move(ps, 2, 4, 1, pd) print("table.move", next(pd), d[1], d[2], d[3], d[4]) pd, d = tproxy{ "A", "B", "C", "D" } table.move(ps, 2, 3, 4, pd) print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5]) table.move(ps, 2, 4, 1) print("table.move", next(ps), s[1], s[2], s[3], s[4]) ps, s = tproxy{ "a", "b", "c", "d" } table.move(ps, 2, 3, 4) print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5]) s = { "a", "b", "c", "d" } d = { "A", "B", "C", "D" } table.move(s, 1, 4, 1, d) print("table.move", d[1], d[2], d[3], d[4]) d = { "A", "B", "C", "D" } table.move(s, 2, 4, 1, d) print("table.move", d[1], d[2], d[3], d[4]) d = { "A", "B", "C", "D" } table.move(s, 2, 3, 4, d) print("table.move", d[1], d[2], d[3], d[4], d[5]) table.move(s, 2, 4, 1) print("table.move", s[1], s[2], s[3], s[4]) s = { "a", "b", "c", "d" } table.move(s, 2, 3, 4) print("table.move", s[1], s[2], s[3], s[4], s[5]) end ___'' do local p, t = tproxy{ "a", "b", "c", "d", "e" } print("table.remove", table.remove(p)) print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5]) print("table.remove", table.remove(p, 1)) print("table.remove", next(p), t[1], t[2], t[3], t[4]) print("table.remove", table.remove(p, 2)) print("table.remove", next(p), t[1], t[2], t[3]) print("table.remove", table.remove(p, 3)) print("table.remove", next(p), t[1], t[2], t[3]) p, t = tproxy{} print("table.remove", table.remove(p)) print("table.remove", next(p), next(t)) t = { "a", "b", "c", "d", "e" } print("table.remove", table.remove(t)) print("table.remove", t[1], t[2], t[3], t[4], t[5]) print("table.remove", table.remove(t, 1)) print("table.remove", t[1], t[2], t[3], t[4]) print("table.remove", table.remove(t, 2)) print("table.remove", t[1], t[2], t[3]) print("table.remove", table.remove(t, 3)) print("table.remove", t[1], t[2], t[3]) t = {} print("table.remove", table.remove(t)) print("table.remove", next(t)) end ___'' do local p, t = tproxy{ 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } table.sort(p) print("table.sort", next(p)) for i,v in ipairs(t) do print("table.sort", i, v) end table.sort(p) print("table.sort", next(p)) for i,v in ipairs(t) do print("table.sort", i, v) end p, t = tproxy{ 9, 8, 7, 6, 5, 4, 3, 2, 1 } table.sort(p) print("table.sort", next(p)) for i,v in ipairs(t) do print("table.sort", i, v) end table.sort(p, function(a, b) return a > b end) print("table.sort", next(p)) for i,v in ipairs(t) do print("table.sort", i, v) end p, t = tproxy{ 1, 1, 1, 1, 1 } print("table.sort", next(p)) for i,v in ipairs(t) do print("table.sort", i, v) end t = { 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } table.sort(t) for i,v in ipairs(t) do print("table.sort", i, v) end table.sort(t, function(a, b) return a > b end) for i,v in ipairs(t) do print("table.sort", i, v) end end ___'' do local p, t = tproxy{ "a", "b", "c" } print("table.unpack", table.unpack(p)) print("table.unpack", table.unpack(p, 2)) print("table.unpack", table.unpack(p, 1, 2)) print("table.unpack", table.unpack(t)) print("table.unpack", table.unpack(t, 2)) print("table.unpack", table.unpack(t, 1, 2)) end ___'' print("math.maxinteger", math.maxinteger+1 > math.maxinteger) print("math.mininteger", math.mininteger-1 < math.mininteger) ___'' print("math.tointeger", math.tointeger(0)) print("math.tointeger", math.tointeger(math.pi)) print("math.tointeger", math.tointeger("hello")) print("math.tointeger", math.tointeger(math.maxinteger+2.0)) print("math.tointeger", math.tointeger(math.mininteger*2.0)) ___'' print("math.type", math.type(0)) print("math.type", math.type(math.pi)) print("math.type", math.type("hello")) ___'' print("math.ult", math.ult(1, 2), math.ult(2, 1)) print("math.ult", math.ult(-1, 2), math.ult(2, -1)) print("math.ult", math.ult(-1, -2), math.ult(-2, -1)) print("math.ult", pcall(math.ult, "x", 2)) print("math.ult", pcall(math.ult, 1, 2.1)) ___'' if utf8.len then local unpack = table.unpack or unpack local function utf8rt(s) local t = { utf8.codepoint(s, 1, #s) } local ps, cs = {}, {} for p,c in utf8.codes(s) do ps[#ps+1], cs[#cs+1] = p, c end print("utf8.codes", unpack(ps)) print("utf8.codes", unpack(cs)) print("utf8.codepoint", unpack(t)) print("utf8.len", utf8.len(s), #t, #s) print("utf8.char", utf8.char(unpack(t))) end utf8rt("äöüßÄÖÜ") utf8rt("abcdefg") ___'' local s = "äöüßÄÖÜ" print("utf8.offset", utf8.offset(s, 1, 1)) print("utf8.offset", utf8.offset(s, 2, 1)) print("utf8.offset", utf8.offset(s, 3, 1)) print("utf8.offset", pcall(utf8.offset, s, 3, 2)) print("utf8.offset", utf8.offset(s, 3, 3)) print("utf8.offset", utf8.offset(s, -1, 7)) print("utf8.offset", utf8.offset(s, -2, 7)) print("utf8.offset", utf8.offset(s, -3, 7)) print("utf8.offset", utf8.offset(s, -1)) ___'' else print("XXX: utf8 module not available") end if string.pack then local format = "bBhHlLjJdc3z" local s = string.pack(format, -128, 255, -32768, 65535, -2147483648, 4294967295, -32768, 65536, 1.25, "abc", "defgh") print("string.unpack", string.unpack(format, s)) ___'' else print("XXX: string packing not available") end print("testing Lua API for Lua 5.1 ...") ___'' print("debug.getuservalue()", F(debug.getuservalue(false))) print("debug.setuservalue()", pcall(function() debug.setuservalue(false, {}) end)) print("debug.setmetatable()", F(debug.setmetatable({}, {}))) ___'' do local t = setmetatable({}, { __pairs = function() return pairs({ a = "a" }) end, }) for k,v in pairs(t) do print("pairs()", k, v) end end ___'' do local code = "print('hello world')\n" local badcode = "print('blub\n" print("load()", pcall(function() load(true) end)) print("load()", F(load(badcode))) print("load()", F(load(code))) print("load()", F(load(code, "[L]"))) print("load()", F(load(code, "[L]", "b"))) print("load()", F(load(code, "[L]", "t"))) print("load()", F(load(code, "[L]", "bt"))) local f = load(code, "[L]", "bt", {}) print("load()", pcall(f)) f = load(code, "[L]", "bt", { print = noprint }) print("load()", pcall(f)) local bytecode = string.dump(f) print("load()", F(load(bytecode))) print("load()", F(load(bytecode, "[L]"))) print("load()", F(load(bytecode, "[L]", "b"))) print("load()", F(load(bytecode, "[L]", "t"))) print("load()", F(load(bytecode, "[L]", "bt"))) f = load(bytecode, "[L]", "bt", {}) print("load()", pcall(f)) f = load(bytecode, "[L]", "bt", { print = noprint }) print("load()", pcall(f)) local function make_loader(code) local mid = math.floor( #code/2 ) local array = { code:sub(1, mid), code:sub(mid+1) } local i = 0 return function() i = i + 1 return array[i] end end print("load()", F(load(make_loader(badcode)))) print("load()", F(load(make_loader(code)))) print("load()", F(load(make_loader(code), "[L]"))) print("load()", F(load(make_loader(code), "[L]", "b"))) print("load()", F(load(make_loader(code), "[L]", "t"))) print("load()", F(load(make_loader(code), "[L]", "bt"))) f = load(make_loader(code), "[L]", "bt", {}) print("load()", pcall(f)) f = load(make_loader(code), "[L]", "bt", { print = noprint }) print("load()", pcall(f)) print("load()", F(load(make_loader(bytecode)))) print("load()", F(load(make_loader(bytecode), "[L]"))) print("load()", F(load(make_loader(bytecode), "[L]", "b"))) print("load()", F(load(make_loader(bytecode), "[L]", "t"))) print("load()", F(load(make_loader(bytecode), "[L]", "bt"))) f = load(make_loader(bytecode), "[L]", "bt", {}) print("load()", pcall(f)) f = load(make_loader(bytecode), "[L]", "bt", { print = noprint }) print("load()", pcall(f)) writefile("good.lua", code) writefile("bad.lua", badcode) writefile("good.luac", bytecode, true) print("loadfile()", F(loadfile("bad.lua"))) print("loadfile()", F(loadfile("good.lua"))) print("loadfile()", F(loadfile("good.lua", "b"))) print("loadfile()", F(loadfile("good.lua", "t"))) print("loadfile()", F(loadfile("good.lua", "bt"))) f = loadfile("good.lua", "bt", {}) print("loadfile()", pcall(f)) f = loadfile("good.lua", "bt", { print = noprint }) print("loadfile()", pcall(f)) print("loadfile()", F(loadfile("good.luac"))) print("loadfile()", F(loadfile("good.luac", "b"))) print("loadfile()", F(loadfile("good.luac", "t"))) print("loadfile()", F(loadfile("good.luac", "bt"))) f = loadfile("good.luac", "bt", {}) print("loadfile()", pcall(f)) f = loadfile("good.luac", "bt", { print = noprint }) print("loadfile()", pcall(f)) os.remove("good.lua") os.remove("bad.lua") os.remove("good.luac") end ___'' do local function func(throw) if throw then error("argh") else return 1, 2, 3 end end local function tb(err) return "|"..err.."|" end print("xpcall()", xpcall(func, debug.traceback, false)) print("xpcall()", xpcall(func, debug.traceback, true)) print("xpcall()", xpcall(func, tb, true)) if mode ~= "module" then local function func2(cb) print("xpcall()", xpcall(cb, debug.traceback, "str")) end local function func3(cb) print("pcall()", pcall(cb, "str")) end local function cb(arg) coroutine.yield(2) return arg end local c = coroutine.wrap(func2) print("xpcall()", c(cb)) print("xpcall()", c()) local c = coroutine.wrap(func3) print("pcall()", c(cb)) print("pcall()", c()) end end ___'' do local t = setmetatable({ 1 }, { __len = function() return 5 end }) print("rawlen()", rawlen(t), rawlen("123")) end ___'' print("os.execute()", os.execute("exit 1")) io.flush() print("os.execute()", os.execute("echo 'hello world!'")) io.flush() print("os.execute()", os.execute("no_such_file")) ___'' do local t = table.pack("a", nil, "b", nil) print("table.(un)pack()", t.n, table.unpack(t, 1, t.n)) end ___'' do print("coroutine.running()", F(coroutine.wrap(function() return coroutine.running() end)())) print("coroutine.running()", F(coroutine.running())) local main_co, co1, co2 = coroutine.running() -- coroutine.yield if mode ~= "module" then print("coroutine.yield()", pcall(function() coroutine.yield(1, 2, 3) end)) end print("coroutine.yield()", coroutine.wrap(function() coroutine.yield(1, 2, 3) end)()) print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3)) co1 = coroutine.create(function(a, b, c) print("coroutine.resume()", a, b, c) return a, b, c end) print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3)) co1 = coroutine.create(function() print("coroutine.status()", "[co1] main is", coroutine.status(main_co)) print("coroutine.status()", "[co1] co2 is", coroutine.status(co2)) end) co2 = coroutine.create(function() print("coroutine.status()", "[co2] main is", coroutine.status(main_co)) print("coroutine.status()", "[co2] co2 is", coroutine.status(co2)) coroutine.yield() coroutine.resume(co1) end) print("coroutine.status()", coroutine.status(main_co)) print("coroutine.status()", coroutine.status(co2)) coroutine.resume(co2) print("coroutine.status()", F(coroutine.status(co2))) coroutine.resume(co2) print("coroutine.status()", F(coroutine.status(co2))) end ___'' print("math.log()", math.log(1000)) print("math.log()", math.log(1000, 10)) ___'' do local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" print(prefix, package.searchpath("no.such.module", path)) print(prefix, package.searchpath("no.such.module", "")) print(prefix, package.searchpath("compat53", path)) print(prefix, package.searchpath("no:such:module", path, ":", "|")) end ___'' if mode ~= "module" then local function mod_func() return {} end local function my_searcher(name) if name == "my.module" then print("package.searchers", "my.module found") return mod_func end end local function my_searcher2(name) if name == "my.module" then print("package.searchers", "my.module found 2") return mod_func end end table.insert(package.searchers, my_searcher) require("my.module") package.loaded["my.module"] = nil local new_s = { my_searcher2 } for i,f in ipairs(package.searchers) do new_s[i+1] = f end package.searchers = new_s require("my.module") end ___'' do print("string.find()", string.find("abc\0abc\0abc", "[^a\0]+")) print("string.find()", string.find("abc\0abc\0abc", "%w+\0", 5)) for x in string.gmatch("abc\0def\0ghi", "[^\0]+") do print("string.gmatch()", x) end for x in string.gmatch("abc\0def\0ghi", "%w*\0") do print("string.gmatch()", #x) end print("string.gsub()", string.gsub("abc\0def\0ghi", "[\0]", "X")) print("string.gsub()", string.gsub("abc\0def\0ghi", "%w*\0", "X")) print("string.gsub()", string.gsub("abc\0def\0ghi", "%A", "X")) print("string.match()", string.match("abc\0abc\0abc", "([^\0a]+)")) print("string.match()", #string.match("abc\0abc\0abc", ".*\0")) print("string.rep()", string.rep("a", 0)) print("string.rep()", string.rep("b", 1)) print("string.rep()", string.rep("c", 4)) print("string.rep()", string.rep("a", 0, "|")) print("string.rep()", string.rep("b", 1, "|")) print("string.rep()", string.rep("c", 4, "|")) local _tostring = tostring function tostring(v) if type(v) == "number" then return "(".._tostring(v)..")" else return _tostring(v) end end print("string.format()", string.format("%q", "\"\\\0000\0010\002\r\n0\t0\"")) print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {})) print("string.format()", string.format("%-3f %%%s %%s", 3.1, true)) print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil)) print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout)) print("string.format()", pcall(function() print("string.format()", string.format("%d %%s", {})) end)) tostring = _tostring end ___'' do print("io.write()", io.type(io.write("hello world\n"))) local f = assert(io.tmpfile()) print("file:write()", io.type(f:write("hello world\n"))) f:close() end ___'' do writefile("data.txt", "123 18.8 hello world\ni'm here\n") io.input("data.txt") print("io.read()", io.read("*n", "*number", "*l", "*a")) io.input("data.txt") print("io.read()", io.read("n", "number", "l", "a")) io.input(io.stdin) if mode ~= "module" then local f = assert(io.open("data.txt", "r")) print("file:read()", f:read("*n", "*number", "*l", "*a")) f:close() f = assert(io.open("data.txt", "r")) print("file:read()", f:read("n", "number", "l", "a")) f:close() end os.remove("data.txt") end ___'' do writefile("data.txt", "123 18.8 hello world\ni'm here\n") for a,b in io.lines(self, 2, "*l") do print("io.lines()", a, b) break end for l in io.lines(self) do print("io.lines()", l) break end for n1,n2,rest in io.lines("data.txt", "*n", "n", "*a") do print("io.lines()", n1, n2, rest) end for l in io.lines("data.txt") do print("io.lines()", l) end print("io.lines()", pcall(function() for l in io.lines("data.txt", "*x") do print(l) end end)) print("io.lines()", pcall(function() for l in io.lines("no_such_file.txt") do print(l) end end)) if mode ~= "module" then local f = assert(io.open(self, "r")) for a,b in f:lines(2, "*l") do print("file:lines()", a, b) break end f:close() f = assert(io.open("data.txt", "r")) for n1,n2,rest in f:lines("*n", "n", "*a") do print("file:lines()", n1, n2, rest) end f:close() f = assert(io.open("data.txt", "r")) for l in f:lines() do print("file:lines()", l) end f:close() print("file:lines()", pcall(function() for l in f:lines() do print(l) end end)) print("file:lines()", pcall(function() local f = assert(io.open("data.txt", "r")) for l in f:lines("*l", "*x") do print(l) end f:close() end)) end os.remove("data.txt") end ___'' print("testing C API ...") local mod = require("testmod") ___'' print("isinteger", mod.isinteger(1)) print("isinteger", mod.isinteger(0)) print("isinteger", mod.isinteger(1234567)) print("isinteger", mod.isinteger(12.3)) print("isinteger", mod.isinteger(math.huge)) print("isinteger", mod.isinteger(math.sqrt(-1))) ___'' print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6)) print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6)) print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6)) print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6)) ___'' print("strtonum", mod.strtonum("+123")) print("strtonum", mod.strtonum(" 123 ")) print("strtonum", mod.strtonum("-1.23")) print("strtonum", mod.strtonum(" 123 abc")) print("strtonum", mod.strtonum("jkl")) ___'' local a, b, c = mod.requiref() print("requiref", type(a), type(b), type(c), a.boolean, b.boolean, c.boolean, type(requiref1), type(requiref2), type(requiref3)) ___'' local proxy, backend = {}, {} setmetatable(proxy, { __index = backend, __newindex = backend }) print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) print("geti/seti", mod.getseti(proxy, 1)) print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) print("geti/seti", mod.getseti(proxy, 1)) print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) -- tests for Lua 5.1 ___'' print("tonumber", mod.tonumber(12)) print("tonumber", mod.tonumber("12")) print("tonumber", mod.tonumber("0")) print("tonumber", mod.tonumber(false)) print("tonumber", mod.tonumber("error")) ___'' print("tointeger", mod.tointeger(12)) print("tointeger", mod.tointeger(-12)) print("tointeger", mod.tointeger(12.1)) print("tointeger", mod.tointeger(12.9)) print("tointeger", mod.tointeger(-12.1)) print("tointeger", mod.tointeger(-12.9)) print("tointeger", mod.tointeger("12")) print("tointeger", mod.tointeger("0")) print("tointeger", mod.tointeger(math.pi)) print("tointeger", mod.tointeger(false)) print("tointeger", mod.tointeger("error")) ___'' print("len", mod.len("123")) print("len", mod.len({ 1, 2, 3})) print("len", pcall(mod.len, true)) local ud, meta = mod.newproxy() meta.__len = function() return 5 end print("len", mod.len(ud)) meta.__len = function() return true end print("len", pcall(mod.len, ud)) ___'' print("copy", mod.copy(true, "string", {}, 1)) ___'' print("rawgetp/rawsetp", mod.rawxetp()) print("rawgetp/rawsetp", mod.rawxetp("I'm back")) ___'' print("globals", F(mod.globals()), mod.globals() == _G) ___'' local t = {} print("getsubtable", F(mod.subtable(t))) local x, msg = mod.subtable(t) print("getsubtable", F(x, msg, x == t.xxx)) ___'' print("udata", F(mod.udata())) print("udata", mod.udata("nosuchtype")) ___'' print("uservalue", F(mod.uservalue())) ___'' print("upvalues", mod.getupvalues()) ___'' print("absindex", mod.absindex("hi", true)) ___'' print("arith", mod.arith(2, 1)) print("arith", mod.arith(3, 5)) ___'' print("compare", mod.compare(1, 1)) print("compare", mod.compare(2, 1)) print("compare", mod.compare(1, 2)) ___'' print("tolstring", mod.tolstring("string")) local t = setmetatable({}, { __tostring = function(v) return "mytable" end }) print("tolstring", mod.tolstring(t)) local t = setmetatable({}, { __tostring = function(v) return nil end }) print("tolstring", pcall(mod.tolstring, t)) local ud, meta = mod.newproxy() meta.__name = "XXX" print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy")) ___'' print("pushstring", mod.pushstring()) ___'' print("Buffer", mod.buffer()) ___'' print("execresult", mod.exec("exit 0")) print("execresult", mod.exec("exit 1")) print("execresult", mod.exec("exit 25")) ___'' do local bin = string.dump(function() end) local modes = { "t", "b", "bt" } local codes = { "", "return true", bin, "invalidsource", "\27invalidbinary" } for _,m in ipairs(modes) do for i,c in ipairs(codes) do print("loadbufferx", m, i, F(mod.loadstring(c, m))) end end ___'' local bom = "\239\187\191" local shebang = "#!/usr/bin/env lua\n" codes[#codes+1] = bom .. shebang .. "return true" codes[#codes+1] = bom .. shebang .. bin codes[#codes+1] = bom .. shebang .. "invalidsource" codes[#codes+1] = bom .. shebang .. "\027invalidbinary" for _,m in ipairs(modes) do for i,c in ipairs(codes) do print("loadfilex", m, i, F(mod.loadfile(c, m))) end end end ___'' lua-compat53-0.7/tests/testmod.c000066400000000000000000000201431332200420300165440ustar00rootroot00000000000000#include #include #include "compat-5.3.h" static int test_isinteger (lua_State *L) { lua_pushboolean(L, lua_isinteger(L, 1)); return 1; } static int test_rotate (lua_State *L) { int r = (int)luaL_checkinteger(L, 1); int n = lua_gettop(L)-1; luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments"); lua_rotate(L, 2, r); return n; } static int test_str2num (lua_State *L) { const char *s = luaL_checkstring(L, 1); size_t len = lua_stringtonumber(L, s); if (len == 0) lua_pushnumber(L, 0); lua_pushinteger(L, (lua_Integer)len); return 2; } static int my_mod (lua_State *L ) { lua_newtable(L); lua_pushboolean(L, 1); lua_setfield(L, -2, "boolean"); return 1; } static int test_requiref (lua_State *L) { lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_newtable(L); lua_pushboolean(L, 0); lua_setfield(L, -2, "boolean"); lua_setfield(L, -2, "requiref3"); lua_pop(L, 1); luaL_requiref(L, "requiref1", my_mod, 0); luaL_requiref(L, "requiref2", my_mod, 1); luaL_requiref(L, "requiref3", my_mod, 1); return 3; } static int test_getseti (lua_State *L) { lua_Integer k = luaL_checkinteger(L, 2); lua_Integer n = 0; if (lua_geti(L, 1, k) == LUA_TNUMBER) { n = lua_tointeger(L, -1); } else { lua_pop(L, 1); lua_pushinteger(L, n); } lua_pushinteger(L, n+1); lua_seti(L, 1, k); return 1; } /* additional tests for Lua5.1 */ #define NUP 3 static int test_newproxy (lua_State *L) { lua_settop(L, 0); lua_newuserdata(L, 0); lua_newtable(L); lua_pushvalue(L, -1); lua_pushboolean(L, 1); lua_setfield(L, -2, "__gc"); lua_setmetatable(L, -3); return 2; } static int test_absindex (lua_State *L) { int i = 1; for (i = 1; i <= NUP; ++i) lua_pushvalue(L, lua_absindex(L, lua_upvalueindex(i))); lua_pushvalue(L, lua_absindex(L, LUA_REGISTRYINDEX)); lua_pushstring(L, lua_typename(L, lua_type(L, lua_absindex(L, -1)))); lua_replace(L, lua_absindex(L, -2)); lua_pushvalue(L, lua_absindex(L, -2)); lua_pushvalue(L, lua_absindex(L, -4)); lua_pushvalue(L, lua_absindex(L, -6)); i += 3; lua_pushvalue(L, lua_absindex(L, 1)); lua_pushvalue(L, lua_absindex(L, 2)); lua_pushvalue(L, lua_absindex(L, 3)); i += 3; return i; } static int test_arith (lua_State *L) { lua_settop(L, 2); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_arith(L, LUA_OPADD); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_arith(L, LUA_OPSUB); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_arith(L, LUA_OPMUL); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_arith(L, LUA_OPDIV); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_arith(L, LUA_OPMOD); lua_pushvalue(L, 1); lua_pushvalue(L, 2); lua_arith(L, LUA_OPPOW); lua_pushvalue(L, 1); lua_arith(L, LUA_OPUNM); return lua_gettop(L)-2; } static int test_compare (lua_State *L) { luaL_checknumber(L, 1); luaL_checknumber(L, 2); lua_settop(L, 2); lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPEQ)); lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLT)); lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLE)); return 3; } static int test_globals (lua_State *L) { lua_pushglobaltable(L); return 1; } static int test_tonumber (lua_State *L) { int isnum = 0; lua_Number n = lua_tonumberx(L, 1, &isnum); if (!isnum) lua_pushnil(L); else lua_pushnumber(L, n); return 1; } static int test_tointeger (lua_State *L) { int isnum = 0; lua_Integer n = lua_tointegerx(L, 1, &isnum); if (!isnum) lua_pushnil(L); else lua_pushinteger(L, n); lua_pushinteger(L, lua_tointeger(L, 1)); return 2; } static int test_len (lua_State *L) { luaL_checkany(L, 1); lua_len(L, 1); lua_pushinteger(L, luaL_len(L, 1)); return 2; } static int test_copy (lua_State *L) { int args = lua_gettop(L); if (args >= 2) { int i = 0; for (i = args-1; i > 0; --i) lua_copy(L, args, i); } return args; } /* need an address */ static char const dummy = 0; static int test_rawxetp (lua_State *L) { if (lua_gettop(L) > 0) lua_pushvalue(L, 1); else lua_pushliteral(L, "hello again"); lua_rawsetp(L, LUA_REGISTRYINDEX, &dummy); lua_settop(L, 0); lua_rawgetp(L, LUA_REGISTRYINDEX, &dummy); return 1; } static int test_udata (lua_State *L) { const char *tname = luaL_optstring(L, 1, "utype1"); void *u1 = lua_newuserdata(L, 1); int u1pos = lua_gettop(L); void *u2 = lua_newuserdata(L, 1); int u2pos = lua_gettop(L); luaL_newmetatable(L, "utype1"); luaL_newmetatable(L, "utype2"); lua_pop(L, 2); luaL_setmetatable(L, "utype2"); lua_pushvalue(L, u1pos); luaL_setmetatable(L, "utype1"); lua_pop(L, 1); (void)u1; (void)u2; lua_pushlightuserdata(L, luaL_testudata(L, u1pos, tname)); lua_pushlightuserdata(L, luaL_testudata(L, u2pos, tname)); luaL_getmetatable(L, "utype1"); lua_getfield(L, -1, "__name"); lua_replace(L, -2); return 3; } static int test_subtable (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); if (luaL_getsubtable(L, 1, "xxx")) { lua_pushliteral(L, "oldtable"); } else { lua_pushliteral(L, "newtable"); } return 2; } static int test_uservalue (lua_State *L) { void *udata = lua_newuserdata(L, 1); int ui = lua_gettop(L); lua_newtable(L); lua_setuservalue(L, ui); lua_pushinteger(L, lua_getuservalue(L, ui)); (void)udata; return 2; } static int test_upvalues (lua_State *L) { int i = 1; for (i = 1; i <= NUP; ++i) lua_pushvalue(L, lua_upvalueindex(i)); return NUP; } static int test_tolstring (lua_State *L) { size_t len = 0; luaL_tolstring(L, 1, &len); lua_pushinteger(L, (int)len); return 2; } static int test_pushstring (lua_State *L) { lua_pushstring(L, lua_pushliteral(L, "abc")); lua_pushstring(L, lua_pushlstring(L, "abc", 2)); lua_pushstring(L, lua_pushlstring(L, NULL, 0)); lua_pushstring(L, lua_pushstring(L, "abc")); lua_pushboolean(L, NULL == lua_pushstring(L, NULL)); return 10; } static int test_buffer (lua_State *L) { luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1); p[0] = 'a'; p[1] = 'b'; luaL_addsize(&b, 2); luaL_addstring(&b, "c"); lua_pushliteral(L, "d"); luaL_addvalue(&b); luaL_addchar(&b, 'e'); luaL_pushresult(&b); return 1; } static int test_exec (lua_State *L) { const char *cmd = luaL_checkstring(L, 1); return luaL_execresult(L, system(cmd)); } static int test_loadstring (lua_State *L) { size_t len = 0; char const* s = luaL_checklstring(L, 1, &len); char const* mode = luaL_optstring(L, 2, "bt"); lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode)); return 2; } static int test_loadfile (lua_State *L) { char filename[L_tmpnam+1] = { 0 }; size_t len = 0; char const* s = luaL_checklstring(L, 1, &len); char const* mode = luaL_optstring(L, 2, "bt"); if (tmpnam(filename)) { FILE* f = fopen(filename, "wb"); if (f) { fwrite(s, 1, len, f); fclose(f); lua_pushinteger(L, luaL_loadfilex(L, filename, mode)); remove(filename); return 2; } else remove(filename); } return 0; } static const luaL_Reg funcs[] = { { "isinteger", test_isinteger }, { "rotate", test_rotate }, { "strtonum", test_str2num }, { "requiref", test_requiref }, { "getseti", test_getseti }, { "newproxy", test_newproxy }, { "arith", test_arith }, { "compare", test_compare }, { "tonumber", test_tonumber }, { "tointeger", test_tointeger }, { "len", test_len }, { "copy", test_copy }, { "rawxetp", test_rawxetp }, { "subtable", test_subtable }, { "udata", test_udata }, { "uservalue", test_uservalue }, { "globals", test_globals }, { "tolstring", test_tolstring }, { "pushstring", test_pushstring }, { "buffer", test_buffer }, { "exec", test_exec }, { "loadstring", test_loadstring }, { "loadfile", test_loadfile }, { NULL, NULL } }; static const luaL_Reg more_funcs[] = { { "getupvalues", test_upvalues }, { "absindex", test_absindex }, { NULL, NULL } }; #ifdef __cplusplus extern "C" { #endif int luaopen_testmod (lua_State *L) { int i = 1; luaL_newlib(L, funcs); for (i = 1; i <= NUP; ++i) lua_pushnumber(L, i); luaL_setfuncs(L, more_funcs, NUP); return 1; } #ifdef __cplusplus } #endif