diff options
| author | daurnimator <quae@daurnimator.com> | 2017-08-30 13:55:59 +1000 |
|---|---|---|
| committer | daurnimator <quae@daurnimator.com> | 2017-08-30 13:56:07 +1000 |
| commit | b8e3766294b6bf11d70a8a202e633b2569675e77 (patch) | |
| tree | c1f29081daf4a1dc3965ee260d88e2aeae9aa902 | |
| parent | b92fca3b68e551d2583754c80196d524890e5ee4 (diff) | |
| parent | 7333333568b13db56136e2354c55556adc7714ed (diff) | |
| download | luaossl-b8e3766294b6bf11d70a8a202e633b2569675e77.tar.gz luaossl-b8e3766294b6bf11d70a8a202e633b2569675e77.tar.bz2 luaossl-b8e3766294b6bf11d70a8a202e633b2569675e77.zip | |
Merge commit '7333333568b13db56136e2354c55556adc7714ed' as 'vendor/compat53'
| -rw-r--r-- | vendor/compat53/.gitignore | 10 | ||||
| -rw-r--r-- | vendor/compat53/LICENSE | 20 | ||||
| -rw-r--r-- | vendor/compat53/README.md | 229 | ||||
| -rw-r--r-- | vendor/compat53/c-api/compat-5.3.c | 617 | ||||
| -rw-r--r-- | vendor/compat53/c-api/compat-5.3.h | 388 | ||||
| -rw-r--r-- | vendor/compat53/compat53/init.lua | 373 | ||||
| -rw-r--r-- | vendor/compat53/compat53/module.lua | 827 | ||||
| -rw-r--r-- | vendor/compat53/lprefix.h | 175 | ||||
| -rw-r--r-- | vendor/compat53/lstrlib.c | 1584 | ||||
| -rw-r--r-- | vendor/compat53/ltablib.c | 450 | ||||
| -rw-r--r-- | vendor/compat53/lutf8lib.c | 256 | ||||
| -rw-r--r-- | vendor/compat53/rockspecs/compat53-0.1-1.rockspec | 31 | ||||
| -rw-r--r-- | vendor/compat53/rockspecs/compat53-0.2-1.rockspec | 32 | ||||
| -rw-r--r-- | vendor/compat53/rockspecs/compat53-0.3-1.rockspec | 32 | ||||
| -rw-r--r-- | vendor/compat53/rockspecs/compat53-0.4-1.rockspec | 32 | ||||
| -rw-r--r-- | vendor/compat53/rockspecs/compat53-0.5-1.rockspec | 32 | ||||
| -rw-r--r-- | vendor/compat53/rockspecs/compat53-scm-0.rockspec | 32 | ||||
| -rwxr-xr-x | vendor/compat53/tests/test.lua | 789 | ||||
| -rw-r--r-- | vendor/compat53/tests/testmod.c | 318 |
19 files changed, 6227 insertions, 0 deletions
diff --git a/vendor/compat53/.gitignore b/vendor/compat53/.gitignore new file mode 100644 index 0000000..67c1b76 --- /dev/null +++ b/vendor/compat53/.gitignore | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # generated files | ||
| 2 | *.so | ||
| 3 | *.dll | ||
| 4 | *.o | ||
| 5 | *.obj | ||
| 6 | HISTO | ||
| 7 | |||
| 8 | # vim temporaries | ||
| 9 | .*.swp | ||
| 10 | |||
diff --git a/vendor/compat53/LICENSE b/vendor/compat53/LICENSE new file mode 100644 index 0000000..511db15 --- /dev/null +++ b/vendor/compat53/LICENSE | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | The MIT License (MIT) | ||
| 2 | |||
| 3 | Copyright (c) 2015 Kepler Project. | ||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 6 | this software and associated documentation files (the "Software"), to deal in | ||
| 7 | the Software without restriction, including without limitation the rights to | ||
| 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 9 | the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 10 | subject to the following conditions: | ||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in all | ||
| 13 | copies or substantial portions of the Software. | ||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
diff --git a/vendor/compat53/README.md b/vendor/compat53/README.md new file mode 100644 index 0000000..08614a1 --- /dev/null +++ b/vendor/compat53/README.md | |||
| @@ -0,0 +1,229 @@ | |||
| 1 | # lua-compat-5.3 | ||
| 2 | |||
| 3 | Lua-5.3-style APIs for Lua 5.2 and 5.1. | ||
| 4 | |||
| 5 | ## What is it | ||
| 6 | |||
| 7 | This is a small module that aims to make it easier to write code | ||
| 8 | in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua | ||
| 9 | 5.3. This does *not* make Lua 5.2 (or even Lua 5.1) entirely | ||
| 10 | compatible with Lua 5.3, but it brings the API closer to that of Lua | ||
| 11 | 5.3. | ||
| 12 | |||
| 13 | It includes: | ||
| 14 | |||
| 15 | * _For writing Lua_: The Lua module `compat53`, which can be require'd | ||
| 16 | from Lua scripts and run in Lua 5.1, 5.2, and 5.3, including a | ||
| 17 | backport of the `utf8` module, the 5.3 `table` module, and the | ||
| 18 | string packing functions straight from the Lua 5.3 sources. | ||
| 19 | * _For writing C_: A C header and file which can be linked to your | ||
| 20 | Lua module written in C, providing some functions from the C API | ||
| 21 | of Lua 5.3 that do not exist in Lua 5.2 or 5.1, making it easier to | ||
| 22 | write C code that compiles with all three versions of liblua. | ||
| 23 | |||
| 24 | ## How to use it | ||
| 25 | |||
| 26 | ### Lua module | ||
| 27 | |||
| 28 | ```lua | ||
| 29 | require("compat53") | ||
| 30 | ``` | ||
| 31 | |||
| 32 | `compat53` makes changes to your global environment and does not return | ||
| 33 | a meaningful return value, so the usual idiom of storing the return of | ||
| 34 | `require` in a local variable makes no sense. | ||
| 35 | |||
| 36 | When run under Lua 5.3, this module does nothing. | ||
| 37 | |||
| 38 | When run under Lua 5.2 or 5.1, it replaces some of your standard | ||
| 39 | functions and adds new ones to bring your environment closer to that | ||
| 40 | of Lua 5.3. It also tries to load the backported `utf8`, `table`, and | ||
| 41 | string packing modules automatically. If unsuccessful, pure Lua | ||
| 42 | versions of the new `table` functions are used as a fallback, and | ||
| 43 | [Roberto's struct library][1] is tried for string packing. | ||
| 44 | |||
| 45 | #### Lua submodules | ||
| 46 | |||
| 47 | ```lua | ||
| 48 | local _ENV = require("compat53.module") | ||
| 49 | if setfenv then setfenv(1, _ENV) end | ||
| 50 | ``` | ||
| 51 | |||
| 52 | The `compat53.module` module does not modify the global environment, | ||
| 53 | and so it is safe to use in modules without affecting other Lua files. | ||
| 54 | It is supposed to be set as the current environment (see above), i.e. | ||
| 55 | cherry picking individual functions from this module is expressly | ||
| 56 | *not* supported!). Not all features are available when using this | ||
| 57 | module (e.g. yieldable (x)pcall support, string/file methods, etc.), | ||
| 58 | so it is recommended to use plain `require("compat53")` whenever | ||
| 59 | possible. | ||
| 60 | |||
| 61 | ### C code | ||
| 62 | |||
| 63 | There are two ways of adding the C API compatibility functions/macros to | ||
| 64 | your project: | ||
| 65 | * If `COMPAT53_PREFIX` is *not* `#define`d, `compat-5.3.h` `#include`s | ||
| 66 | `compat-5.3.c`, and all functions are made `static`. You don't have to | ||
| 67 | compile/link/add `compat-5.3.c` yourself. This is useful for one-file | ||
| 68 | projects. | ||
| 69 | * If `COMPAT53_PREFIX` is `#define`d, all exported functions are renamed | ||
| 70 | behind the scenes using this prefix to avoid linker conflicts with other | ||
| 71 | code using this package. This doesn't change the way you call the | ||
| 72 | compatibility functions in your code. You have to compile and link | ||
| 73 | `compat-5.3.c` to your project yourself. You can change the way the | ||
| 74 | functions are exported using the `COMPAT53_API` macro (e.g. if you need | ||
| 75 | some `__declspec` magic). While it is technically possible to use | ||
| 76 | the "lua" prefix (and it looks better in the debugger), this is | ||
| 77 | discouraged because LuaJIT has started to implement its own Lua 5.2+ | ||
| 78 | C API functions, and with the "lua" prefix you'd violate the | ||
| 79 | one-definition rule with recent LuaJIT versions. | ||
| 80 | |||
| 81 | ## What's implemented | ||
| 82 | |||
| 83 | ### Lua | ||
| 84 | |||
| 85 | * the `utf8` module backported from the Lua 5.3 sources | ||
| 86 | * `string.pack`, `string.packsize`, and `string.unpack` from the Lua | ||
| 87 | 5.3 sources or from the `struct` module. (`struct` is not 100% | ||
| 88 | compatible to Lua 5.3's string packing!) (See [here][4]) | ||
| 89 | * `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`, | ||
| 90 | and `math.ult` (see [here][5]) | ||
| 91 | * `assert` accepts non-string error messages | ||
| 92 | * `ipairs` respects `__index` metamethod | ||
| 93 | * `table.move` | ||
| 94 | * `table` library respects metamethods | ||
| 95 | |||
| 96 | For Lua 5.1 additionally: | ||
| 97 | * `load` and `loadfile` accept `mode` and `env` parameters | ||
| 98 | * `table.pack` and `table.unpack` | ||
| 99 | * string patterns may contain embedded zeros (but see [here][6]) | ||
| 100 | * `string.rep` accepts `sep` argument | ||
| 101 | * `string.format` calls `tostring` on arguments for `%s` | ||
| 102 | * `math.log` accepts base argument | ||
| 103 | * `xpcall` takes additional arguments | ||
| 104 | * `pcall` and `xpcall` can execute functions that yield (see | ||
| 105 | [here][22] for a possible problem with `coroutine.running`) | ||
| 106 | * `pairs` respects `__pairs` metamethod (see [here][7]) | ||
| 107 | * `rawlen` (but `#` still doesn't respect `__len` for tables) | ||
| 108 | * `package.searchers` as alias for `package.loaders` | ||
| 109 | * `package.searchpath` (see [here][8]) | ||
| 110 | * `coroutine` functions dealing with the main coroutine (see | ||
| 111 | [here][22] for a possible problem with `coroutine.running`) | ||
| 112 | * `coroutine.create` accepts functions written in C | ||
| 113 | * return code of `os.execute` (see [here][9]) | ||
| 114 | * `io.write` and `file:write` return file handle | ||
| 115 | * `io.lines` and `file:lines` accept format arguments (like `io.read`) | ||
| 116 | (see [here][10] and [here][11]) | ||
| 117 | * `debug.setmetatable` returns object | ||
| 118 | * `debug.getuservalue` (see [here][12]) | ||
| 119 | * `debug.setuservalue` (see [here][13]) | ||
| 120 | |||
| 121 | ### C | ||
| 122 | |||
| 123 | * `lua_KContext` (see [here][14]) | ||
| 124 | * `lua_KFunction` (see [here][14]) | ||
| 125 | * `lua_dump` (extra `strip` parameter, ignored, see [here][15]) | ||
| 126 | * `lua_getfield` (return value) | ||
| 127 | * `lua_geti` and `lua_seti` | ||
| 128 | * `lua_getglobal` (return value) | ||
| 129 | * `lua_getmetafield` (return value) | ||
| 130 | * `lua_gettable` (return value) | ||
| 131 | * `lua_getuservalue` (limited compatibility, see [here][16]) | ||
| 132 | * `lua_setuservalue` (limited compatibility, see [here][17]) | ||
| 133 | * `lua_isinteger` | ||
| 134 | * `lua_numbertointeger` | ||
| 135 | * `lua_callk` and `lua_pcallk` (limited compatibility, see [here][14]) | ||
| 136 | * `lua_rawget` and `lua_rawgeti` (return values) | ||
| 137 | * `lua_rawgetp` and `lua_rawsetp` | ||
| 138 | * `luaL_requiref` (now checks `package.loaded` first) | ||
| 139 | * `lua_rotate` | ||
| 140 | * `lua_stringtonumber` (see [here][18]) | ||
| 141 | |||
| 142 | For Lua 5.1 additionally: | ||
| 143 | * `LUA_OK` | ||
| 144 | * `LUA_OP*` macros for `lua_arith` and `lua_compare` | ||
| 145 | * `lua_Unsigned` | ||
| 146 | * `lua_absindex` | ||
| 147 | * `lua_arith` (see [here][19]) | ||
| 148 | * `lua_compare` | ||
| 149 | * `lua_len`, `lua_rawlen`, and `luaL_len` | ||
| 150 | * `lua_pushstring`, `lua_pushlstring` (return value) | ||
| 151 | * `lua_copy` | ||
| 152 | * `lua_pushglobaltable` | ||
| 153 | * `luaL_testudata` | ||
| 154 | * `luaL_setfuncs`, `luaL_newlibtable`, and `luaL_newlib` | ||
| 155 | * `luaL_setmetatable` | ||
| 156 | * `luaL_getsubtable` | ||
| 157 | * `luaL_traceback` | ||
| 158 | * `luaL_execresult` | ||
| 159 | * `luaL_fileresult` | ||
| 160 | * `luaL_checkversion` (with empty body, only to avoid compile errors, | ||
| 161 | see [here][20]) | ||
| 162 | * `luaL_tolstring` | ||
| 163 | * `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize` | ||
| 164 | (see [here][21]) | ||
| 165 | * `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`, | ||
| 166 | `luaL_checkunsigned`, `luaL_optunsigned`, if | ||
| 167 | `LUA_COMPAT_APIINTCASTS` is defined. | ||
| 168 | |||
| 169 | ## What's not implemented | ||
| 170 | |||
| 171 | * bit operators | ||
| 172 | * integer division operator | ||
| 173 | * utf8 escape sequences | ||
| 174 | * 64 bit integers | ||
| 175 | * `coroutine.isyieldable` | ||
| 176 | * Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See | ||
| 177 | [`lua-compat-5.2`][2] for a detailed list. | ||
| 178 | * the following C API functions/macros: | ||
| 179 | * `lua_isyieldable` | ||
| 180 | * `lua_getextraspace` | ||
| 181 | * `lua_arith` (new operators missing) | ||
| 182 | * `lua_push(v)fstring` (new formats missing) | ||
| 183 | * `lua_upvalueid` (5.1) | ||
| 184 | * `lua_upvaluejoin` (5.1) | ||
| 185 | * `lua_version` (5.1) | ||
| 186 | * `lua_yieldk` (5.1) | ||
| 187 | * `luaL_loadbufferx` (5.1) | ||
| 188 | * `luaL_loadfilex` (5.1) | ||
| 189 | |||
| 190 | ## See also | ||
| 191 | |||
| 192 | * For Lua-5.2-style APIs under Lua 5.1, see [lua-compat-5.2][2], | ||
| 193 | which also is the basis for most of the code in this project. | ||
| 194 | * For Lua-5.1-style APIs under Lua 5.0, see [Compat-5.1][3] | ||
| 195 | |||
| 196 | ## Credits | ||
| 197 | |||
| 198 | This package contains code written by: | ||
| 199 | |||
| 200 | * [The Lua Team](http://www.lua.org) | ||
| 201 | * Philipp Janda ([@siffiejoe](http://github.com/siffiejoe)) | ||
| 202 | * Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola)) | ||
| 203 | * Hisham Muhammad ([@hishamhm](http://github.com/hishamhm)) | ||
| 204 | * Renato Maia ([@renatomaia](http://github.com/renatomaia)) | ||
| 205 | |||
| 206 | |||
| 207 | [1]: http://www.inf.puc-rio.br/~roberto/struct/ | ||
| 208 | [2]: http://github.com/keplerproject/lua-compat-5.2/ | ||
| 209 | [3]: http://keplerproject.org/compat/ | ||
| 210 | [4]: https://github.com/keplerproject/lua-compat-5.3/wiki/string_packing | ||
| 211 | [5]: https://github.com/keplerproject/lua-compat-5.3/wiki/math.type | ||
| 212 | [6]: https://github.com/keplerproject/lua-compat-5.3/wiki/pattern_matching | ||
| 213 | [7]: https://github.com/keplerproject/lua-compat-5.3/wiki/pairs | ||
| 214 | [8]: https://github.com/keplerproject/lua-compat-5.3/wiki/package.searchpath | ||
| 215 | [9]: https://github.com/keplerproject/lua-compat-5.3/wiki/os.execute | ||
| 216 | [10]: https://github.com/keplerproject/lua-compat-5.3/wiki/io.lines | ||
| 217 | [11]: https://github.com/keplerproject/lua-compat-5.3/wiki/file.lines | ||
| 218 | [12]: https://github.com/keplerproject/lua-compat-5.3/wiki/debug.getuservalue | ||
| 219 | [13]: https://github.com/keplerproject/lua-compat-5.3/wiki/debug.setuservalue | ||
| 220 | [14]: https://github.com/keplerproject/lua-compat-5.3/wiki/yieldable_c_functions | ||
| 221 | [15]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_dump | ||
| 222 | [16]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_getuservalue | ||
| 223 | [17]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_setuservalue | ||
| 224 | [18]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_stringtonumber | ||
| 225 | [19]: https://github.com/keplerproject/lua-compat-5.3/wiki/lua_arith | ||
| 226 | [20]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_checkversion | ||
| 227 | [21]: https://github.com/keplerproject/lua-compat-5.3/wiki/luaL_Buffer | ||
| 228 | [22]: https://github.com/keplerproject/lua-compat-5.3/wiki/coroutine.running | ||
| 229 | |||
diff --git a/vendor/compat53/c-api/compat-5.3.c b/vendor/compat53/c-api/compat-5.3.c new file mode 100644 index 0000000..883efb8 --- /dev/null +++ b/vendor/compat53/c-api/compat-5.3.c | |||
| @@ -0,0 +1,617 @@ | |||
| 1 | #include <stddef.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include <ctype.h> | ||
| 5 | #include <errno.h> | ||
| 6 | #include "compat-5.3.h" | ||
| 7 | |||
| 8 | /* don't compile it again if it already is included via compat53.h */ | ||
| 9 | #ifndef COMPAT53_C_ | ||
| 10 | #define COMPAT53_C_ | ||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | /* definitions for Lua 5.1 only */ | ||
| 15 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 | ||
| 16 | |||
| 17 | |||
| 18 | COMPAT53_API int lua_absindex (lua_State *L, int i) { | ||
| 19 | if (i < 0 && i > LUA_REGISTRYINDEX) | ||
| 20 | i += lua_gettop(L) + 1; | ||
| 21 | return i; | ||
| 22 | } | ||
| 23 | |||
| 24 | |||
| 25 | static void compat53_call_lua (lua_State *L, char const code[], size_t len, | ||
| 26 | int nargs, int nret) { | ||
| 27 | lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); | ||
| 28 | if (lua_type(L, -1) != LUA_TFUNCTION) { | ||
| 29 | lua_pop(L, 1); | ||
| 30 | if (luaL_loadbuffer(L, code, len, "=none")) | ||
| 31 | lua_error(L); | ||
| 32 | lua_pushvalue(L, -1); | ||
| 33 | lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); | ||
| 34 | } | ||
| 35 | lua_insert(L, -nargs-1); | ||
| 36 | lua_call(L, nargs, nret); | ||
| 37 | } | ||
| 38 | |||
| 39 | |||
| 40 | static const char compat53_arith_code[] = | ||
| 41 | "local op,a,b=...\n" | ||
| 42 | "if op==0 then return a+b\n" | ||
| 43 | "elseif op==1 then return a-b\n" | ||
| 44 | "elseif op==2 then return a*b\n" | ||
| 45 | "elseif op==3 then return a/b\n" | ||
| 46 | "elseif op==4 then return a%b\n" | ||
| 47 | "elseif op==5 then return a^b\n" | ||
| 48 | "elseif op==6 then return -a\n" | ||
| 49 | "end\n"; | ||
| 50 | |||
| 51 | COMPAT53_API void lua_arith (lua_State *L, int op) { | ||
| 52 | if (op < LUA_OPADD || op > LUA_OPUNM) | ||
| 53 | luaL_error(L, "invalid 'op' argument for lua_arith"); | ||
| 54 | luaL_checkstack(L, 5, "not enough stack slots"); | ||
| 55 | if (op == LUA_OPUNM) | ||
| 56 | lua_pushvalue(L, -1); | ||
| 57 | lua_pushnumber(L, op); | ||
| 58 | lua_insert(L, -3); | ||
| 59 | compat53_call_lua(L, compat53_arith_code, | ||
| 60 | sizeof(compat53_arith_code)-1, 3, 1); | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | static const char compat53_compare_code[] = | ||
| 65 | "local a,b=...\n" | ||
| 66 | "return a<=b\n"; | ||
| 67 | |||
| 68 | COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op) { | ||
| 69 | int result = 0; | ||
| 70 | switch (op) { | ||
| 71 | case LUA_OPEQ: | ||
| 72 | return lua_equal(L, idx1, idx2); | ||
| 73 | case LUA_OPLT: | ||
| 74 | return lua_lessthan(L, idx1, idx2); | ||
| 75 | case LUA_OPLE: | ||
| 76 | luaL_checkstack(L, 5, "not enough stack slots"); | ||
| 77 | idx1 = lua_absindex(L, idx1); | ||
| 78 | idx2 = lua_absindex(L, idx2); | ||
| 79 | lua_pushvalue(L, idx1); | ||
| 80 | lua_pushvalue(L, idx2); | ||
| 81 | compat53_call_lua(L, compat53_compare_code, | ||
| 82 | sizeof(compat53_compare_code)-1, 2, 1); | ||
| 83 | result = lua_toboolean(L, -1); | ||
| 84 | lua_pop(L, 1); | ||
| 85 | return result; | ||
| 86 | default: | ||
| 87 | luaL_error(L, "invalid 'op' argument for lua_compare"); | ||
| 88 | } | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | |||
| 93 | COMPAT53_API void lua_copy (lua_State *L, int from, int to) { | ||
| 94 | int abs_to = lua_absindex(L, to); | ||
| 95 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
| 96 | lua_pushvalue(L, from); | ||
| 97 | lua_replace(L, abs_to); | ||
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | COMPAT53_API void lua_len (lua_State *L, int i) { | ||
| 102 | switch (lua_type(L, i)) { | ||
| 103 | case LUA_TSTRING: | ||
| 104 | lua_pushnumber(L, (lua_Integer)lua_objlen(L, i)); | ||
| 105 | break; | ||
| 106 | case LUA_TTABLE: | ||
| 107 | if (!luaL_callmeta(L, i, "__len")) | ||
| 108 | lua_pushnumber(L, (lua_Integer)lua_objlen(L, i)); | ||
| 109 | break; | ||
| 110 | case LUA_TUSERDATA: | ||
| 111 | if (luaL_callmeta(L, i, "__len")) | ||
| 112 | break; | ||
| 113 | /* maybe fall through */ | ||
| 114 | default: | ||
| 115 | luaL_error(L, "attempt to get length of a %s value", | ||
| 116 | lua_typename(L, lua_type(L, i))); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
| 121 | COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p) { | ||
| 122 | int abs_i = lua_absindex(L, i); | ||
| 123 | lua_pushlightuserdata(L, (void*)p); | ||
| 124 | lua_rawget(L, abs_i); | ||
| 125 | return lua_type(L, -1); | ||
| 126 | } | ||
| 127 | |||
| 128 | COMPAT53_API void lua_rawsetp (lua_State *L, int i, const void *p) { | ||
| 129 | int abs_i = lua_absindex(L, i); | ||
| 130 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
| 131 | lua_pushlightuserdata(L, (void*)p); | ||
| 132 | lua_insert(L, -2); | ||
| 133 | lua_rawset(L, abs_i); | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) { | ||
| 138 | lua_Integer n = lua_tointeger(L, i); | ||
| 139 | if (isnum != NULL) { | ||
| 140 | *isnum = (n != 0 || lua_isnumber(L, i)); | ||
| 141 | } | ||
| 142 | return n; | ||
| 143 | } | ||
| 144 | |||
| 145 | |||
| 146 | COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) { | ||
| 147 | lua_Number n = lua_tonumber(L, i); | ||
| 148 | if (isnum != NULL) { | ||
| 149 | *isnum = (n != 0 || lua_isnumber(L, i)); | ||
| 150 | } | ||
| 151 | return n; | ||
| 152 | } | ||
| 153 | |||
| 154 | |||
| 155 | COMPAT53_API void luaL_checkversion (lua_State *L) { | ||
| 156 | (void)L; | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg) { | ||
| 161 | if (!lua_checkstack(L, sp+LUA_MINSTACK)) { | ||
| 162 | if (msg != NULL) | ||
| 163 | luaL_error(L, "stack overflow (%s)", msg); | ||
| 164 | else { | ||
| 165 | lua_pushliteral(L, "stack overflow"); | ||
| 166 | lua_error(L); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | |||
| 172 | COMPAT53_API int luaL_getsubtable (lua_State *L, int i, const char *name) { | ||
| 173 | int abs_i = lua_absindex(L, i); | ||
| 174 | luaL_checkstack(L, 3, "not enough stack slots"); | ||
| 175 | lua_pushstring(L, name); | ||
| 176 | lua_gettable(L, abs_i); | ||
| 177 | if (lua_istable(L, -1)) | ||
| 178 | return 1; | ||
| 179 | lua_pop(L, 1); | ||
| 180 | lua_newtable(L); | ||
| 181 | lua_pushstring(L, name); | ||
| 182 | lua_pushvalue(L, -2); | ||
| 183 | lua_settable(L, abs_i); | ||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 188 | COMPAT53_API lua_Integer luaL_len (lua_State *L, int i) { | ||
| 189 | lua_Integer res = 0; | ||
| 190 | int isnum = 0; | ||
| 191 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
| 192 | lua_len(L, i); | ||
| 193 | res = lua_tointegerx(L, -1, &isnum); | ||
| 194 | lua_pop(L, 1); | ||
| 195 | if (!isnum) | ||
| 196 | luaL_error(L, "object length is not an integer"); | ||
| 197 | return res; | ||
| 198 | } | ||
| 199 | |||
| 200 | |||
| 201 | COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { | ||
| 202 | luaL_checkstack(L, nup+1, "too many upvalues"); | ||
| 203 | for (; l->name != NULL; l++) { /* fill the table with given functions */ | ||
| 204 | int i; | ||
| 205 | lua_pushstring(L, l->name); | ||
| 206 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ | ||
| 207 | lua_pushvalue(L, -(nup + 1)); | ||
| 208 | lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ | ||
| 209 | lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ | ||
| 210 | } | ||
| 211 | lua_pop(L, nup); /* remove upvalues */ | ||
| 212 | } | ||
| 213 | |||
| 214 | |||
| 215 | COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname) { | ||
| 216 | luaL_checkstack(L, 1, "not enough stack slots"); | ||
| 217 | luaL_getmetatable(L, tname); | ||
| 218 | lua_setmetatable(L, -2); | ||
| 219 | } | ||
| 220 | |||
| 221 | |||
| 222 | COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname) { | ||
| 223 | void *p = lua_touserdata(L, i); | ||
| 224 | luaL_checkstack(L, 2, "not enough stack slots"); | ||
| 225 | if (p == NULL || !lua_getmetatable(L, i)) | ||
| 226 | return NULL; | ||
| 227 | else { | ||
| 228 | int res = 0; | ||
| 229 | luaL_getmetatable(L, tname); | ||
| 230 | res = lua_rawequal(L, -1, -2); | ||
| 231 | lua_pop(L, 2); | ||
| 232 | if (!res) | ||
| 233 | p = NULL; | ||
| 234 | } | ||
| 235 | return p; | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | static int compat53_countlevels (lua_State *L) { | ||
| 240 | lua_Debug ar; | ||
| 241 | int li = 1, le = 1; | ||
| 242 | /* find an upper bound */ | ||
| 243 | while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } | ||
| 244 | /* do a binary search */ | ||
| 245 | while (li < le) { | ||
| 246 | int m = (li + le)/2; | ||
| 247 | if (lua_getstack(L, m, &ar)) li = m + 1; | ||
| 248 | else le = m; | ||
| 249 | } | ||
| 250 | return le - 1; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int compat53_findfield (lua_State *L, int objidx, int level) { | ||
| 254 | if (level == 0 || !lua_istable(L, -1)) | ||
| 255 | return 0; /* not found */ | ||
| 256 | lua_pushnil(L); /* start 'next' loop */ | ||
| 257 | while (lua_next(L, -2)) { /* for each pair in table */ | ||
| 258 | if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ | ||
| 259 | if (lua_rawequal(L, objidx, -1)) { /* found object? */ | ||
| 260 | lua_pop(L, 1); /* remove value (but keep name) */ | ||
| 261 | return 1; | ||
| 262 | } | ||
| 263 | else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ | ||
| 264 | lua_remove(L, -2); /* remove table (but keep name) */ | ||
| 265 | lua_pushliteral(L, "."); | ||
| 266 | lua_insert(L, -2); /* place '.' between the two names */ | ||
| 267 | lua_concat(L, 3); | ||
| 268 | return 1; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | lua_pop(L, 1); /* remove value */ | ||
| 272 | } | ||
| 273 | return 0; /* not found */ | ||
| 274 | } | ||
| 275 | |||
| 276 | static int compat53_pushglobalfuncname (lua_State *L, lua_Debug *ar) { | ||
| 277 | int top = lua_gettop(L); | ||
| 278 | lua_getinfo(L, "f", ar); /* push function */ | ||
| 279 | lua_pushvalue(L, LUA_GLOBALSINDEX); | ||
| 280 | if (compat53_findfield(L, top + 1, 2)) { | ||
| 281 | lua_copy(L, -1, top + 1); /* move name to proper place */ | ||
| 282 | lua_pop(L, 2); /* remove pushed values */ | ||
| 283 | return 1; | ||
| 284 | } | ||
| 285 | else { | ||
| 286 | lua_settop(L, top); /* remove function and global table */ | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | static void compat53_pushfuncname (lua_State *L, lua_Debug *ar) { | ||
| 292 | if (*ar->namewhat != '\0') /* is there a name? */ | ||
| 293 | lua_pushfstring(L, "function " LUA_QS, ar->name); | ||
| 294 | else if (*ar->what == 'm') /* main? */ | ||
| 295 | lua_pushliteral(L, "main chunk"); | ||
| 296 | else if (*ar->what == 'C') { | ||
| 297 | if (compat53_pushglobalfuncname(L, ar)) { | ||
| 298 | lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); | ||
| 299 | lua_remove(L, -2); /* remove name */ | ||
| 300 | } | ||
| 301 | else | ||
| 302 | lua_pushliteral(L, "?"); | ||
| 303 | } | ||
| 304 | else | ||
| 305 | lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); | ||
| 306 | } | ||
| 307 | |||
| 308 | #define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ | ||
| 309 | #define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ | ||
| 310 | |||
| 311 | COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, | ||
| 312 | const char *msg, int level) { | ||
| 313 | lua_Debug ar; | ||
| 314 | int top = lua_gettop(L); | ||
| 315 | int numlevels = compat53_countlevels(L1); | ||
| 316 | int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; | ||
| 317 | if (msg) lua_pushfstring(L, "%s\n", msg); | ||
| 318 | lua_pushliteral(L, "stack traceback:"); | ||
| 319 | while (lua_getstack(L1, level++, &ar)) { | ||
| 320 | if (level == mark) { /* too many levels? */ | ||
| 321 | lua_pushliteral(L, "\n\t..."); /* add a '...' */ | ||
| 322 | level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ | ||
| 323 | } | ||
| 324 | else { | ||
| 325 | lua_getinfo(L1, "Slnt", &ar); | ||
| 326 | lua_pushfstring(L, "\n\t%s:", ar.short_src); | ||
| 327 | if (ar.currentline > 0) | ||
| 328 | lua_pushfstring(L, "%d:", ar.currentline); | ||
| 329 | lua_pushliteral(L, " in "); | ||
| 330 | compat53_pushfuncname(L, &ar); | ||
| 331 | lua_concat(L, lua_gettop(L) - top); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | lua_concat(L, lua_gettop(L) - top); | ||
| 335 | } | ||
| 336 | |||
| 337 | |||
| 338 | COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { | ||
| 339 | int en = errno; /* calls to Lua API may change this value */ | ||
| 340 | if (stat) { | ||
| 341 | lua_pushboolean(L, 1); | ||
| 342 | return 1; | ||
| 343 | } | ||
| 344 | else { | ||
| 345 | lua_pushnil(L); | ||
| 346 | if (fname) | ||
| 347 | lua_pushfstring(L, "%s: %s", fname, strerror(en)); | ||
| 348 | else | ||
| 349 | lua_pushstring(L, strerror(en)); | ||
| 350 | lua_pushnumber(L, (lua_Number)en); | ||
| 351 | return 3; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | |||
| 356 | #if !defined(l_inspectstat) && \ | ||
| 357 | (defined(unix) || defined(__unix) || defined(__unix__) || \ | ||
| 358 | defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ | ||
| 359 | (defined(__APPLE__) && defined(__MACH__))) | ||
| 360 | /* some form of unix; check feature macros in unistd.h for details */ | ||
| 361 | # include <unistd.h> | ||
| 362 | /* check posix version; the relevant include files and macros probably | ||
| 363 | * were available before 2001, but I'm not sure */ | ||
| 364 | # if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L | ||
| 365 | # include <sys/wait.h> | ||
| 366 | # define l_inspectstat(stat,what) \ | ||
| 367 | if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ | ||
| 368 | else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } | ||
| 369 | # endif | ||
| 370 | #endif | ||
| 371 | |||
| 372 | /* provide default (no-op) version */ | ||
| 373 | #if !defined(l_inspectstat) | ||
| 374 | # define l_inspectstat(stat,what) ((void)0) | ||
| 375 | #endif | ||
| 376 | |||
| 377 | |||
| 378 | COMPAT53_API int luaL_execresult (lua_State *L, int stat) { | ||
| 379 | const char *what = "exit"; | ||
| 380 | if (stat == -1) | ||
| 381 | return luaL_fileresult(L, 0, NULL); | ||
| 382 | else { | ||
| 383 | l_inspectstat(stat, what); | ||
| 384 | if (*what == 'e' && stat == 0) | ||
| 385 | lua_pushboolean(L, 1); | ||
| 386 | else | ||
| 387 | lua_pushnil(L); | ||
| 388 | lua_pushstring(L, what); | ||
| 389 | lua_pushinteger(L, stat); | ||
| 390 | return 3; | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | |||
| 395 | COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) { | ||
| 396 | /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ | ||
| 397 | B->b.p = NULL; | ||
| 398 | B->b.L = NULL; | ||
| 399 | B->b.lvl = 0; | ||
| 400 | /* reuse the buffer from the 5.1-style luaL_Buffer though! */ | ||
| 401 | B->ptr = B->b.buffer; | ||
| 402 | B->capacity = LUAL_BUFFERSIZE; | ||
| 403 | B->nelems = 0; | ||
| 404 | B->L2 = L; | ||
| 405 | } | ||
| 406 | |||
| 407 | |||
| 408 | COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s) { | ||
| 409 | if (B->capacity - B->nelems < s) { /* needs to grow */ | ||
| 410 | char* newptr = NULL; | ||
| 411 | size_t newcap = B->capacity * 2; | ||
| 412 | if (newcap - B->nelems < s) | ||
| 413 | newcap = B->nelems + s; | ||
| 414 | if (newcap < B->capacity) /* overflow */ | ||
| 415 | luaL_error(B->L2, "buffer too large"); | ||
| 416 | newptr = (char*)lua_newuserdata(B->L2, newcap); | ||
| 417 | memcpy(newptr, B->ptr, B->nelems); | ||
| 418 | if (B->ptr != B->b.buffer) | ||
| 419 | lua_replace(B->L2, -2); /* remove old buffer */ | ||
| 420 | B->ptr = newptr; | ||
| 421 | B->capacity = newcap; | ||
| 422 | } | ||
| 423 | return B->ptr+B->nelems; | ||
| 424 | } | ||
| 425 | |||
| 426 | |||
| 427 | COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l) { | ||
| 428 | memcpy(luaL_prepbuffsize(B, l), s, l); | ||
| 429 | luaL_addsize(B, l); | ||
| 430 | } | ||
| 431 | |||
| 432 | |||
| 433 | COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B) { | ||
| 434 | size_t len = 0; | ||
| 435 | const char *s = lua_tolstring(B->L2, -1, &len); | ||
| 436 | if (!s) | ||
| 437 | luaL_error(B->L2, "cannot convert value to string"); | ||
| 438 | if (B->ptr != B->b.buffer) | ||
| 439 | lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ | ||
| 440 | luaL_addlstring(B, s, len); | ||
| 441 | lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); | ||
| 442 | } | ||
| 443 | |||
| 444 | |||
| 445 | void luaL_pushresult (luaL_Buffer_53 *B) { | ||
| 446 | lua_pushlstring(B->L2, B->ptr, B->nelems); | ||
| 447 | if (B->ptr != B->b.buffer) | ||
| 448 | lua_replace(B->L2, -2); /* remove userdata buffer */ | ||
| 449 | } | ||
| 450 | |||
| 451 | |||
| 452 | #endif /* Lua 5.1 */ | ||
| 453 | |||
| 454 | |||
| 455 | |||
| 456 | /* definitions for Lua 5.1 and Lua 5.2 */ | ||
| 457 | #if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502 | ||
| 458 | |||
| 459 | |||
| 460 | COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i) { | ||
| 461 | index = lua_absindex(L, index); | ||
| 462 | lua_pushinteger(L, i); | ||
| 463 | lua_gettable(L, index); | ||
| 464 | return lua_type(L, -1); | ||
| 465 | } | ||
| 466 | |||
| 467 | |||
| 468 | COMPAT53_API int lua_isinteger (lua_State *L, int index) { | ||
| 469 | if (lua_type(L, index) == LUA_TNUMBER) { | ||
| 470 | lua_Number n = lua_tonumber(L, index); | ||
| 471 | lua_Integer i = lua_tointeger(L, index); | ||
| 472 | if (i == n) | ||
| 473 | return 1; | ||
| 474 | } | ||
| 475 | return 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | |||
| 479 | static void compat53_reverse (lua_State *L, int a, int b) { | ||
| 480 | for (; a < b; ++a, --b) { | ||
| 481 | lua_pushvalue(L, a); | ||
| 482 | lua_pushvalue(L, b); | ||
| 483 | lua_replace(L, a); | ||
| 484 | lua_replace(L, b); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | COMPAT53_API void lua_rotate (lua_State *L, int idx, int n) { | ||
| 490 | int n_elems = 0; | ||
| 491 | idx = lua_absindex(L, idx); | ||
| 492 | n_elems = lua_gettop(L)-idx+1; | ||
| 493 | if (n < 0) | ||
| 494 | n += n_elems; | ||
| 495 | if ( n > 0 && n < n_elems) { | ||
| 496 | luaL_checkstack(L, 2, "not enough stack slots available"); | ||
| 497 | n = n_elems - n; | ||
| 498 | compat53_reverse(L, idx, idx+n-1); | ||
| 499 | compat53_reverse(L, idx+n, idx+n_elems-1); | ||
| 500 | compat53_reverse(L, idx, idx+n_elems-1); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | |||
| 505 | COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i) { | ||
| 506 | luaL_checkstack(L, 1, "not enough stack slots available"); | ||
| 507 | index = lua_absindex(L, index); | ||
| 508 | lua_pushinteger(L, i); | ||
| 509 | lua_insert(L, -2); | ||
| 510 | lua_settable(L, index); | ||
| 511 | } | ||
| 512 | |||
| 513 | |||
| 514 | #if !defined(lua_str2number) | ||
| 515 | # define lua_str2number(s, p) strtod((s), (p)) | ||
| 516 | #endif | ||
| 517 | |||
| 518 | COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) { | ||
| 519 | char* endptr; | ||
| 520 | lua_Number n = lua_str2number(s, &endptr); | ||
| 521 | if (endptr != s) { | ||
| 522 | while (*endptr != '\0' && isspace((unsigned char)*endptr)) | ||
| 523 | ++endptr; | ||
| 524 | if (*endptr == '\0') { | ||
| 525 | lua_pushnumber(L, n); | ||
| 526 | return endptr - s + 1; | ||
| 527 | } | ||
| 528 | } | ||
| 529 | return 0; | ||
| 530 | } | ||
| 531 | |||
| 532 | |||
| 533 | COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { | ||
| 534 | if (!luaL_callmeta(L, idx, "__tostring")) { | ||
| 535 | int t = lua_type(L, idx), tt = 0; | ||
| 536 | char const* name = NULL; | ||
| 537 | switch (t) { | ||
| 538 | case LUA_TNIL: | ||
| 539 | lua_pushliteral(L, "nil"); | ||
| 540 | break; | ||
| 541 | case LUA_TSTRING: | ||
| 542 | case LUA_TNUMBER: | ||
| 543 | lua_pushvalue(L, idx); | ||
| 544 | break; | ||
| 545 | case LUA_TBOOLEAN: | ||
| 546 | if (lua_toboolean(L, idx)) | ||
| 547 | lua_pushliteral(L, "true"); | ||
| 548 | else | ||
| 549 | lua_pushliteral(L, "false"); | ||
| 550 | break; | ||
| 551 | default: | ||
| 552 | tt = luaL_getmetafield(L, idx, "__name"); | ||
| 553 | name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); | ||
| 554 | lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); | ||
| 555 | if (tt != LUA_TNIL) | ||
| 556 | lua_replace(L, -2); | ||
| 557 | break; | ||
| 558 | } | ||
| 559 | } else { | ||
| 560 | if (!lua_isstring(L, -1)) | ||
| 561 | luaL_error(L, "'__tostring' must return a string"); | ||
| 562 | } | ||
| 563 | return lua_tolstring(L, -1, len); | ||
| 564 | } | ||
| 565 | |||
| 566 | |||
| 567 | COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, | ||
| 568 | lua_CFunction openf, int glb) { | ||
| 569 | luaL_checkstack(L, 3, "not enough stack slots available"); | ||
| 570 | luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); | ||
| 571 | if (lua_getfield(L, -1, modname) == LUA_TNIL) { | ||
| 572 | lua_pop(L, 1); | ||
| 573 | lua_pushcfunction(L, openf); | ||
| 574 | lua_pushstring(L, modname); | ||
| 575 | lua_call(L, 1, 1); | ||
| 576 | lua_pushvalue(L, -1); | ||
| 577 | lua_setfield(L, -3, modname); | ||
| 578 | } | ||
| 579 | if (glb) { | ||
| 580 | lua_pushvalue(L, -1); | ||
| 581 | lua_setglobal(L, modname); | ||
| 582 | } | ||
| 583 | lua_replace(L, -2); | ||
| 584 | } | ||
| 585 | |||
| 586 | |||
| 587 | #endif /* Lua 5.1 and 5.2 */ | ||
| 588 | |||
| 589 | |||
| 590 | #endif /* COMPAT53_C_ */ | ||
| 591 | |||
| 592 | |||
| 593 | /********************************************************************* | ||
| 594 | * This file contains parts of Lua 5.2's and Lua 5.3's source code: | ||
| 595 | * | ||
| 596 | * Copyright (C) 1994-2014 Lua.org, PUC-Rio. | ||
| 597 | * | ||
| 598 | * Permission is hereby granted, free of charge, to any person obtaining | ||
| 599 | * a copy of this software and associated documentation files (the | ||
| 600 | * "Software"), to deal in the Software without restriction, including | ||
| 601 | * without limitation the rights to use, copy, modify, merge, publish, | ||
| 602 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 603 | * permit persons to whom the Software is furnished to do so, subject to | ||
| 604 | * the following conditions: | ||
| 605 | * | ||
| 606 | * The above copyright notice and this permission notice shall be | ||
| 607 | * included in all copies or substantial portions of the Software. | ||
| 608 | * | ||
| 609 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 610 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 611 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| 612 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
| 613 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 614 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 615 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 616 | *********************************************************************/ | ||
| 617 | |||
diff --git a/vendor/compat53/c-api/compat-5.3.h b/vendor/compat53/c-api/compat-5.3.h new file mode 100644 index 0000000..bee77a1 --- /dev/null +++ b/vendor/compat53/c-api/compat-5.3.h | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | #ifndef COMPAT53_H_ | ||
| 2 | #define COMPAT53_H_ | ||
| 3 | |||
| 4 | #include <stddef.h> | ||
| 5 | #include <limits.h> | ||
| 6 | #include <string.h> | ||
| 7 | #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) | ||
| 8 | extern "C" { | ||
| 9 | #endif | ||
| 10 | #include <lua.h> | ||
| 11 | #include <lauxlib.h> | ||
| 12 | #if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) | ||
| 13 | } | ||
| 14 | #endif | ||
| 15 | |||
| 16 | |||
| 17 | #if defined(COMPAT53_PREFIX) | ||
| 18 | /* - change the symbol names of functions to avoid linker conflicts | ||
| 19 | * - compat-5.3.c needs to be compiled (and linked) separately | ||
| 20 | */ | ||
| 21 | # if !defined(COMPAT53_API) | ||
| 22 | # define COMPAT53_API extern | ||
| 23 | # endif | ||
| 24 | # undef COMPAT53_INCLUDE_SOURCE | ||
| 25 | #else /* COMPAT53_PREFIX */ | ||
| 26 | /* - make all functions static and include the source. | ||
| 27 | * - compat-5.3.c doesn't need to be compiled (and linked) separately | ||
| 28 | */ | ||
| 29 | # define COMPAT53_PREFIX compat53 | ||
| 30 | # undef COMPAT53_API | ||
| 31 | # if defined(__GNUC__) || defined(__clang__) | ||
| 32 | # define COMPAT53_API __attribute__((__unused__)) static | ||
| 33 | # else | ||
| 34 | # define COMPAT53_API static | ||
| 35 | # endif | ||
| 36 | # define COMPAT53_INCLUDE_SOURCE | ||
| 37 | #endif /* COMPAT53_PREFIX */ | ||
| 38 | |||
| 39 | #define COMPAT53_CONCAT_HELPER(a, b) a##b | ||
| 40 | #define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) | ||
| 41 | |||
| 42 | |||
| 43 | |||
| 44 | /* declarations for Lua 5.1 */ | ||
| 45 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 | ||
| 46 | |||
| 47 | /* XXX not implemented: | ||
| 48 | * lua_arith (new operators) | ||
| 49 | * lua_upvalueid | ||
| 50 | * lua_upvaluejoin | ||
| 51 | * lua_version | ||
| 52 | * lua_yieldk | ||
| 53 | * luaL_loadbufferx | ||
| 54 | * luaL_loadfilex | ||
| 55 | */ | ||
| 56 | |||
| 57 | #ifndef LUA_OK | ||
| 58 | # define LUA_OK 0 | ||
| 59 | #endif | ||
| 60 | #ifndef LUA_OPADD | ||
| 61 | # define LUA_OPADD 0 | ||
| 62 | #endif | ||
| 63 | #ifndef LUA_OPSUB | ||
| 64 | # define LUA_OPSUB 1 | ||
| 65 | #endif | ||
| 66 | #ifndef LUA_OPMUL | ||
| 67 | # define LUA_OPMUL 2 | ||
| 68 | #endif | ||
| 69 | #ifndef LUA_OPDIV | ||
| 70 | # define LUA_OPDIV 3 | ||
| 71 | #endif | ||
| 72 | #ifndef LUA_OPMOD | ||
| 73 | # define LUA_OPMOD 4 | ||
| 74 | #endif | ||
| 75 | #ifndef LUA_OPPOW | ||
| 76 | # define LUA_OPPOW 5 | ||
| 77 | #endif | ||
| 78 | #ifndef LUA_OPUNM | ||
| 79 | # define LUA_OPUNM 6 | ||
| 80 | #endif | ||
| 81 | #ifndef LUA_OPEQ | ||
| 82 | # define LUA_OPEQ 0 | ||
| 83 | #endif | ||
| 84 | #ifndef LUA_OPLT | ||
| 85 | # define LUA_OPLT 1 | ||
| 86 | #endif | ||
| 87 | #ifndef LUA_OPLE | ||
| 88 | # define LUA_OPLE 2 | ||
| 89 | #endif | ||
| 90 | |||
| 91 | typedef size_t lua_Unsigned; | ||
| 92 | |||
| 93 | typedef struct luaL_Buffer_53 { | ||
| 94 | luaL_Buffer b; /* make incorrect code crash! */ | ||
| 95 | char *ptr; | ||
| 96 | size_t nelems; | ||
| 97 | size_t capacity; | ||
| 98 | lua_State *L2; | ||
| 99 | } luaL_Buffer_53; | ||
| 100 | #define luaL_Buffer luaL_Buffer_53 | ||
| 101 | |||
| 102 | #define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) | ||
| 103 | COMPAT53_API int lua_absindex (lua_State *L, int i); | ||
| 104 | |||
| 105 | #define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) | ||
| 106 | COMPAT53_API void lua_arith (lua_State *L, int op); | ||
| 107 | |||
| 108 | #define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) | ||
| 109 | COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op); | ||
| 110 | |||
| 111 | #define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) | ||
| 112 | COMPAT53_API void lua_copy (lua_State *L, int from, int to); | ||
| 113 | |||
| 114 | #define lua_getuservalue(L, i) \ | ||
| 115 | (lua_getfenv((L), (i)), lua_type((L), -1)) | ||
| 116 | #define lua_setuservalue(L, i) \ | ||
| 117 | (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) | ||
| 118 | |||
| 119 | #define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) | ||
| 120 | COMPAT53_API void lua_len (lua_State *L, int i); | ||
| 121 | |||
| 122 | #define lua_pushstring(L, s) \ | ||
| 123 | (lua_pushstring((L), (s)), lua_tostring((L), -1)) | ||
| 124 | |||
| 125 | #define lua_pushlstring(L, s, len) \ | ||
| 126 | ((((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))), lua_tostring((L), -1)) | ||
| 127 | |||
| 128 | #ifndef luaL_newlibtable | ||
| 129 | # define luaL_newlibtable(L, l) \ | ||
| 130 | (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) | ||
| 131 | #endif | ||
| 132 | #ifndef luaL_newlib | ||
| 133 | # define luaL_newlib(L, l) \ | ||
| 134 | (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) | ||
| 135 | #endif | ||
| 136 | |||
| 137 | #define lua_pushglobaltable(L) \ | ||
| 138 | lua_pushvalue((L), LUA_GLOBALSINDEX) | ||
| 139 | |||
| 140 | #define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) | ||
| 141 | COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p); | ||
| 142 | |||
| 143 | #define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) | ||
| 144 | COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); | ||
| 145 | |||
| 146 | #define lua_rawlen(L, i) lua_objlen((L), (i)) | ||
| 147 | |||
| 148 | #define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx) | ||
| 149 | COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum); | ||
| 150 | |||
| 151 | #define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) | ||
| 152 | COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); | ||
| 153 | |||
| 154 | #define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) | ||
| 155 | COMPAT53_API void luaL_checkversion (lua_State *L); | ||
| 156 | |||
| 157 | #define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) | ||
| 158 | COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); | ||
| 159 | |||
| 160 | #define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) | ||
| 161 | COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name); | ||
| 162 | |||
| 163 | #define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) | ||
| 164 | COMPAT53_API lua_Integer luaL_len (lua_State *L, int i); | ||
| 165 | |||
| 166 | #define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) | ||
| 167 | COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); | ||
| 168 | |||
| 169 | #define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) | ||
| 170 | COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname); | ||
| 171 | |||
| 172 | #define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) | ||
| 173 | COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname); | ||
| 174 | |||
| 175 | #define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) | ||
| 176 | COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); | ||
| 177 | |||
| 178 | #define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) | ||
| 179 | COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname); | ||
| 180 | |||
| 181 | #define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) | ||
| 182 | COMPAT53_API int luaL_execresult (lua_State *L, int stat); | ||
| 183 | |||
| 184 | #define lua_callk(L, na, nr, ctx, cont) \ | ||
| 185 | ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) | ||
| 186 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ | ||
| 187 | ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) | ||
| 188 | |||
| 189 | #define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) | ||
| 190 | COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B); | ||
| 191 | |||
| 192 | #define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) | ||
| 193 | COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s); | ||
| 194 | |||
| 195 | #define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) | ||
| 196 | COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l); | ||
| 197 | |||
| 198 | #define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) | ||
| 199 | COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B); | ||
| 200 | |||
| 201 | #define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) | ||
| 202 | COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B); | ||
| 203 | |||
| 204 | #undef luaL_buffinitsize | ||
| 205 | #define luaL_buffinitsize(L, B, s) \ | ||
| 206 | (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) | ||
| 207 | |||
| 208 | #undef luaL_prepbuffer | ||
| 209 | #define luaL_prepbuffer(B) \ | ||
| 210 | luaL_prepbuffsize((B), LUAL_BUFFERSIZE) | ||
| 211 | |||
| 212 | #undef luaL_addchar | ||
| 213 | #define luaL_addchar(B, c) \ | ||
| 214 | ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ | ||
| 215 | ((B)->ptr[(B)->nelems++] = (c))) | ||
| 216 | |||
| 217 | #undef luaL_addsize | ||
| 218 | #define luaL_addsize(B, s) \ | ||
| 219 | ((B)->nelems += (s)) | ||
| 220 | |||
| 221 | #undef luaL_addstring | ||
| 222 | #define luaL_addstring(B, s) \ | ||
| 223 | luaL_addlstring((B), (s), strlen((s))) | ||
| 224 | |||
| 225 | #undef luaL_pushresultsize | ||
| 226 | #define luaL_pushresultsize(B, s) \ | ||
| 227 | (luaL_addsize((B), (s)), luaL_pushresult((B))) | ||
| 228 | |||
| 229 | #if defined(LUA_COMPAT_APIINTCASTS) | ||
| 230 | #define lua_pushunsigned(L, n) \ | ||
| 231 | lua_pushinteger((L), (lua_Integer)(n)) | ||
| 232 | #define lua_tounsignedx(L, i, is) \ | ||
| 233 | ((lua_Unsigned)lua_tointegerx((L), (i), (is))) | ||
| 234 | #define lua_tounsigned(L, i) \ | ||
| 235 | lua_tounsignedx((L), (i), NULL) | ||
| 236 | #define luaL_checkunsigned(L, a) \ | ||
| 237 | ((lua_Unsigned)luaL_checkinteger((L), (a))) | ||
| 238 | #define luaL_optunsigned(L, a, d) \ | ||
| 239 | ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) | ||
| 240 | #endif | ||
| 241 | |||
| 242 | #endif /* Lua 5.1 only */ | ||
| 243 | |||
| 244 | |||
| 245 | |||
| 246 | /* declarations for Lua 5.1 and 5.2 */ | ||
| 247 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 | ||
| 248 | |||
| 249 | typedef int lua_KContext; | ||
| 250 | |||
| 251 | typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); | ||
| 252 | |||
| 253 | #define lua_dump(L, w, d, s) \ | ||
| 254 | ((void)(s), lua_dump((L), (w), (d))) | ||
| 255 | |||
| 256 | #define lua_getfield(L, i, k) \ | ||
| 257 | (lua_getfield((L), (i), (k)), lua_type((L), -1)) | ||
| 258 | |||
| 259 | #define lua_gettable(L, i) \ | ||
| 260 | (lua_gettable((L), (i)), lua_type((L), -1)) | ||
| 261 | |||
| 262 | #define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) | ||
| 263 | COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i); | ||
| 264 | |||
| 265 | #define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) | ||
| 266 | COMPAT53_API int lua_isinteger (lua_State *L, int index); | ||
| 267 | |||
| 268 | #define lua_numbertointeger(n, p) \ | ||
| 269 | ((*(p) = (lua_Integer)(n)), 1) | ||
| 270 | |||
| 271 | #define lua_rawget(L, i) \ | ||
| 272 | (lua_rawget((L), (i)), lua_type((L), -1)) | ||
| 273 | |||
| 274 | #define lua_rawgeti(L, i, n) \ | ||
| 275 | (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) | ||
| 276 | |||
| 277 | #define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) | ||
| 278 | COMPAT53_API void lua_rotate (lua_State *L, int idx, int n); | ||
| 279 | |||
| 280 | #define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) | ||
| 281 | COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i); | ||
| 282 | |||
| 283 | #define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) | ||
| 284 | COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s); | ||
| 285 | |||
| 286 | #define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) | ||
| 287 | COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); | ||
| 288 | |||
| 289 | #define luaL_getmetafield(L, o, e) \ | ||
| 290 | (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) | ||
| 291 | |||
| 292 | #define luaL_newmetatable(L, tn) \ | ||
| 293 | (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) | ||
| 294 | |||
| 295 | #define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) | ||
| 296 | COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, | ||
| 297 | lua_CFunction openf, int glb ); | ||
| 298 | |||
| 299 | #endif /* Lua 5.1 and Lua 5.2 */ | ||
| 300 | |||
| 301 | |||
| 302 | |||
| 303 | /* declarations for Lua 5.2 */ | ||
| 304 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 | ||
| 305 | |||
| 306 | /* XXX not implemented: | ||
| 307 | * lua_isyieldable | ||
| 308 | * lua_getextraspace | ||
| 309 | * lua_arith (new operators) | ||
| 310 | * lua_pushfstring (new formats) | ||
| 311 | */ | ||
| 312 | |||
| 313 | #define lua_getglobal(L, n) \ | ||
| 314 | (lua_getglobal((L), (n)), lua_type((L), -1)) | ||
| 315 | |||
| 316 | #define lua_getuservalue(L, i) \ | ||
| 317 | (lua_getuservalue((L), (i)), lua_type((L), -1)) | ||
| 318 | |||
| 319 | #define lua_pushlstring(L, s, len) \ | ||
| 320 | (((len) == 0) ? lua_pushlstring((L), "", 0) : lua_pushlstring((L), (s), (len))) | ||
| 321 | |||
| 322 | #define lua_rawgetp(L, i, p) \ | ||
| 323 | (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) | ||
| 324 | |||
| 325 | #define LUA_KFUNCTION(_name) \ | ||
| 326 | static int (_name)(lua_State *L, int status, lua_KContext ctx); \ | ||
| 327 | static int (_name ## _52)(lua_State *L) { \ | ||
| 328 | lua_KContext ctx; \ | ||
| 329 | int status = lua_getctx(L, &ctx); \ | ||
| 330 | return (_name)(L, status, ctx); \ | ||
| 331 | } \ | ||
| 332 | static int (_name)(lua_State *L, int status, lua_KContext ctx) | ||
| 333 | |||
| 334 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ | ||
| 335 | lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) | ||
| 336 | |||
| 337 | #define lua_callk(L, na, nr, ctx, cont) \ | ||
| 338 | lua_callk((L), (na), (nr), (ctx), cont ## _52) | ||
| 339 | |||
| 340 | #define lua_yieldk(L, nr, ctx, cont) \ | ||
| 341 | lua_yieldk((L), (nr), (ctx), cont ## _52) | ||
| 342 | |||
| 343 | #ifdef lua_call | ||
| 344 | # undef lua_call | ||
| 345 | # define lua_call(L, na, nr) \ | ||
| 346 | (lua_callk)((L), (na), (nr), 0, NULL) | ||
| 347 | #endif | ||
| 348 | |||
| 349 | #ifdef lua_pcall | ||
| 350 | # undef lua_pcall | ||
| 351 | # define lua_pcall(L, na, nr, err) \ | ||
| 352 | (lua_pcallk)((L), (na), (nr), (err), 0, NULL) | ||
| 353 | #endif | ||
| 354 | |||
| 355 | #ifdef lua_yield | ||
| 356 | # undef lua_yield | ||
| 357 | # define lua_yield(L, nr) \ | ||
| 358 | (lua_yieldk)((L), (nr), 0, NULL) | ||
| 359 | #endif | ||
| 360 | |||
| 361 | #endif /* Lua 5.2 only */ | ||
| 362 | |||
| 363 | |||
| 364 | |||
| 365 | /* other Lua versions */ | ||
| 366 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 503 | ||
| 367 | |||
| 368 | # error "unsupported Lua version (i.e. not Lua 5.1, 5.2, or 5.3)" | ||
| 369 | |||
| 370 | #endif /* other Lua versions except 5.1, 5.2, and 5.3 */ | ||
| 371 | |||
| 372 | |||
| 373 | |||
| 374 | /* helper macro for defining continuation functions (for every version | ||
| 375 | * *except* Lua 5.2) */ | ||
| 376 | #ifndef LUA_KFUNCTION | ||
| 377 | #define LUA_KFUNCTION(_name) \ | ||
| 378 | static int (_name)(lua_State *L, int status, lua_KContext ctx) | ||
| 379 | #endif | ||
| 380 | |||
| 381 | |||
| 382 | #if defined(COMPAT53_INCLUDE_SOURCE) | ||
| 383 | # include "compat-5.3.c" | ||
| 384 | #endif | ||
| 385 | |||
| 386 | |||
| 387 | #endif /* COMPAT53_H_ */ | ||
| 388 | |||
diff --git a/vendor/compat53/compat53/init.lua b/vendor/compat53/compat53/init.lua new file mode 100644 index 0000000..a7f0c80 --- /dev/null +++ b/vendor/compat53/compat53/init.lua | |||
| @@ -0,0 +1,373 @@ | |||
| 1 | local lua_version = _VERSION:sub(-3) | ||
| 2 | |||
| 3 | |||
| 4 | if lua_version < "5.3" then | ||
| 5 | |||
| 6 | local _G, pairs, require, select, type = | ||
| 7 | _G, pairs, require, select, type | ||
| 8 | local debug, io = debug, io | ||
| 9 | local unpack = lua_version == "5.1" and unpack or table.unpack | ||
| 10 | |||
| 11 | local M = require("compat53.module") | ||
| 12 | |||
| 13 | -- select the most powerful getmetatable function available | ||
| 14 | local gmt = type(debug) == "table" and debug.getmetatable or | ||
| 15 | getmetatable or function() return false end | ||
| 16 | -- metatable for file objects from Lua's standard io library | ||
| 17 | local file_meta = gmt(io.stdout) | ||
| 18 | |||
| 19 | |||
| 20 | -- make '*' optional for file:read and file:lines | ||
| 21 | if type(file_meta) == "table" and type(file_meta.__index) == "table" then | ||
| 22 | |||
| 23 | local function addasterisk(fmt) | ||
| 24 | if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then | ||
| 25 | return "*"..fmt | ||
| 26 | else | ||
| 27 | return fmt | ||
| 28 | end | ||
| 29 | end | ||
| 30 | |||
| 31 | local file_lines = file_meta.__index.lines | ||
| 32 | file_meta.__index.lines = function(self, ...) | ||
| 33 | local n = select('#', ...) | ||
| 34 | for i = 1, n do | ||
| 35 | local a = select(i, ...) | ||
| 36 | local b = addasterisk(a) | ||
| 37 | -- as an optimization we only allocate a table for the | ||
| 38 | -- modified format arguments when we have a '*' somewhere | ||
| 39 | if a ~= b then | ||
| 40 | local args = { ... } | ||
| 41 | args[i] = b | ||
| 42 | for j = i+1, n do | ||
| 43 | args[j] = addasterisk(args[j]) | ||
| 44 | end | ||
| 45 | return file_lines(self, unpack(args, 1, n)) | ||
| 46 | end | ||
| 47 | end | ||
| 48 | return file_lines(self, ...) | ||
| 49 | end | ||
| 50 | |||
| 51 | local file_read = file_meta.__index.read | ||
| 52 | file_meta.__index.read = function(self, ...) | ||
| 53 | local n = select('#', ...) | ||
| 54 | for i = 1, n do | ||
| 55 | local a = select(i, ...) | ||
| 56 | local b = addasterisk(a) | ||
| 57 | -- as an optimization we only allocate a table for the | ||
| 58 | -- modified format arguments when we have a '*' somewhere | ||
| 59 | if a ~= b then | ||
| 60 | local args = { ... } | ||
| 61 | args[i] = b | ||
| 62 | for j = i+1, n do | ||
| 63 | args[j] = addasterisk(args[j]) | ||
| 64 | end | ||
| 65 | return file_read(self, unpack(args, 1, n)) | ||
| 66 | end | ||
| 67 | end | ||
| 68 | return file_read(self, ...) | ||
| 69 | end | ||
| 70 | |||
| 71 | end -- got a valid metatable for file objects | ||
| 72 | |||
| 73 | |||
| 74 | -- changes for Lua 5.1 only | ||
| 75 | if lua_version == "5.1" then | ||
| 76 | |||
| 77 | -- cache globals | ||
| 78 | local error, pcall, rawset, setmetatable, tostring, xpcall = | ||
| 79 | error, pcall, rawset, setmetatable, tostring, xpcall | ||
| 80 | local coroutine, package, string = coroutine, package, string | ||
| 81 | local coroutine_resume = coroutine.resume | ||
| 82 | local coroutine_running = coroutine.running | ||
| 83 | local coroutine_status = coroutine.status | ||
| 84 | local coroutine_yield = coroutine.yield | ||
| 85 | local io_type = io.type | ||
| 86 | |||
| 87 | |||
| 88 | -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) | ||
| 89 | local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" | ||
| 90 | local is_luajit52 = is_luajit and | ||
| 91 | #setmetatable({}, { __len = function() return 1 end }) == 1 | ||
| 92 | |||
| 93 | |||
| 94 | -- make package.searchers available as an alias for package.loaders | ||
| 95 | local p_index = { searchers = package.loaders } | ||
| 96 | setmetatable(package, { | ||
| 97 | __index = p_index, | ||
| 98 | __newindex = function(p, k, v) | ||
| 99 | if k == "searchers" then | ||
| 100 | rawset(p, "loaders", v) | ||
| 101 | p_index.searchers = v | ||
| 102 | else | ||
| 103 | rawset(p, k, v) | ||
| 104 | end | ||
| 105 | end | ||
| 106 | }) | ||
| 107 | |||
| 108 | |||
| 109 | if type(file_meta) == "table" and type(file_meta.__index) == "table" then | ||
| 110 | if not is_luajit then | ||
| 111 | local function helper(_, var_1, ...) | ||
| 112 | if var_1 == nil then | ||
| 113 | if (...) ~= nil then | ||
| 114 | error((...), 2) | ||
| 115 | end | ||
| 116 | end | ||
| 117 | return var_1, ... | ||
| 118 | end | ||
| 119 | |||
| 120 | local function lines_iterator(st) | ||
| 121 | return helper(st, st.f:read(unpack(st, 1, st.n))) | ||
| 122 | end | ||
| 123 | |||
| 124 | local file_write = file_meta.__index.write | ||
| 125 | file_meta.__index.write = function(self, ...) | ||
| 126 | local res, msg, errno = file_write(self, ...) | ||
| 127 | if res then | ||
| 128 | return self | ||
| 129 | else | ||
| 130 | return nil, msg, errno | ||
| 131 | end | ||
| 132 | end | ||
| 133 | |||
| 134 | file_meta.__index.lines = function(self, ...) | ||
| 135 | if io_type(self) == "closed file" then | ||
| 136 | error("attempt to use a closed file", 2) | ||
| 137 | end | ||
| 138 | local st = { f=self, n=select('#', ...), ... } | ||
| 139 | for i = 1, st.n do | ||
| 140 | local t = type(st[i]) | ||
| 141 | if t == "string" then | ||
| 142 | local fmt = st[i]:match("^*?([aln])") | ||
| 143 | if not fmt then | ||
| 144 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) | ||
| 145 | end | ||
| 146 | st[i] = "*"..fmt | ||
| 147 | elseif t ~= "number" then | ||
| 148 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) | ||
| 149 | end | ||
| 150 | end | ||
| 151 | return lines_iterator, st | ||
| 152 | end | ||
| 153 | end -- not luajit | ||
| 154 | end -- file_meta valid | ||
| 155 | |||
| 156 | |||
| 157 | -- the (x)pcall implementations start a new coroutine internally | ||
| 158 | -- to allow yielding even in Lua 5.1. to allow for accurate | ||
| 159 | -- stack traces we keep track of the nested coroutine activations | ||
| 160 | -- in the weak tables below: | ||
| 161 | local weak_meta = { __mode = "kv" } | ||
| 162 | -- maps the internal pcall coroutines to the user coroutine that | ||
| 163 | -- *should* be running if pcall didn't use coroutines internally | ||
| 164 | local pcall_mainOf = setmetatable({}, weak_meta) | ||
| 165 | -- table that maps each running coroutine started by pcall to | ||
| 166 | -- the coroutine that resumed it (user coroutine *or* pcall | ||
| 167 | -- coroutine!) | ||
| 168 | local pcall_previous = setmetatable({}, weak_meta) | ||
| 169 | -- reverse of `pcall_mainOf`. maps a user coroutine to the | ||
| 170 | -- currently active pcall coroutine started within it | ||
| 171 | local pcall_callOf = setmetatable({}, weak_meta) | ||
| 172 | -- similar to `pcall_mainOf` but is used only while executing | ||
| 173 | -- the error handler of xpcall (thus no nesting is necessary!) | ||
| 174 | local xpcall_running = setmetatable({}, weak_meta) | ||
| 175 | |||
| 176 | -- handle debug functions | ||
| 177 | if type(debug) == "table" then | ||
| 178 | local debug_getinfo = debug.getinfo | ||
| 179 | local debug_traceback = debug.traceback | ||
| 180 | |||
| 181 | if not is_luajit then | ||
| 182 | local function calculate_trace_level(co, level) | ||
| 183 | if level ~= nil then | ||
| 184 | for out = 1, 1/0 do | ||
| 185 | local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") | ||
| 186 | if info == nil then | ||
| 187 | local max = out-1 | ||
| 188 | if level <= max then | ||
| 189 | return level | ||
| 190 | end | ||
| 191 | return nil, level-max | ||
| 192 | end | ||
| 193 | end | ||
| 194 | end | ||
| 195 | return 1 | ||
| 196 | end | ||
| 197 | |||
| 198 | local stack_pattern = "\nstack traceback:" | ||
| 199 | local stack_replace = "" | ||
| 200 | function debug.traceback(co, msg, level) | ||
| 201 | local lvl | ||
| 202 | local nilmsg | ||
| 203 | if type(co) ~= "thread" then | ||
| 204 | co, msg, level = coroutine_running(), co, msg | ||
| 205 | end | ||
| 206 | if msg == nil then | ||
| 207 | msg = "" | ||
| 208 | nilmsg = true | ||
| 209 | elseif type(msg) ~= "string" then | ||
| 210 | return msg | ||
| 211 | end | ||
| 212 | if co == nil then | ||
| 213 | msg = debug_traceback(msg, level or 1) | ||
| 214 | else | ||
| 215 | local xpco = xpcall_running[co] | ||
| 216 | if xpco ~= nil then | ||
| 217 | lvl, level = calculate_trace_level(xpco, level) | ||
| 218 | if lvl then | ||
| 219 | msg = debug_traceback(xpco, msg, lvl) | ||
| 220 | else | ||
| 221 | msg = msg..stack_pattern | ||
| 222 | end | ||
| 223 | lvl, level = calculate_trace_level(co, level) | ||
| 224 | if lvl then | ||
| 225 | local trace = debug_traceback(co, "", lvl) | ||
| 226 | msg = msg..trace:gsub(stack_pattern, stack_replace) | ||
| 227 | end | ||
| 228 | else | ||
| 229 | co = pcall_callOf[co] or co | ||
| 230 | lvl, level = calculate_trace_level(co, level) | ||
| 231 | if lvl then | ||
| 232 | msg = debug_traceback(co, msg, lvl) | ||
| 233 | else | ||
| 234 | msg = msg..stack_pattern | ||
| 235 | end | ||
| 236 | end | ||
| 237 | co = pcall_previous[co] | ||
| 238 | while co ~= nil do | ||
| 239 | lvl, level = calculate_trace_level(co, level) | ||
| 240 | if lvl then | ||
| 241 | local trace = debug_traceback(co, "", lvl) | ||
| 242 | msg = msg..trace:gsub(stack_pattern, stack_replace) | ||
| 243 | end | ||
| 244 | co = pcall_previous[co] | ||
| 245 | end | ||
| 246 | end | ||
| 247 | if nilmsg then | ||
| 248 | msg = msg:gsub("^\n", "") | ||
| 249 | end | ||
| 250 | msg = msg:gsub("\n\t%(tail call%): %?", "\000") | ||
| 251 | msg = msg:gsub("\n\t%.%.%.\n", "\001\n") | ||
| 252 | msg = msg:gsub("\n\t%.%.%.$", "\001") | ||
| 253 | msg = msg:gsub("(%z+)\001(%z+)", function(some, other) | ||
| 254 | return "\n\t(..."..#some+#other.."+ tail call(s)...)" | ||
| 255 | end) | ||
| 256 | msg = msg:gsub("\001(%z+)", function(zeros) | ||
| 257 | return "\n\t(..."..#zeros.."+ tail call(s)...)" | ||
| 258 | end) | ||
| 259 | msg = msg:gsub("(%z+)\001", function(zeros) | ||
| 260 | return "\n\t(..."..#zeros.."+ tail call(s)...)" | ||
| 261 | end) | ||
| 262 | msg = msg:gsub("%z+", function(zeros) | ||
| 263 | return "\n\t(..."..#zeros.." tail call(s)...)" | ||
| 264 | end) | ||
| 265 | msg = msg:gsub("\001", function() | ||
| 266 | return "\n\t..." | ||
| 267 | end) | ||
| 268 | return msg | ||
| 269 | end | ||
| 270 | end -- is not luajit | ||
| 271 | end -- debug table available | ||
| 272 | |||
| 273 | |||
| 274 | if not is_luajit52 then | ||
| 275 | local coroutine_running52 = M.coroutine.running | ||
| 276 | function M.coroutine.running() | ||
| 277 | local co, ismain = coroutine_running52() | ||
| 278 | if ismain then | ||
| 279 | return co, true | ||
| 280 | else | ||
| 281 | return pcall_mainOf[co] or co, false | ||
| 282 | end | ||
| 283 | end | ||
| 284 | end | ||
| 285 | |||
| 286 | if not is_luajit then | ||
| 287 | local function pcall_results(current, call, success, ...) | ||
| 288 | if coroutine_status(call) == "suspended" then | ||
| 289 | return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) | ||
| 290 | end | ||
| 291 | if pcall_previous then | ||
| 292 | pcall_previous[call] = nil | ||
| 293 | local main = pcall_mainOf[call] | ||
| 294 | if main == current then current = nil end | ||
| 295 | pcall_callOf[main] = current | ||
| 296 | end | ||
| 297 | pcall_mainOf[call] = nil | ||
| 298 | return success, ... | ||
| 299 | end | ||
| 300 | |||
| 301 | local function pcall_exec(current, call, ...) | ||
| 302 | local main = pcall_mainOf[current] or current | ||
| 303 | pcall_mainOf[call] = main | ||
| 304 | if pcall_previous then | ||
| 305 | pcall_previous[call] = current | ||
| 306 | pcall_callOf[main] = call | ||
| 307 | end | ||
| 308 | return pcall_results(current, call, coroutine_resume(call, ...)) | ||
| 309 | end | ||
| 310 | |||
| 311 | local coroutine_create52 = M.coroutine.create | ||
| 312 | |||
| 313 | local function pcall_coroutine(func) | ||
| 314 | if type(func) ~= "function" then | ||
| 315 | local callable = func | ||
| 316 | func = function (...) return callable(...) end | ||
| 317 | end | ||
| 318 | return coroutine_create52(func) | ||
| 319 | end | ||
| 320 | |||
| 321 | function M.pcall(func, ...) | ||
| 322 | local current = coroutine_running() | ||
| 323 | if not current then return pcall(func, ...) end | ||
| 324 | return pcall_exec(current, pcall_coroutine(func), ...) | ||
| 325 | end | ||
| 326 | |||
| 327 | local function xpcall_catch(current, call, msgh, success, ...) | ||
| 328 | if not success then | ||
| 329 | xpcall_running[current] = call | ||
| 330 | local ok, result = pcall(msgh, ...) | ||
| 331 | xpcall_running[current] = nil | ||
| 332 | if not ok then | ||
| 333 | return false, "error in error handling ("..tostring(result)..")" | ||
| 334 | end | ||
| 335 | return false, result | ||
| 336 | end | ||
| 337 | return true, ... | ||
| 338 | end | ||
| 339 | |||
| 340 | function M.xpcall(f, msgh, ...) | ||
| 341 | local current = coroutine_running() | ||
| 342 | if not current then | ||
| 343 | local args, n = { ... }, select('#', ...) | ||
| 344 | return xpcall(function() return f(unpack(args, 1, n)) end, msgh) | ||
| 345 | end | ||
| 346 | local call = pcall_coroutine(f) | ||
| 347 | return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) | ||
| 348 | end | ||
| 349 | end -- not luajit | ||
| 350 | |||
| 351 | end -- lua 5.1 | ||
| 352 | |||
| 353 | |||
| 354 | -- handle exporting to global scope | ||
| 355 | local function extend_table(from, to) | ||
| 356 | if from ~= to then | ||
| 357 | for k,v in pairs(from) do | ||
| 358 | if type(v) == "table" and | ||
| 359 | type(to[k]) == "table" and | ||
| 360 | v ~= to[k] then | ||
| 361 | extend_table(v, to[k]) | ||
| 362 | else | ||
| 363 | to[k] = v | ||
| 364 | end | ||
| 365 | end | ||
| 366 | end | ||
| 367 | end | ||
| 368 | |||
| 369 | extend_table(M, _G) | ||
| 370 | |||
| 371 | end -- lua < 5.3 | ||
| 372 | |||
| 373 | -- vi: set expandtab softtabstop=3 shiftwidth=3 : | ||
diff --git a/vendor/compat53/compat53/module.lua b/vendor/compat53/compat53/module.lua new file mode 100644 index 0000000..30be6b5 --- /dev/null +++ b/vendor/compat53/compat53/module.lua | |||
| @@ -0,0 +1,827 @@ | |||
| 1 | local _G, _VERSION = _G, _VERSION | ||
| 2 | local lua_version = _VERSION:sub(-3) | ||
| 3 | |||
| 4 | |||
| 5 | local M = _G | ||
| 6 | |||
| 7 | if lua_version < "5.3" then | ||
| 8 | |||
| 9 | -- cache globals in upvalues | ||
| 10 | local error, ipairs, pairs, pcall, require, select, setmetatable, type = | ||
| 11 | error, ipairs, pairs, pcall, require, select, setmetatable, type | ||
| 12 | local debug, io, math, package, string, table = | ||
| 13 | debug, io, math, package, string, table | ||
| 14 | local io_lines = io.lines | ||
| 15 | local io_read = io.read | ||
| 16 | local unpack = lua_version == "5.1" and unpack or table.unpack | ||
| 17 | |||
| 18 | -- create module table | ||
| 19 | M = {} | ||
| 20 | local M_meta = { | ||
| 21 | __index = _G, | ||
| 22 | -- __newindex is set at the end | ||
| 23 | } | ||
| 24 | setmetatable(M, M_meta) | ||
| 25 | |||
| 26 | -- create subtables | ||
| 27 | M.io = setmetatable({}, { __index = io }) | ||
| 28 | M.math = setmetatable({}, { __index = math }) | ||
| 29 | M.string = setmetatable({}, { __index = string }) | ||
| 30 | M.table = setmetatable({}, { __index = table }) | ||
| 31 | M.utf8 = {} | ||
| 32 | |||
| 33 | |||
| 34 | -- select the most powerful getmetatable function available | ||
| 35 | local gmt = type(debug) == "table" and debug.getmetatable or | ||
| 36 | getmetatable or function() return false end | ||
| 37 | |||
| 38 | -- type checking functions | ||
| 39 | local checkinteger -- forward declararation | ||
| 40 | |||
| 41 | local function argcheck(cond, i, f, extra) | ||
| 42 | if not cond then | ||
| 43 | error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0) | ||
| 44 | end | ||
| 45 | end | ||
| 46 | |||
| 47 | |||
| 48 | -- load utf8 library | ||
| 49 | local utf8_ok, utf8lib = pcall(require, "compat53.utf8") | ||
| 50 | if utf8_ok then | ||
| 51 | if lua_version == "5.1" then | ||
| 52 | utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" | ||
| 53 | end | ||
| 54 | for k,v in pairs(utf8lib) do | ||
| 55 | M.utf8[k] = v | ||
| 56 | end | ||
| 57 | package.loaded["utf8"] = M.utf8 | ||
| 58 | end | ||
| 59 | |||
| 60 | |||
| 61 | -- load table library | ||
| 62 | local table_ok, tablib = pcall(require, "compat53.table") | ||
| 63 | if table_ok then | ||
| 64 | for k,v in pairs(tablib) do | ||
| 65 | M.table[k] = v | ||
| 66 | end | ||
| 67 | end | ||
| 68 | |||
| 69 | |||
| 70 | -- load string packing functions | ||
| 71 | local str_ok, strlib = pcall(require, "compat53.string") | ||
| 72 | if str_ok then | ||
| 73 | for k,v in pairs(strlib) do | ||
| 74 | M.string[k] = v | ||
| 75 | end | ||
| 76 | end | ||
| 77 | |||
| 78 | |||
| 79 | -- try Roberto's struct module for string packing/unpacking if | ||
| 80 | -- compat53.string is unavailable | ||
| 81 | if not str_ok then | ||
| 82 | local struct_ok, struct = pcall(require, "struct") | ||
| 83 | if struct_ok then | ||
| 84 | M.string.pack = struct.pack | ||
| 85 | M.string.packsize = struct.size | ||
| 86 | M.string.unpack = struct.unpack | ||
| 87 | end | ||
| 88 | end | ||
| 89 | |||
| 90 | |||
| 91 | -- update math library | ||
| 92 | do | ||
| 93 | local maxint, minint = 1 | ||
| 94 | |||
| 95 | while maxint+1 > maxint and 2*maxint > maxint do | ||
| 96 | maxint = maxint * 2 | ||
| 97 | end | ||
| 98 | if 2*maxint <= maxint then | ||
| 99 | maxint = 2*maxint-1 | ||
| 100 | minint = -maxint-1 | ||
| 101 | else | ||
| 102 | maxint = maxint | ||
| 103 | minint = -maxint | ||
| 104 | end | ||
| 105 | M.math.maxinteger = maxint | ||
| 106 | M.math.mininteger = minint | ||
| 107 | |||
| 108 | function M.math.tointeger(n) | ||
| 109 | if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then | ||
| 110 | return n | ||
| 111 | end | ||
| 112 | return nil | ||
| 113 | end | ||
| 114 | |||
| 115 | function M.math.type(n) | ||
| 116 | if type(n) == "number" then | ||
| 117 | if n <= maxint and n >= minint and n % 1 == 0 then | ||
| 118 | return "integer" | ||
| 119 | else | ||
| 120 | return "float" | ||
| 121 | end | ||
| 122 | else | ||
| 123 | return nil | ||
| 124 | end | ||
| 125 | end | ||
| 126 | |||
| 127 | function checkinteger(x, i, f) | ||
| 128 | local t = type(x) | ||
| 129 | if t ~= "number" then | ||
| 130 | error("bad argument #"..i.." to '"..f.. | ||
| 131 | "' (number expected, got "..t..")", 0) | ||
| 132 | elseif x > maxint or x < minint or x % 1 ~= 0 then | ||
| 133 | error("bad argument #"..i.." to '"..f.. | ||
| 134 | "' (number has no integer representation)", 0) | ||
| 135 | else | ||
| 136 | return x | ||
| 137 | end | ||
| 138 | end | ||
| 139 | |||
| 140 | function M.math.ult(m, n) | ||
| 141 | m = checkinteger(m, "1", "math.ult") | ||
| 142 | n = checkinteger(n, "2", "math.ult") | ||
| 143 | if m >= 0 and n < 0 then | ||
| 144 | return true | ||
| 145 | elseif m < 0 and n >= 0 then | ||
| 146 | return false | ||
| 147 | else | ||
| 148 | return m < n | ||
| 149 | end | ||
| 150 | end | ||
| 151 | end | ||
| 152 | |||
| 153 | |||
| 154 | -- assert should allow non-string error objects | ||
| 155 | function M.assert(cond, ...) | ||
| 156 | if cond then | ||
| 157 | return cond, ... | ||
| 158 | elseif select('#', ...) > 0 then | ||
| 159 | error((...), 0) | ||
| 160 | else | ||
| 161 | error("assertion failed!", 0) | ||
| 162 | end | ||
| 163 | end | ||
| 164 | |||
| 165 | |||
| 166 | -- ipairs should respect __index metamethod | ||
| 167 | do | ||
| 168 | local function ipairs_iterator(st, var) | ||
| 169 | var = var + 1 | ||
| 170 | local val = st[var] | ||
| 171 | if val ~= nil then | ||
| 172 | return var, st[var] | ||
| 173 | end | ||
| 174 | end | ||
| 175 | function M.ipairs(t) | ||
| 176 | if gmt(t) ~= nil then -- t has metatable | ||
| 177 | return ipairs_iterator, t, 0 | ||
| 178 | else | ||
| 179 | return ipairs(t) | ||
| 180 | end | ||
| 181 | end | ||
| 182 | end | ||
| 183 | |||
| 184 | |||
| 185 | -- make '*' optional for io.read and io.lines | ||
| 186 | do | ||
| 187 | local function addasterisk(fmt) | ||
| 188 | if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then | ||
| 189 | return "*"..fmt | ||
| 190 | else | ||
| 191 | return fmt | ||
| 192 | end | ||
| 193 | end | ||
| 194 | |||
| 195 | function M.io.read(...) | ||
| 196 | local n = select('#', ...) | ||
| 197 | for i = 1, n do | ||
| 198 | local a = select(i, ...) | ||
| 199 | local b = addasterisk(a) | ||
| 200 | -- as an optimization we only allocate a table for the | ||
| 201 | -- modified format arguments when we have a '*' somewhere. | ||
| 202 | if a ~= b then | ||
| 203 | local args = { ... } | ||
| 204 | args[i] = b | ||
| 205 | for j = i+1, n do | ||
| 206 | args[j] = addasterisk(args[j]) | ||
| 207 | end | ||
| 208 | return io_read(unpack(args, 1, n)) | ||
| 209 | end | ||
| 210 | end | ||
| 211 | return io_read(...) | ||
| 212 | end | ||
| 213 | |||
| 214 | -- PUC-Rio Lua 5.1 uses a different implementation for io.lines! | ||
| 215 | function M.io.lines(...) | ||
| 216 | local n = select('#', ...) | ||
| 217 | for i = 2, n do | ||
| 218 | local a = select(i, ...) | ||
| 219 | local b = addasterisk(a) | ||
| 220 | -- as an optimization we only allocate a table for the | ||
| 221 | -- modified format arguments when we have a '*' somewhere. | ||
| 222 | if a ~= b then | ||
| 223 | local args = { ... } | ||
| 224 | args[i] = b | ||
| 225 | for j = i+1, n do | ||
| 226 | args[j] = addasterisk(args[j]) | ||
| 227 | end | ||
| 228 | return io_lines(unpack(args, 1, n)) | ||
| 229 | end | ||
| 230 | end | ||
| 231 | return io_lines(...) | ||
| 232 | end | ||
| 233 | end | ||
| 234 | |||
| 235 | |||
| 236 | -- update table library (if C module not available) | ||
| 237 | if not table_ok then | ||
| 238 | local table_concat = table.concat | ||
| 239 | local table_insert = table.insert | ||
| 240 | local table_remove = table.remove | ||
| 241 | local table_sort = table.sort | ||
| 242 | |||
| 243 | function M.table.concat(list, sep, i, j) | ||
| 244 | local mt = gmt(list) | ||
| 245 | if type(mt) == "table" and type(mt.__len) == "function" then | ||
| 246 | local src = list | ||
| 247 | list, i, j = {}, i or 1, j or mt.__len(src) | ||
| 248 | for k = i, j do | ||
| 249 | list[k] = src[k] | ||
| 250 | end | ||
| 251 | end | ||
| 252 | return table_concat(list, sep, i, j) | ||
| 253 | end | ||
| 254 | |||
| 255 | function M.table.insert(list, ...) | ||
| 256 | local mt = gmt(list) | ||
| 257 | local has_mt = type(mt) == "table" | ||
| 258 | local has_len = has_mt and type(mt.__len) == "function" | ||
| 259 | if has_mt and (has_len or mt.__index or mt.__newindex) then | ||
| 260 | local e = (has_len and mt.__len(list) or #list)+1 | ||
| 261 | local nargs, pos, value = select('#', ...), ... | ||
| 262 | if nargs == 1 then | ||
| 263 | pos, value = e, pos | ||
| 264 | elseif nargs == 2 then | ||
| 265 | pos = checkinteger(pos, "2", "table.insert") | ||
| 266 | argcheck(1 <= pos and pos <= e, "2", "table.insert", | ||
| 267 | "position out of bounds" ) | ||
| 268 | else | ||
| 269 | error("wrong number of arguments to 'insert'", 0) | ||
| 270 | end | ||
| 271 | for i = e-1, pos, -1 do | ||
| 272 | list[i+1] = list[i] | ||
| 273 | end | ||
| 274 | list[pos] = value | ||
| 275 | else | ||
| 276 | return table_insert(list, ...) | ||
| 277 | end | ||
| 278 | end | ||
| 279 | |||
| 280 | function M.table.move(a1, f, e, t, a2) | ||
| 281 | a2 = a2 or a1 | ||
| 282 | f = checkinteger(f, "2", "table.move") | ||
| 283 | argcheck(f > 0, "2", "table.move", | ||
| 284 | "initial position must be positive") | ||
| 285 | e = checkinteger(e, "3", "table.move") | ||
| 286 | t = checkinteger(t, "4", "table.move") | ||
| 287 | if e >= f then | ||
| 288 | local m, n, d = 0, e-f, 1 | ||
| 289 | if t > f then m, n, d = n, m, -1 end | ||
| 290 | for i = m, n, d do | ||
| 291 | a2[t+i] = a1[f+i] | ||
| 292 | end | ||
| 293 | end | ||
| 294 | return a2 | ||
| 295 | end | ||
| 296 | |||
| 297 | function M.table.remove(list, pos) | ||
| 298 | local mt = gmt(list) | ||
| 299 | local has_mt = type(mt) == "table" | ||
| 300 | local has_len = has_mt and type(mt.__len) == "function" | ||
| 301 | if has_mt and (has_len or mt.__index or mt.__newindex) then | ||
| 302 | local e = (has_len and mt.__len(list) or #list) | ||
| 303 | pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e | ||
| 304 | if pos ~= e then | ||
| 305 | argcheck(1 <= pos and pos <= e+1, "2", "table.remove", | ||
| 306 | "position out of bounds" ) | ||
| 307 | end | ||
| 308 | local result = list[pos] | ||
| 309 | while pos < e do | ||
| 310 | list[pos] = list[pos+1] | ||
| 311 | pos = pos + 1 | ||
| 312 | end | ||
| 313 | list[pos] = nil | ||
| 314 | return result | ||
| 315 | else | ||
| 316 | return table_remove(list, pos) | ||
| 317 | end | ||
| 318 | end | ||
| 319 | |||
| 320 | do | ||
| 321 | local function pivot(list, cmp, a, b) | ||
| 322 | local m = b - a | ||
| 323 | if m > 2 then | ||
| 324 | local c = a + (m-m%2)/2 | ||
| 325 | local x, y, z = list[a], list[b], list[c] | ||
| 326 | if not cmp(x, y) then | ||
| 327 | x, y, a, b = y, x, b, a | ||
| 328 | end | ||
| 329 | if not cmp(y, z) then | ||
| 330 | y, b = z, c | ||
| 331 | end | ||
| 332 | if not cmp(x, y) then | ||
| 333 | y, b = x, a | ||
| 334 | end | ||
| 335 | return b, y | ||
| 336 | else | ||
| 337 | return b, list[b] | ||
| 338 | end | ||
| 339 | end | ||
| 340 | |||
| 341 | local function lt_cmp(a, b) | ||
| 342 | return a < b | ||
| 343 | end | ||
| 344 | |||
| 345 | local function qsort(list, cmp, b, e) | ||
| 346 | if b < e then | ||
| 347 | local i, j, k, val = b, e, pivot(list, cmp, b, e) | ||
| 348 | while i < j do | ||
| 349 | while i < j and cmp(list[i], val) do | ||
| 350 | i = i + 1 | ||
| 351 | end | ||
| 352 | while i < j and not cmp(list[j], val) do | ||
| 353 | j = j - 1 | ||
| 354 | end | ||
| 355 | if i < j then | ||
| 356 | list[i], list[j] = list[j], list[i] | ||
| 357 | if i == k then k = j end -- update pivot position | ||
| 358 | i, j = i+1, j-1 | ||
| 359 | end | ||
| 360 | end | ||
| 361 | if i ~= k and not cmp(list[i], val) then | ||
| 362 | list[i], list[k] = val, list[i] | ||
| 363 | k = i -- update pivot position | ||
| 364 | end | ||
| 365 | qsort(list, cmp, b, i == k and i-1 or i) | ||
| 366 | return qsort(list, cmp, i+1, e) | ||
| 367 | end | ||
| 368 | end | ||
| 369 | |||
| 370 | function M.table.sort(list, cmp) | ||
| 371 | local mt = gmt(list) | ||
| 372 | local has_mt = type(mt) == "table" | ||
| 373 | local has_len = has_mt and type(mt.__len) == "function" | ||
| 374 | if has_len then | ||
| 375 | cmp = cmp or lt_cmp | ||
| 376 | local len = mt.__len(list) | ||
| 377 | return qsort(list, cmp, 1, len) | ||
| 378 | else | ||
| 379 | return table_sort(list, cmp) | ||
| 380 | end | ||
| 381 | end | ||
| 382 | end | ||
| 383 | |||
| 384 | local function unpack_helper(list, i, j, ...) | ||
| 385 | if j < i then | ||
| 386 | return ... | ||
| 387 | else | ||
| 388 | return unpack_helper(list, i, j-1, list[j], ...) | ||
| 389 | end | ||
| 390 | end | ||
| 391 | function M.table.unpack(list, i, j) | ||
| 392 | local mt = gmt(list) | ||
| 393 | local has_mt = type(mt) == "table" | ||
| 394 | local has_len = has_mt and type(mt.__len) == "function" | ||
| 395 | if has_mt and (has_len or mt.__index) then | ||
| 396 | i, j = i or 1, j or (has_len and mt.__len(list)) or #list | ||
| 397 | return unpack_helper(list, i, j) | ||
| 398 | else | ||
| 399 | return unpack(list, i, j) | ||
| 400 | end | ||
| 401 | end | ||
| 402 | end -- update table library | ||
| 403 | |||
| 404 | |||
| 405 | -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 | ||
| 406 | if lua_version == "5.1" then | ||
| 407 | -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) | ||
| 408 | local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" | ||
| 409 | local is_luajit52 = is_luajit and | ||
| 410 | #setmetatable({}, { __len = function() return 1 end }) == 1 | ||
| 411 | |||
| 412 | -- cache globals in upvalues | ||
| 413 | local load, loadfile, loadstring, setfenv, xpcall = | ||
| 414 | load, loadfile, loadstring, setfenv, xpcall | ||
| 415 | local coroutine, os = coroutine, os | ||
| 416 | local coroutine_create = coroutine.create | ||
| 417 | local coroutine_resume = coroutine.resume | ||
| 418 | local coroutine_running = coroutine.running | ||
| 419 | local coroutine_status = coroutine.status | ||
| 420 | local coroutine_yield = coroutine.yield | ||
| 421 | local io_input = io.input | ||
| 422 | local io_open = io.open | ||
| 423 | local io_output = io.output | ||
| 424 | local io_write = io.write | ||
| 425 | local math_log = math.log | ||
| 426 | local os_execute = os.execute | ||
| 427 | local string_find = string.find | ||
| 428 | local string_format = string.format | ||
| 429 | local string_gmatch = string.gmatch | ||
| 430 | local string_gsub = string.gsub | ||
| 431 | local string_match = string.match | ||
| 432 | local string_rep = string.rep | ||
| 433 | local table_concat = table.concat | ||
| 434 | |||
| 435 | -- create subtables | ||
| 436 | M.coroutine = setmetatable({}, { __index = coroutine }) | ||
| 437 | M.os = setmetatable({}, { __index = os }) | ||
| 438 | M.package = setmetatable({}, { __index = package }) | ||
| 439 | |||
| 440 | -- handle debug functions | ||
| 441 | if type(debug) == "table" then | ||
| 442 | local debug_setfenv = debug.setfenv | ||
| 443 | local debug_getfenv = debug.getfenv | ||
| 444 | local debug_setmetatable = debug.setmetatable | ||
| 445 | |||
| 446 | M.debug = setmetatable({}, { __index = debug }) | ||
| 447 | |||
| 448 | if not is_luajit52 then | ||
| 449 | function M.debug.setuservalue(obj, value) | ||
| 450 | if type(obj) ~= "userdata" then | ||
| 451 | error("bad argument #1 to 'setuservalue' (userdata expected, got ".. | ||
| 452 | type(obj)..")", 2) | ||
| 453 | end | ||
| 454 | if value == nil then value = _G end | ||
| 455 | if type(value) ~= "table" then | ||
| 456 | error("bad argument #2 to 'setuservalue' (table expected, got ".. | ||
| 457 | type(value)..")", 2) | ||
| 458 | end | ||
| 459 | return debug_setfenv(obj, value) | ||
| 460 | end | ||
| 461 | |||
| 462 | function M.debug.getuservalue(obj) | ||
| 463 | if type(obj) ~= "userdata" then | ||
| 464 | return nil | ||
| 465 | else | ||
| 466 | local v = debug_getfenv(obj) | ||
| 467 | if v == _G or v == package then | ||
| 468 | return nil | ||
| 469 | end | ||
| 470 | return v | ||
| 471 | end | ||
| 472 | end | ||
| 473 | |||
| 474 | function M.debug.setmetatable(value, tab) | ||
| 475 | debug_setmetatable(value, tab) | ||
| 476 | return value | ||
| 477 | end | ||
| 478 | end -- not luajit with compat52 enabled | ||
| 479 | end -- debug table available | ||
| 480 | |||
| 481 | |||
| 482 | if not is_luajit52 then | ||
| 483 | function M.pairs(t) | ||
| 484 | local mt = gmt(t) | ||
| 485 | if type(mt) == "table" and type(mt.__pairs) == "function" then | ||
| 486 | return mt.__pairs(t) | ||
| 487 | else | ||
| 488 | return pairs(t) | ||
| 489 | end | ||
| 490 | end | ||
| 491 | end | ||
| 492 | |||
| 493 | |||
| 494 | if not is_luajit then | ||
| 495 | local function check_mode(mode, prefix) | ||
| 496 | local has = { text = false, binary = false } | ||
| 497 | for i = 1,#mode do | ||
| 498 | local c = mode:sub(i, i) | ||
| 499 | if c == "t" then has.text = true end | ||
| 500 | if c == "b" then has.binary = true end | ||
| 501 | end | ||
| 502 | local t = prefix:sub(1, 1) == "\27" and "binary" or "text" | ||
| 503 | if not has[t] then | ||
| 504 | return "attempt to load a "..t.." chunk (mode is '"..mode.."')" | ||
| 505 | end | ||
| 506 | end | ||
| 507 | |||
| 508 | function M.load(ld, source, mode, env) | ||
| 509 | mode = mode or "bt" | ||
| 510 | local chunk, msg | ||
| 511 | if type( ld ) == "string" then | ||
| 512 | if mode ~= "bt" then | ||
| 513 | local merr = check_mode(mode, ld) | ||
| 514 | if merr then return nil, merr end | ||
| 515 | end | ||
| 516 | chunk, msg = loadstring(ld, source) | ||
| 517 | else | ||
| 518 | local ld_type = type(ld) | ||
| 519 | if ld_type ~= "function" then | ||
| 520 | error("bad argument #1 to 'load' (function expected, got ".. | ||
| 521 | ld_type..")", 2) | ||
| 522 | end | ||
| 523 | if mode ~= "bt" then | ||
| 524 | local checked, merr = false, nil | ||
| 525 | local function checked_ld() | ||
| 526 | if checked then | ||
| 527 | return ld() | ||
| 528 | else | ||
| 529 | checked = true | ||
| 530 | local v = ld() | ||
| 531 | merr = check_mode(mode, v or "") | ||
| 532 | if merr then return nil end | ||
| 533 | return v | ||
| 534 | end | ||
| 535 | end | ||
| 536 | chunk, msg = load(checked_ld, source) | ||
| 537 | if merr then return nil, merr end | ||
| 538 | else | ||
| 539 | chunk, msg = load(ld, source) | ||
| 540 | end | ||
| 541 | end | ||
| 542 | if not chunk then | ||
| 543 | return chunk, msg | ||
| 544 | end | ||
| 545 | if env ~= nil then | ||
| 546 | setfenv(chunk, env) | ||
| 547 | end | ||
| 548 | return chunk | ||
| 549 | end | ||
| 550 | |||
| 551 | M.loadstring = M.load | ||
| 552 | |||
| 553 | function M.loadfile(file, mode, env) | ||
| 554 | mode = mode or "bt" | ||
| 555 | if mode ~= "bt" then | ||
| 556 | local f = io_open(file, "rb") | ||
| 557 | if f then | ||
| 558 | local prefix = f:read(1) | ||
| 559 | f:close() | ||
| 560 | if prefix then | ||
| 561 | local merr = check_mode(mode, prefix) | ||
| 562 | if merr then return nil, merr end | ||
| 563 | end | ||
| 564 | end | ||
| 565 | end | ||
| 566 | local chunk, msg = loadfile(file) | ||
| 567 | if not chunk then | ||
| 568 | return chunk, msg | ||
| 569 | end | ||
| 570 | if env ~= nil then | ||
| 571 | setfenv(chunk, env) | ||
| 572 | end | ||
| 573 | return chunk | ||
| 574 | end | ||
| 575 | end -- not luajit | ||
| 576 | |||
| 577 | |||
| 578 | if not is_luajit52 then | ||
| 579 | function M.rawlen(v) | ||
| 580 | local t = type(v) | ||
| 581 | if t ~= "string" and t ~= "table" then | ||
| 582 | error("bad argument #1 to 'rawlen' (table or string expected)", 2) | ||
| 583 | end | ||
| 584 | return #v | ||
| 585 | end | ||
| 586 | end | ||
| 587 | |||
| 588 | |||
| 589 | if not is_luajit then | ||
| 590 | function M.xpcall(f, msgh, ...) | ||
| 591 | local args, n = { ... }, select('#', ...) | ||
| 592 | return xpcall(function() return f(unpack(args, 1, n)) end, msgh) | ||
| 593 | end | ||
| 594 | end | ||
| 595 | |||
| 596 | |||
| 597 | if not is_luajit52 then | ||
| 598 | function M.os.execute(cmd) | ||
| 599 | local code = os_execute(cmd) | ||
| 600 | -- Lua 5.1 does not report exit by signal. | ||
| 601 | if code == 0 then | ||
| 602 | return true, "exit", code | ||
| 603 | else | ||
| 604 | if package.config:sub(1, 1) == '/' then | ||
| 605 | code = code/256 -- only correct on Linux! | ||
| 606 | end | ||
| 607 | return nil, "exit", code | ||
| 608 | end | ||
| 609 | end | ||
| 610 | end | ||
| 611 | |||
| 612 | |||
| 613 | if not table_ok and not is_luajit52 then | ||
| 614 | M.table.pack = function(...) | ||
| 615 | return { n = select('#', ...), ... } | ||
| 616 | end | ||
| 617 | end | ||
| 618 | |||
| 619 | |||
| 620 | local main_coroutine = coroutine_create(function() end) | ||
| 621 | |||
| 622 | function M.coroutine.create(func) | ||
| 623 | local success, result = pcall(coroutine_create, func) | ||
| 624 | if not success then | ||
| 625 | if type(func) ~= "function" then | ||
| 626 | error("bad argument #1 (function expected)", 0) | ||
| 627 | end | ||
| 628 | result = coroutine_create(function(...) return func(...) end) | ||
| 629 | end | ||
| 630 | return result | ||
| 631 | end | ||
| 632 | |||
| 633 | if not is_luajit52 then | ||
| 634 | function M.coroutine.running() | ||
| 635 | local co = coroutine_running() | ||
| 636 | if co then | ||
| 637 | return co, false | ||
| 638 | else | ||
| 639 | return main_coroutine, true | ||
| 640 | end | ||
| 641 | end | ||
| 642 | end | ||
| 643 | |||
| 644 | function M.coroutine.yield(...) | ||
| 645 | local co, flag = coroutine_running() | ||
| 646 | if co and not flag then | ||
| 647 | return coroutine_yield(...) | ||
| 648 | else | ||
| 649 | error("attempt to yield from outside a coroutine", 0) | ||
| 650 | end | ||
| 651 | end | ||
| 652 | |||
| 653 | if not is_luajit then | ||
| 654 | function M.coroutine.resume(co, ...) | ||
| 655 | if co == main_coroutine then | ||
| 656 | return false, "cannot resume non-suspended coroutine" | ||
| 657 | else | ||
| 658 | return coroutine_resume(co, ...) | ||
| 659 | end | ||
| 660 | end | ||
| 661 | |||
| 662 | function M.coroutine.status(co) | ||
| 663 | local notmain = coroutine_running() | ||
| 664 | if co == main_coroutine then | ||
| 665 | return notmain and "normal" or "running" | ||
| 666 | else | ||
| 667 | return coroutine_status(co) | ||
| 668 | end | ||
| 669 | end | ||
| 670 | end -- not luajit | ||
| 671 | |||
| 672 | |||
| 673 | if not is_luajit then | ||
| 674 | M.math.log = function(x, base) | ||
| 675 | if base ~= nil then | ||
| 676 | return math_log(x)/math_log(base) | ||
| 677 | else | ||
| 678 | return math_log(x) | ||
| 679 | end | ||
| 680 | end | ||
| 681 | end | ||
| 682 | |||
| 683 | |||
| 684 | if not is_luajit then | ||
| 685 | function M.package.searchpath(name, path, sep, rep) | ||
| 686 | sep = (sep or "."):gsub("(%p)", "%%%1") | ||
| 687 | rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") | ||
| 688 | local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") | ||
| 689 | local msg = {} | ||
| 690 | for subpath in path:gmatch("[^;]+") do | ||
| 691 | local fpath = subpath:gsub("%?", pname) | ||
| 692 | local f = io_open(fpath, "r") | ||
| 693 | if f then | ||
| 694 | f:close() | ||
| 695 | return fpath | ||
| 696 | end | ||
| 697 | msg[#msg+1] = "\n\tno file '" .. fpath .. "'" | ||
| 698 | end | ||
| 699 | return nil, table_concat(msg) | ||
| 700 | end | ||
| 701 | end | ||
| 702 | |||
| 703 | |||
| 704 | local function fix_pattern(pattern) | ||
| 705 | return (string_gsub(pattern, "%z", "%%z")) | ||
| 706 | end | ||
| 707 | |||
| 708 | function M.string.find(s, pattern, ...) | ||
| 709 | return string_find(s, fix_pattern(pattern), ...) | ||
| 710 | end | ||
| 711 | |||
| 712 | function M.string.gmatch(s, pattern) | ||
| 713 | return string_gmatch(s, fix_pattern(pattern)) | ||
| 714 | end | ||
| 715 | |||
| 716 | function M.string.gsub(s, pattern, ...) | ||
| 717 | return string_gsub(s, fix_pattern(pattern), ...) | ||
| 718 | end | ||
| 719 | |||
| 720 | function M.string.match(s, pattern, ...) | ||
| 721 | return string_match(s, fix_pattern(pattern), ...) | ||
| 722 | end | ||
| 723 | |||
| 724 | if not is_luajit then | ||
| 725 | function M.string.rep(s, n, sep) | ||
| 726 | if sep ~= nil and sep ~= "" and n >= 2 then | ||
| 727 | return s .. string_rep(sep..s, n-1) | ||
| 728 | else | ||
| 729 | return string_rep(s, n) | ||
| 730 | end | ||
| 731 | end | ||
| 732 | end | ||
| 733 | |||
| 734 | if not is_luajit then | ||
| 735 | do | ||
| 736 | local addqt = { | ||
| 737 | ["\n"] = "\\\n", | ||
| 738 | ["\\"] = "\\\\", | ||
| 739 | ["\""] = "\\\"" | ||
| 740 | } | ||
| 741 | |||
| 742 | local function addquoted(c, d) | ||
| 743 | return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d | ||
| 744 | end | ||
| 745 | |||
| 746 | function M.string.format(fmt, ...) | ||
| 747 | local args, n = { ... }, select('#', ...) | ||
| 748 | local i = 0 | ||
| 749 | local function adjust_fmt(lead, mods, kind) | ||
| 750 | if #lead % 2 == 0 then | ||
| 751 | i = i + 1 | ||
| 752 | if kind == "s" then | ||
| 753 | args[i] = _G.tostring(args[i]) | ||
| 754 | elseif kind == "q" then | ||
| 755 | args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"' | ||
| 756 | return lead.."%"..mods.."s" | ||
| 757 | end | ||
| 758 | end | ||
| 759 | end | ||
| 760 | fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) | ||
| 761 | return string_format(fmt, unpack(args, 1, n)) | ||
| 762 | end | ||
| 763 | end | ||
| 764 | end | ||
| 765 | |||
| 766 | |||
| 767 | function M.io.write(...) | ||
| 768 | local res, msg, errno = io_write(...) | ||
| 769 | if res then | ||
| 770 | return io_output() | ||
| 771 | else | ||
| 772 | return nil, msg, errno | ||
| 773 | end | ||
| 774 | end | ||
| 775 | |||
| 776 | if not is_luajit then | ||
| 777 | local function helper(st, var_1, ...) | ||
| 778 | if var_1 == nil then | ||
| 779 | if st.doclose then st.f:close() end | ||
| 780 | if (...) ~= nil then | ||
| 781 | error((...), 2) | ||
| 782 | end | ||
| 783 | end | ||
| 784 | return var_1, ... | ||
| 785 | end | ||
| 786 | |||
| 787 | local function lines_iterator(st) | ||
| 788 | return helper(st, st.f:read(unpack(st, 1, st.n))) | ||
| 789 | end | ||
| 790 | |||
| 791 | function M.io.lines(fname, ...) | ||
| 792 | local doclose, file, msg | ||
| 793 | if fname ~= nil then | ||
| 794 | doclose, file, msg = true, io_open(fname, "r") | ||
| 795 | if not file then error(msg, 2) end | ||
| 796 | else | ||
| 797 | doclose, file = false, io_input() | ||
| 798 | end | ||
| 799 | local st = { f=file, doclose=doclose, n=select('#', ...), ... } | ||
| 800 | for i = 1, st.n do | ||
| 801 | local t = type(st[i]) | ||
| 802 | if t == "string" then | ||
| 803 | local fmt = st[i]:match("^%*?([aln])") | ||
| 804 | if not fmt then | ||
| 805 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) | ||
| 806 | end | ||
| 807 | st[i] = "*"..fmt | ||
| 808 | elseif t ~= "number" then | ||
| 809 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) | ||
| 810 | end | ||
| 811 | end | ||
| 812 | return lines_iterator, st | ||
| 813 | end | ||
| 814 | end -- not luajit | ||
| 815 | |||
| 816 | end -- lua 5.1 | ||
| 817 | |||
| 818 | -- further write should be forwarded to _G | ||
| 819 | M_meta.__newindex = _G | ||
| 820 | |||
| 821 | end -- lua < 5.3 | ||
| 822 | |||
| 823 | |||
| 824 | -- return module table | ||
| 825 | return M | ||
| 826 | |||
| 827 | -- vi: set expandtab softtabstop=3 shiftwidth=3 : | ||
diff --git a/vendor/compat53/lprefix.h b/vendor/compat53/lprefix.h new file mode 100644 index 0000000..0eb149f --- /dev/null +++ b/vendor/compat53/lprefix.h | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ | ||
| 3 | ** Definitions for Lua code that must come before any other header file | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef lprefix_h | ||
| 8 | #define lprefix_h | ||
| 9 | |||
| 10 | |||
| 11 | /* | ||
| 12 | ** Allows POSIX/XSI stuff | ||
| 13 | */ | ||
| 14 | #if !defined(LUA_USE_C89) /* { */ | ||
| 15 | |||
| 16 | #if !defined(_XOPEN_SOURCE) | ||
| 17 | #define _XOPEN_SOURCE 600 | ||
| 18 | #elif _XOPEN_SOURCE == 0 | ||
| 19 | #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ | ||
| 20 | #endif | ||
| 21 | |||
| 22 | /* | ||
| 23 | ** Allows manipulation of large files in gcc and some other compilers | ||
| 24 | */ | ||
| 25 | #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) | ||
| 26 | #define _LARGEFILE_SOURCE 1 | ||
| 27 | #define _FILE_OFFSET_BITS 64 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #endif /* } */ | ||
| 31 | |||
| 32 | |||
| 33 | /* | ||
| 34 | ** Windows stuff | ||
| 35 | */ | ||
| 36 | #if defined(_WIN32) /* { */ | ||
| 37 | |||
| 38 | #if !defined(_CRT_SECURE_NO_WARNINGS) | ||
| 39 | #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #endif /* } */ | ||
| 43 | |||
| 44 | |||
| 45 | /* COMPAT53 adaptation */ | ||
| 46 | #include "c-api/compat-5.3.h" | ||
| 47 | |||
| 48 | #undef LUAMOD_API | ||
| 49 | #define LUAMOD_API extern | ||
| 50 | |||
| 51 | |||
| 52 | #ifdef lutf8lib_c | ||
| 53 | # define luaopen_utf8 luaopen_compat53_utf8 | ||
| 54 | /* we don't support the %U format string of lua_pushfstring! | ||
| 55 | * code below adapted from the Lua 5.3 sources: | ||
| 56 | */ | ||
| 57 | static const char *compat53_utf8_escape (lua_State* L, long x) { | ||
| 58 | if (x < 0x80) { /* ASCII */ | ||
| 59 | char c = (char)x; | ||
| 60 | lua_pushlstring(L, &c, 1); | ||
| 61 | } else { | ||
| 62 | char buff[8] = { 0 }; | ||
| 63 | unsigned int mfb = 0x3f; | ||
| 64 | int n = 1; | ||
| 65 | do { | ||
| 66 | buff[8 - (n++)] = (char)(0x80|(x & 0x3f)); | ||
| 67 | x >>= 6; | ||
| 68 | mfb >>= 1; | ||
| 69 | } while (x > mfb); | ||
| 70 | buff[8-n] = (char)((~mfb << 1) | x); | ||
| 71 | lua_pushlstring(L, buff+8-n, n); | ||
| 72 | } | ||
| 73 | return lua_tostring(L, -1); | ||
| 74 | } | ||
| 75 | # define lua_pushfstring(L, fmt, l) \ | ||
| 76 | compat53_utf8_escape(L, l) | ||
| 77 | #endif | ||
| 78 | |||
| 79 | |||
| 80 | #ifdef ltablib_c | ||
| 81 | # define luaopen_table luaopen_compat53_table | ||
| 82 | # ifndef LUA_MAXINTEGER | ||
| 83 | /* conservative estimate: */ | ||
| 84 | # define LUA_MAXINTEGER INT_MAX | ||
| 85 | # endif | ||
| 86 | #endif /* ltablib_c */ | ||
| 87 | |||
| 88 | |||
| 89 | #ifdef lstrlib_c | ||
| 90 | #include <locale.h> | ||
| 91 | #include <lualib.h> | ||
| 92 | /* move the string library open function out of the way (we only take | ||
| 93 | * the string packing functions)! | ||
| 94 | */ | ||
| 95 | # define luaopen_string luaopen_string_XXX | ||
| 96 | /* used in string.format implementation, which we don't use: */ | ||
| 97 | # ifndef LUA_INTEGER_FRMLEN | ||
| 98 | # define LUA_INTEGER_FRMLEN "" | ||
| 99 | # define LUA_NUMBER_FRMLEN "" | ||
| 100 | # endif | ||
| 101 | # ifndef LUA_MININTEGER | ||
| 102 | # define LUA_MININTEGER 0 | ||
| 103 | # endif | ||
| 104 | # ifndef LUA_INTEGER_FMT | ||
| 105 | # define LUA_INTEGER_FMT "%d" | ||
| 106 | # endif | ||
| 107 | # ifndef LUAI_UACINT | ||
| 108 | # define LUAI_UACINT lua_Integer | ||
| 109 | # endif | ||
| 110 | /* different Lua 5.3 versions have conflicting variants of this macro | ||
| 111 | * in luaconf.h, there's a fallback implementation in lstrlib.c, and | ||
| 112 | * the macro isn't used for string (un)packing anyway! | ||
| 113 | * */ | ||
| 114 | # undef lua_number2strx | ||
| 115 | # if LUA_VERSION_NUM < 503 | ||
| 116 | /* lstrlib assumes that lua_Integer and lua_Unsigned have the same | ||
| 117 | * size, so we use the unsigned equivalent of ptrdiff_t! */ | ||
| 118 | # define lua_Unsigned size_t | ||
| 119 | # endif | ||
| 120 | # ifndef l_mathlim | ||
| 121 | # ifdef LUA_NUMBER_DOUBLE | ||
| 122 | # define l_mathlim(n) (DBL_##n) | ||
| 123 | # else | ||
| 124 | # define l_mathlim(n) (FLT_##n) | ||
| 125 | # endif | ||
| 126 | # endif | ||
| 127 | # ifndef l_mathop | ||
| 128 | # ifdef LUA_NUMBER_DOUBLE | ||
| 129 | # define l_mathop(op) op | ||
| 130 | # else | ||
| 131 | # define l_mathop(op) op##f | ||
| 132 | # endif | ||
| 133 | # endif | ||
| 134 | # ifndef lua_getlocaledecpoint | ||
| 135 | # define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) | ||
| 136 | # endif | ||
| 137 | # ifndef l_sprintf | ||
| 138 | # if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L | ||
| 139 | # define l_sprintf(s,sz,f,i) (snprintf(s, sz, f, i)) | ||
| 140 | # else | ||
| 141 | # define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s, f, i)) | ||
| 142 | # endif | ||
| 143 | # endif | ||
| 144 | |||
| 145 | static int str_pack (lua_State *L); | ||
| 146 | static int str_packsize (lua_State *L); | ||
| 147 | static int str_unpack (lua_State *L); | ||
| 148 | LUAMOD_API int luaopen_compat53_string (lua_State *L) { | ||
| 149 | luaL_Reg const funcs[] = { | ||
| 150 | { "pack", str_pack }, | ||
| 151 | { "packsize", str_packsize }, | ||
| 152 | { "unpack", str_unpack }, | ||
| 153 | { NULL, NULL } | ||
| 154 | }; | ||
| 155 | luaL_newlib(L, funcs); | ||
| 156 | return 1; | ||
| 157 | } | ||
| 158 | /* fake CLANG feature detection on other compilers */ | ||
| 159 | # ifndef __has_attribute | ||
| 160 | # define __has_attribute(x) 0 | ||
| 161 | # endif | ||
| 162 | /* make luaopen_string(_XXX) static, so it (and all other referenced | ||
| 163 | * string functions) won't be included in the resulting dll | ||
| 164 | * (hopefully). | ||
| 165 | */ | ||
| 166 | # undef LUAMOD_API | ||
| 167 | # if defined(__GNUC__) || __has_attribute(__unused__) | ||
| 168 | # define LUAMOD_API __attribute__((__unused__)) static | ||
| 169 | # else | ||
| 170 | # define LUAMOD_API static | ||
| 171 | # endif | ||
| 172 | #endif /* lstrlib.c */ | ||
| 173 | |||
| 174 | #endif | ||
| 175 | |||
diff --git a/vendor/compat53/lstrlib.c b/vendor/compat53/lstrlib.c new file mode 100644 index 0000000..c7aa755 --- /dev/null +++ b/vendor/compat53/lstrlib.c | |||
| @@ -0,0 +1,1584 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $ | ||
| 3 | ** Standard library for string operations and pattern-matching | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | #define lstrlib_c | ||
| 8 | #define LUA_LIB | ||
| 9 | |||
| 10 | #include "lprefix.h" | ||
| 11 | |||
| 12 | |||
| 13 | #include <ctype.h> | ||
| 14 | #include <float.h> | ||
| 15 | #include <limits.h> | ||
| 16 | #include <locale.h> | ||
| 17 | #include <stddef.h> | ||
| 18 | #include <stdio.h> | ||
| 19 | #include <stdlib.h> | ||
| 20 | #include <string.h> | ||
| 21 | |||
| 22 | #include "lua.h" | ||
| 23 | |||
| 24 | #include "lauxlib.h" | ||
| 25 | #include "lualib.h" | ||
| 26 | |||
| 27 | |||
| 28 | /* | ||
| 29 | ** maximum number of captures that a pattern can do during | ||
| 30 | ** pattern-matching. This limit is arbitrary, but must fit in | ||
| 31 | ** an unsigned char. | ||
| 32 | */ | ||
| 33 | #if !defined(LUA_MAXCAPTURES) | ||
| 34 | #define LUA_MAXCAPTURES 32 | ||
| 35 | #endif | ||
| 36 | |||
| 37 | |||
| 38 | /* macro to 'unsign' a character */ | ||
| 39 | #define uchar(c) ((unsigned char)(c)) | ||
| 40 | |||
| 41 | |||
| 42 | /* | ||
| 43 | ** Some sizes are better limited to fit in 'int', but must also fit in | ||
| 44 | ** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) | ||
| 45 | */ | ||
| 46 | #define MAX_SIZET ((size_t)(~(size_t)0)) | ||
| 47 | |||
| 48 | #define MAXSIZE \ | ||
| 49 | (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) | ||
| 50 | |||
| 51 | |||
| 52 | |||
| 53 | |||
| 54 | static int str_len (lua_State *L) { | ||
| 55 | size_t l; | ||
| 56 | luaL_checklstring(L, 1, &l); | ||
| 57 | lua_pushinteger(L, (lua_Integer)l); | ||
| 58 | return 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 62 | /* translate a relative string position: negative means back from end */ | ||
| 63 | static lua_Integer posrelat (lua_Integer pos, size_t len) { | ||
| 64 | if (pos >= 0) return pos; | ||
| 65 | else if (0u - (size_t)pos > len) return 0; | ||
| 66 | else return (lua_Integer)len + pos + 1; | ||
| 67 | } | ||
| 68 | |||
| 69 | |||
| 70 | static int str_sub (lua_State *L) { | ||
| 71 | size_t l; | ||
| 72 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 73 | lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); | ||
| 74 | lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); | ||
| 75 | if (start < 1) start = 1; | ||
| 76 | if (end > (lua_Integer)l) end = l; | ||
| 77 | if (start <= end) | ||
| 78 | lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); | ||
| 79 | else lua_pushliteral(L, ""); | ||
| 80 | return 1; | ||
| 81 | } | ||
| 82 | |||
| 83 | |||
| 84 | static int str_reverse (lua_State *L) { | ||
| 85 | size_t l, i; | ||
| 86 | luaL_Buffer b; | ||
| 87 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 88 | char *p = luaL_buffinitsize(L, &b, l); | ||
| 89 | for (i = 0; i < l; i++) | ||
| 90 | p[i] = s[l - i - 1]; | ||
| 91 | luaL_pushresultsize(&b, l); | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | static int str_lower (lua_State *L) { | ||
| 97 | size_t l; | ||
| 98 | size_t i; | ||
| 99 | luaL_Buffer b; | ||
| 100 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 101 | char *p = luaL_buffinitsize(L, &b, l); | ||
| 102 | for (i=0; i<l; i++) | ||
| 103 | p[i] = tolower(uchar(s[i])); | ||
| 104 | luaL_pushresultsize(&b, l); | ||
| 105 | return 1; | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | static int str_upper (lua_State *L) { | ||
| 110 | size_t l; | ||
| 111 | size_t i; | ||
| 112 | luaL_Buffer b; | ||
| 113 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 114 | char *p = luaL_buffinitsize(L, &b, l); | ||
| 115 | for (i=0; i<l; i++) | ||
| 116 | p[i] = toupper(uchar(s[i])); | ||
| 117 | luaL_pushresultsize(&b, l); | ||
| 118 | return 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | |||
| 122 | static int str_rep (lua_State *L) { | ||
| 123 | size_t l, lsep; | ||
| 124 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 125 | lua_Integer n = luaL_checkinteger(L, 2); | ||
| 126 | const char *sep = luaL_optlstring(L, 3, "", &lsep); | ||
| 127 | if (n <= 0) lua_pushliteral(L, ""); | ||
| 128 | else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ | ||
| 129 | return luaL_error(L, "resulting string too large"); | ||
| 130 | else { | ||
| 131 | size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; | ||
| 132 | luaL_Buffer b; | ||
| 133 | char *p = luaL_buffinitsize(L, &b, totallen); | ||
| 134 | while (n-- > 1) { /* first n-1 copies (followed by separator) */ | ||
| 135 | memcpy(p, s, l * sizeof(char)); p += l; | ||
| 136 | if (lsep > 0) { /* empty 'memcpy' is not that cheap */ | ||
| 137 | memcpy(p, sep, lsep * sizeof(char)); | ||
| 138 | p += lsep; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ | ||
| 142 | luaL_pushresultsize(&b, totallen); | ||
| 143 | } | ||
| 144 | return 1; | ||
| 145 | } | ||
| 146 | |||
| 147 | |||
| 148 | static int str_byte (lua_State *L) { | ||
| 149 | size_t l; | ||
| 150 | const char *s = luaL_checklstring(L, 1, &l); | ||
| 151 | lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); | ||
| 152 | lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); | ||
| 153 | int n, i; | ||
| 154 | if (posi < 1) posi = 1; | ||
| 155 | if (pose > (lua_Integer)l) pose = l; | ||
| 156 | if (posi > pose) return 0; /* empty interval; return no values */ | ||
| 157 | if (pose - posi >= INT_MAX) /* arithmetic overflow? */ | ||
| 158 | return luaL_error(L, "string slice too long"); | ||
| 159 | n = (int)(pose - posi) + 1; | ||
| 160 | luaL_checkstack(L, n, "string slice too long"); | ||
| 161 | for (i=0; i<n; i++) | ||
| 162 | lua_pushinteger(L, uchar(s[posi+i-1])); | ||
| 163 | return n; | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | static int str_char (lua_State *L) { | ||
| 168 | int n = lua_gettop(L); /* number of arguments */ | ||
| 169 | int i; | ||
| 170 | luaL_Buffer b; | ||
| 171 | char *p = luaL_buffinitsize(L, &b, n); | ||
| 172 | for (i=1; i<=n; i++) { | ||
| 173 | lua_Integer c = luaL_checkinteger(L, i); | ||
| 174 | luaL_argcheck(L, uchar(c) == c, i, "value out of range"); | ||
| 175 | p[i - 1] = uchar(c); | ||
| 176 | } | ||
| 177 | luaL_pushresultsize(&b, n); | ||
| 178 | return 1; | ||
| 179 | } | ||
| 180 | |||
| 181 | |||
| 182 | static int writer (lua_State *L, const void *b, size_t size, void *B) { | ||
| 183 | (void)L; | ||
| 184 | luaL_addlstring((luaL_Buffer *) B, (const char *)b, size); | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | |||
| 189 | static int str_dump (lua_State *L) { | ||
| 190 | luaL_Buffer b; | ||
| 191 | int strip = lua_toboolean(L, 2); | ||
| 192 | luaL_checktype(L, 1, LUA_TFUNCTION); | ||
| 193 | lua_settop(L, 1); | ||
| 194 | luaL_buffinit(L,&b); | ||
| 195 | if (lua_dump(L, writer, &b, strip) != 0) | ||
| 196 | return luaL_error(L, "unable to dump given function"); | ||
| 197 | luaL_pushresult(&b); | ||
| 198 | return 1; | ||
| 199 | } | ||
| 200 | |||
| 201 | |||
| 202 | |||
| 203 | /* | ||
| 204 | ** {====================================================== | ||
| 205 | ** PATTERN MATCHING | ||
| 206 | ** ======================================================= | ||
| 207 | */ | ||
| 208 | |||
| 209 | |||
| 210 | #define CAP_UNFINISHED (-1) | ||
| 211 | #define CAP_POSITION (-2) | ||
| 212 | |||
| 213 | |||
| 214 | typedef struct MatchState { | ||
| 215 | const char *src_init; /* init of source string */ | ||
| 216 | const char *src_end; /* end ('\0') of source string */ | ||
| 217 | const char *p_end; /* end ('\0') of pattern */ | ||
| 218 | lua_State *L; | ||
| 219 | int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ | ||
| 220 | unsigned char level; /* total number of captures (finished or unfinished) */ | ||
| 221 | struct { | ||
| 222 | const char *init; | ||
| 223 | ptrdiff_t len; | ||
| 224 | } capture[LUA_MAXCAPTURES]; | ||
| 225 | } MatchState; | ||
| 226 | |||
| 227 | |||
| 228 | /* recursive function */ | ||
| 229 | static const char *match (MatchState *ms, const char *s, const char *p); | ||
| 230 | |||
| 231 | |||
| 232 | /* maximum recursion depth for 'match' */ | ||
| 233 | #if !defined(MAXCCALLS) | ||
| 234 | #define MAXCCALLS 200 | ||
| 235 | #endif | ||
| 236 | |||
| 237 | |||
| 238 | #define L_ESC '%' | ||
| 239 | #define SPECIALS "^$*+?.([%-" | ||
| 240 | |||
| 241 | |||
| 242 | static int check_capture (MatchState *ms, int l) { | ||
| 243 | l -= '1'; | ||
| 244 | if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) | ||
| 245 | return luaL_error(ms->L, "invalid capture index %%%d", l + 1); | ||
| 246 | return l; | ||
| 247 | } | ||
| 248 | |||
| 249 | |||
| 250 | static int capture_to_close (MatchState *ms) { | ||
| 251 | int level = ms->level; | ||
| 252 | for (level--; level>=0; level--) | ||
| 253 | if (ms->capture[level].len == CAP_UNFINISHED) return level; | ||
| 254 | return luaL_error(ms->L, "invalid pattern capture"); | ||
| 255 | } | ||
| 256 | |||
| 257 | |||
| 258 | static const char *classend (MatchState *ms, const char *p) { | ||
| 259 | switch (*p++) { | ||
| 260 | case L_ESC: { | ||
| 261 | if (p == ms->p_end) | ||
| 262 | luaL_error(ms->L, "malformed pattern (ends with '%%')"); | ||
| 263 | return p+1; | ||
| 264 | } | ||
| 265 | case '[': { | ||
| 266 | if (*p == '^') p++; | ||
| 267 | do { /* look for a ']' */ | ||
| 268 | if (p == ms->p_end) | ||
| 269 | luaL_error(ms->L, "malformed pattern (missing ']')"); | ||
| 270 | if (*(p++) == L_ESC && p < ms->p_end) | ||
| 271 | p++; /* skip escapes (e.g. '%]') */ | ||
| 272 | } while (*p != ']'); | ||
| 273 | return p+1; | ||
| 274 | } | ||
| 275 | default: { | ||
| 276 | return p; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | |||
| 282 | static int match_class (int c, int cl) { | ||
| 283 | int res; | ||
| 284 | switch (tolower(cl)) { | ||
| 285 | case 'a' : res = isalpha(c); break; | ||
| 286 | case 'c' : res = iscntrl(c); break; | ||
| 287 | case 'd' : res = isdigit(c); break; | ||
| 288 | case 'g' : res = isgraph(c); break; | ||
| 289 | case 'l' : res = islower(c); break; | ||
| 290 | case 'p' : res = ispunct(c); break; | ||
| 291 | case 's' : res = isspace(c); break; | ||
| 292 | case 'u' : res = isupper(c); break; | ||
| 293 | case 'w' : res = isalnum(c); break; | ||
| 294 | case 'x' : res = isxdigit(c); break; | ||
| 295 | case 'z' : res = (c == 0); break; /* deprecated option */ | ||
| 296 | default: return (cl == c); | ||
| 297 | } | ||
| 298 | return (islower(cl) ? res : !res); | ||
| 299 | } | ||
| 300 | |||
| 301 | |||
| 302 | static int matchbracketclass (int c, const char *p, const char *ec) { | ||
| 303 | int sig = 1; | ||
| 304 | if (*(p+1) == '^') { | ||
| 305 | sig = 0; | ||
| 306 | p++; /* skip the '^' */ | ||
| 307 | } | ||
| 308 | while (++p < ec) { | ||
| 309 | if (*p == L_ESC) { | ||
| 310 | p++; | ||
| 311 | if (match_class(c, uchar(*p))) | ||
| 312 | return sig; | ||
| 313 | } | ||
| 314 | else if ((*(p+1) == '-') && (p+2 < ec)) { | ||
| 315 | p+=2; | ||
| 316 | if (uchar(*(p-2)) <= c && c <= uchar(*p)) | ||
| 317 | return sig; | ||
| 318 | } | ||
| 319 | else if (uchar(*p) == c) return sig; | ||
| 320 | } | ||
| 321 | return !sig; | ||
| 322 | } | ||
| 323 | |||
| 324 | |||
| 325 | static int singlematch (MatchState *ms, const char *s, const char *p, | ||
| 326 | const char *ep) { | ||
| 327 | if (s >= ms->src_end) | ||
| 328 | return 0; | ||
| 329 | else { | ||
| 330 | int c = uchar(*s); | ||
| 331 | switch (*p) { | ||
| 332 | case '.': return 1; /* matches any char */ | ||
| 333 | case L_ESC: return match_class(c, uchar(*(p+1))); | ||
| 334 | case '[': return matchbracketclass(c, p, ep-1); | ||
| 335 | default: return (uchar(*p) == c); | ||
| 336 | } | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | static const char *matchbalance (MatchState *ms, const char *s, | ||
| 342 | const char *p) { | ||
| 343 | if (p >= ms->p_end - 1) | ||
| 344 | luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); | ||
| 345 | if (*s != *p) return NULL; | ||
| 346 | else { | ||
| 347 | int b = *p; | ||
| 348 | int e = *(p+1); | ||
| 349 | int cont = 1; | ||
| 350 | while (++s < ms->src_end) { | ||
| 351 | if (*s == e) { | ||
| 352 | if (--cont == 0) return s+1; | ||
| 353 | } | ||
| 354 | else if (*s == b) cont++; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | return NULL; /* string ends out of balance */ | ||
| 358 | } | ||
| 359 | |||
| 360 | |||
| 361 | static const char *max_expand (MatchState *ms, const char *s, | ||
| 362 | const char *p, const char *ep) { | ||
| 363 | ptrdiff_t i = 0; /* counts maximum expand for item */ | ||
| 364 | while (singlematch(ms, s + i, p, ep)) | ||
| 365 | i++; | ||
| 366 | /* keeps trying to match with the maximum repetitions */ | ||
| 367 | while (i>=0) { | ||
| 368 | const char *res = match(ms, (s+i), ep+1); | ||
| 369 | if (res) return res; | ||
| 370 | i--; /* else didn't match; reduce 1 repetition to try again */ | ||
| 371 | } | ||
| 372 | return NULL; | ||
| 373 | } | ||
| 374 | |||
| 375 | |||
| 376 | static const char *min_expand (MatchState *ms, const char *s, | ||
| 377 | const char *p, const char *ep) { | ||
| 378 | for (;;) { | ||
| 379 | const char *res = match(ms, s, ep+1); | ||
| 380 | if (res != NULL) | ||
| 381 | return res; | ||
| 382 | else if (singlematch(ms, s, p, ep)) | ||
| 383 | s++; /* try with one more repetition */ | ||
| 384 | else return NULL; | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | static const char *start_capture (MatchState *ms, const char *s, | ||
| 390 | const char *p, int what) { | ||
| 391 | const char *res; | ||
| 392 | int level = ms->level; | ||
| 393 | if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); | ||
| 394 | ms->capture[level].init = s; | ||
| 395 | ms->capture[level].len = what; | ||
| 396 | ms->level = level+1; | ||
| 397 | if ((res=match(ms, s, p)) == NULL) /* match failed? */ | ||
| 398 | ms->level--; /* undo capture */ | ||
| 399 | return res; | ||
| 400 | } | ||
| 401 | |||
| 402 | |||
| 403 | static const char *end_capture (MatchState *ms, const char *s, | ||
| 404 | const char *p) { | ||
| 405 | int l = capture_to_close(ms); | ||
| 406 | const char *res; | ||
| 407 | ms->capture[l].len = s - ms->capture[l].init; /* close capture */ | ||
| 408 | if ((res = match(ms, s, p)) == NULL) /* match failed? */ | ||
| 409 | ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ | ||
| 410 | return res; | ||
| 411 | } | ||
| 412 | |||
| 413 | |||
| 414 | static const char *match_capture (MatchState *ms, const char *s, int l) { | ||
| 415 | size_t len; | ||
| 416 | l = check_capture(ms, l); | ||
| 417 | len = ms->capture[l].len; | ||
| 418 | if ((size_t)(ms->src_end-s) >= len && | ||
| 419 | memcmp(ms->capture[l].init, s, len) == 0) | ||
| 420 | return s+len; | ||
| 421 | else return NULL; | ||
| 422 | } | ||
| 423 | |||
| 424 | |||
| 425 | static const char *match (MatchState *ms, const char *s, const char *p) { | ||
| 426 | if (ms->matchdepth-- == 0) | ||
| 427 | luaL_error(ms->L, "pattern too complex"); | ||
| 428 | init: /* using goto's to optimize tail recursion */ | ||
| 429 | if (p != ms->p_end) { /* end of pattern? */ | ||
| 430 | switch (*p) { | ||
| 431 | case '(': { /* start capture */ | ||
| 432 | if (*(p + 1) == ')') /* position capture? */ | ||
| 433 | s = start_capture(ms, s, p + 2, CAP_POSITION); | ||
| 434 | else | ||
| 435 | s = start_capture(ms, s, p + 1, CAP_UNFINISHED); | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | case ')': { /* end capture */ | ||
| 439 | s = end_capture(ms, s, p + 1); | ||
| 440 | break; | ||
| 441 | } | ||
| 442 | case '$': { | ||
| 443 | if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ | ||
| 444 | goto dflt; /* no; go to default */ | ||
| 445 | s = (s == ms->src_end) ? s : NULL; /* check end of string */ | ||
| 446 | break; | ||
| 447 | } | ||
| 448 | case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ | ||
| 449 | switch (*(p + 1)) { | ||
| 450 | case 'b': { /* balanced string? */ | ||
| 451 | s = matchbalance(ms, s, p + 2); | ||
| 452 | if (s != NULL) { | ||
| 453 | p += 4; goto init; /* return match(ms, s, p + 4); */ | ||
| 454 | } /* else fail (s == NULL) */ | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | case 'f': { /* frontier? */ | ||
| 458 | const char *ep; char previous; | ||
| 459 | p += 2; | ||
| 460 | if (*p != '[') | ||
| 461 | luaL_error(ms->L, "missing '[' after '%%f' in pattern"); | ||
| 462 | ep = classend(ms, p); /* points to what is next */ | ||
| 463 | previous = (s == ms->src_init) ? '\0' : *(s - 1); | ||
| 464 | if (!matchbracketclass(uchar(previous), p, ep - 1) && | ||
| 465 | matchbracketclass(uchar(*s), p, ep - 1)) { | ||
| 466 | p = ep; goto init; /* return match(ms, s, ep); */ | ||
| 467 | } | ||
| 468 | s = NULL; /* match failed */ | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | case '0': case '1': case '2': case '3': | ||
| 472 | case '4': case '5': case '6': case '7': | ||
| 473 | case '8': case '9': { /* capture results (%0-%9)? */ | ||
| 474 | s = match_capture(ms, s, uchar(*(p + 1))); | ||
| 475 | if (s != NULL) { | ||
| 476 | p += 2; goto init; /* return match(ms, s, p + 2) */ | ||
| 477 | } | ||
| 478 | break; | ||
| 479 | } | ||
| 480 | default: goto dflt; | ||
| 481 | } | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | default: dflt: { /* pattern class plus optional suffix */ | ||
| 485 | const char *ep = classend(ms, p); /* points to optional suffix */ | ||
| 486 | /* does not match at least once? */ | ||
| 487 | if (!singlematch(ms, s, p, ep)) { | ||
| 488 | if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ | ||
| 489 | p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ | ||
| 490 | } | ||
| 491 | else /* '+' or no suffix */ | ||
| 492 | s = NULL; /* fail */ | ||
| 493 | } | ||
| 494 | else { /* matched once */ | ||
| 495 | switch (*ep) { /* handle optional suffix */ | ||
| 496 | case '?': { /* optional */ | ||
| 497 | const char *res; | ||
| 498 | if ((res = match(ms, s + 1, ep + 1)) != NULL) | ||
| 499 | s = res; | ||
| 500 | else { | ||
| 501 | p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ | ||
| 502 | } | ||
| 503 | break; | ||
| 504 | } | ||
| 505 | case '+': /* 1 or more repetitions */ | ||
| 506 | s++; /* 1 match already done */ | ||
| 507 | /* FALLTHROUGH */ | ||
| 508 | case '*': /* 0 or more repetitions */ | ||
| 509 | s = max_expand(ms, s, p, ep); | ||
| 510 | break; | ||
| 511 | case '-': /* 0 or more repetitions (minimum) */ | ||
| 512 | s = min_expand(ms, s, p, ep); | ||
| 513 | break; | ||
| 514 | default: /* no suffix */ | ||
| 515 | s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ | ||
| 516 | } | ||
| 517 | } | ||
| 518 | break; | ||
| 519 | } | ||
| 520 | } | ||
| 521 | } | ||
| 522 | ms->matchdepth++; | ||
| 523 | return s; | ||
| 524 | } | ||
| 525 | |||
| 526 | |||
| 527 | |||
| 528 | static const char *lmemfind (const char *s1, size_t l1, | ||
| 529 | const char *s2, size_t l2) { | ||
| 530 | if (l2 == 0) return s1; /* empty strings are everywhere */ | ||
| 531 | else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ | ||
| 532 | else { | ||
| 533 | const char *init; /* to search for a '*s2' inside 's1' */ | ||
| 534 | l2--; /* 1st char will be checked by 'memchr' */ | ||
| 535 | l1 = l1-l2; /* 's2' cannot be found after that */ | ||
| 536 | while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { | ||
| 537 | init++; /* 1st char is already checked */ | ||
| 538 | if (memcmp(init, s2+1, l2) == 0) | ||
| 539 | return init-1; | ||
| 540 | else { /* correct 'l1' and 's1' to try again */ | ||
| 541 | l1 -= init-s1; | ||
| 542 | s1 = init; | ||
| 543 | } | ||
| 544 | } | ||
| 545 | return NULL; /* not found */ | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | |||
| 550 | static void push_onecapture (MatchState *ms, int i, const char *s, | ||
| 551 | const char *e) { | ||
| 552 | if (i >= ms->level) { | ||
| 553 | if (i == 0) /* ms->level == 0, too */ | ||
| 554 | lua_pushlstring(ms->L, s, e - s); /* add whole match */ | ||
| 555 | else | ||
| 556 | luaL_error(ms->L, "invalid capture index %%%d", i + 1); | ||
| 557 | } | ||
| 558 | else { | ||
| 559 | ptrdiff_t l = ms->capture[i].len; | ||
| 560 | if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); | ||
| 561 | if (l == CAP_POSITION) | ||
| 562 | lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); | ||
| 563 | else | ||
| 564 | lua_pushlstring(ms->L, ms->capture[i].init, l); | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | |||
| 569 | static int push_captures (MatchState *ms, const char *s, const char *e) { | ||
| 570 | int i; | ||
| 571 | int nlevels = (ms->level == 0 && s) ? 1 : ms->level; | ||
| 572 | luaL_checkstack(ms->L, nlevels, "too many captures"); | ||
| 573 | for (i = 0; i < nlevels; i++) | ||
| 574 | push_onecapture(ms, i, s, e); | ||
| 575 | return nlevels; /* number of strings pushed */ | ||
| 576 | } | ||
| 577 | |||
| 578 | |||
| 579 | /* check whether pattern has no special characters */ | ||
| 580 | static int nospecials (const char *p, size_t l) { | ||
| 581 | size_t upto = 0; | ||
| 582 | do { | ||
| 583 | if (strpbrk(p + upto, SPECIALS)) | ||
| 584 | return 0; /* pattern has a special character */ | ||
| 585 | upto += strlen(p + upto) + 1; /* may have more after \0 */ | ||
| 586 | } while (upto <= l); | ||
| 587 | return 1; /* no special chars found */ | ||
| 588 | } | ||
| 589 | |||
| 590 | |||
| 591 | static void prepstate (MatchState *ms, lua_State *L, | ||
| 592 | const char *s, size_t ls, const char *p, size_t lp) { | ||
| 593 | ms->L = L; | ||
| 594 | ms->matchdepth = MAXCCALLS; | ||
| 595 | ms->src_init = s; | ||
| 596 | ms->src_end = s + ls; | ||
| 597 | ms->p_end = p + lp; | ||
| 598 | } | ||
| 599 | |||
| 600 | |||
| 601 | static void reprepstate (MatchState *ms) { | ||
| 602 | ms->level = 0; | ||
| 603 | lua_assert(ms->matchdepth == MAXCCALLS); | ||
| 604 | } | ||
| 605 | |||
| 606 | |||
| 607 | static int str_find_aux (lua_State *L, int find) { | ||
| 608 | size_t ls, lp; | ||
| 609 | const char *s = luaL_checklstring(L, 1, &ls); | ||
| 610 | const char *p = luaL_checklstring(L, 2, &lp); | ||
| 611 | lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); | ||
| 612 | if (init < 1) init = 1; | ||
| 613 | else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ | ||
| 614 | lua_pushnil(L); /* cannot find anything */ | ||
| 615 | return 1; | ||
| 616 | } | ||
| 617 | /* explicit request or no special characters? */ | ||
| 618 | if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { | ||
| 619 | /* do a plain search */ | ||
| 620 | const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); | ||
| 621 | if (s2) { | ||
| 622 | lua_pushinteger(L, (s2 - s) + 1); | ||
| 623 | lua_pushinteger(L, (s2 - s) + lp); | ||
| 624 | return 2; | ||
| 625 | } | ||
| 626 | } | ||
| 627 | else { | ||
| 628 | MatchState ms; | ||
| 629 | const char *s1 = s + init - 1; | ||
| 630 | int anchor = (*p == '^'); | ||
| 631 | if (anchor) { | ||
| 632 | p++; lp--; /* skip anchor character */ | ||
| 633 | } | ||
| 634 | prepstate(&ms, L, s, ls, p, lp); | ||
| 635 | do { | ||
| 636 | const char *res; | ||
| 637 | reprepstate(&ms); | ||
| 638 | if ((res=match(&ms, s1, p)) != NULL) { | ||
| 639 | if (find) { | ||
| 640 | lua_pushinteger(L, (s1 - s) + 1); /* start */ | ||
| 641 | lua_pushinteger(L, res - s); /* end */ | ||
| 642 | return push_captures(&ms, NULL, 0) + 2; | ||
| 643 | } | ||
| 644 | else | ||
| 645 | return push_captures(&ms, s1, res); | ||
| 646 | } | ||
| 647 | } while (s1++ < ms.src_end && !anchor); | ||
| 648 | } | ||
| 649 | lua_pushnil(L); /* not found */ | ||
| 650 | return 1; | ||
| 651 | } | ||
| 652 | |||
| 653 | |||
| 654 | static int str_find (lua_State *L) { | ||
| 655 | return str_find_aux(L, 1); | ||
| 656 | } | ||
| 657 | |||
| 658 | |||
| 659 | static int str_match (lua_State *L) { | ||
| 660 | return str_find_aux(L, 0); | ||
| 661 | } | ||
| 662 | |||
| 663 | |||
| 664 | /* state for 'gmatch' */ | ||
| 665 | typedef struct GMatchState { | ||
| 666 | const char *src; /* current position */ | ||
| 667 | const char *p; /* pattern */ | ||
| 668 | const char *lastmatch; /* end of last match */ | ||
| 669 | MatchState ms; /* match state */ | ||
| 670 | } GMatchState; | ||
| 671 | |||
| 672 | |||
| 673 | static int gmatch_aux (lua_State *L) { | ||
| 674 | GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); | ||
| 675 | const char *src; | ||
| 676 | gm->ms.L = L; | ||
| 677 | for (src = gm->src; src <= gm->ms.src_end; src++) { | ||
| 678 | const char *e; | ||
| 679 | reprepstate(&gm->ms); | ||
| 680 | if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { | ||
| 681 | gm->src = gm->lastmatch = e; | ||
| 682 | return push_captures(&gm->ms, src, e); | ||
| 683 | } | ||
| 684 | } | ||
| 685 | return 0; /* not found */ | ||
| 686 | } | ||
| 687 | |||
| 688 | |||
| 689 | static int gmatch (lua_State *L) { | ||
| 690 | size_t ls, lp; | ||
| 691 | const char *s = luaL_checklstring(L, 1, &ls); | ||
| 692 | const char *p = luaL_checklstring(L, 2, &lp); | ||
| 693 | GMatchState *gm; | ||
| 694 | lua_settop(L, 2); /* keep them on closure to avoid being collected */ | ||
| 695 | gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); | ||
| 696 | prepstate(&gm->ms, L, s, ls, p, lp); | ||
| 697 | gm->src = s; gm->p = p; gm->lastmatch = NULL; | ||
| 698 | lua_pushcclosure(L, gmatch_aux, 3); | ||
| 699 | return 1; | ||
| 700 | } | ||
| 701 | |||
| 702 | |||
| 703 | static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, | ||
| 704 | const char *e) { | ||
| 705 | size_t l, i; | ||
| 706 | lua_State *L = ms->L; | ||
| 707 | const char *news = lua_tolstring(L, 3, &l); | ||
| 708 | for (i = 0; i < l; i++) { | ||
| 709 | if (news[i] != L_ESC) | ||
| 710 | luaL_addchar(b, news[i]); | ||
| 711 | else { | ||
| 712 | i++; /* skip ESC */ | ||
| 713 | if (!isdigit(uchar(news[i]))) { | ||
| 714 | if (news[i] != L_ESC) | ||
| 715 | luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); | ||
| 716 | luaL_addchar(b, news[i]); | ||
| 717 | } | ||
| 718 | else if (news[i] == '0') | ||
| 719 | luaL_addlstring(b, s, e - s); | ||
| 720 | else { | ||
| 721 | push_onecapture(ms, news[i] - '1', s, e); | ||
| 722 | luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ | ||
| 723 | lua_remove(L, -2); /* remove original value */ | ||
| 724 | luaL_addvalue(b); /* add capture to accumulated result */ | ||
| 725 | } | ||
| 726 | } | ||
| 727 | } | ||
| 728 | } | ||
| 729 | |||
| 730 | |||
| 731 | static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, | ||
| 732 | const char *e, int tr) { | ||
| 733 | lua_State *L = ms->L; | ||
| 734 | switch (tr) { | ||
| 735 | case LUA_TFUNCTION: { | ||
| 736 | int n; | ||
| 737 | lua_pushvalue(L, 3); | ||
| 738 | n = push_captures(ms, s, e); | ||
| 739 | lua_call(L, n, 1); | ||
| 740 | break; | ||
| 741 | } | ||
| 742 | case LUA_TTABLE: { | ||
| 743 | push_onecapture(ms, 0, s, e); | ||
| 744 | lua_gettable(L, 3); | ||
| 745 | break; | ||
| 746 | } | ||
| 747 | default: { /* LUA_TNUMBER or LUA_TSTRING */ | ||
| 748 | add_s(ms, b, s, e); | ||
| 749 | return; | ||
| 750 | } | ||
| 751 | } | ||
| 752 | if (!lua_toboolean(L, -1)) { /* nil or false? */ | ||
| 753 | lua_pop(L, 1); | ||
| 754 | lua_pushlstring(L, s, e - s); /* keep original text */ | ||
| 755 | } | ||
| 756 | else if (!lua_isstring(L, -1)) | ||
| 757 | luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); | ||
| 758 | luaL_addvalue(b); /* add result to accumulator */ | ||
| 759 | } | ||
| 760 | |||
| 761 | |||
| 762 | static int str_gsub (lua_State *L) { | ||
| 763 | size_t srcl, lp; | ||
| 764 | const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ | ||
| 765 | const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ | ||
| 766 | const char *lastmatch = NULL; /* end of last match */ | ||
| 767 | int tr = lua_type(L, 3); /* replacement type */ | ||
| 768 | lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ | ||
| 769 | int anchor = (*p == '^'); | ||
| 770 | lua_Integer n = 0; /* replacement count */ | ||
| 771 | MatchState ms; | ||
| 772 | luaL_Buffer b; | ||
| 773 | luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || | ||
| 774 | tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, | ||
| 775 | "string/function/table expected"); | ||
| 776 | luaL_buffinit(L, &b); | ||
| 777 | if (anchor) { | ||
| 778 | p++; lp--; /* skip anchor character */ | ||
| 779 | } | ||
| 780 | prepstate(&ms, L, src, srcl, p, lp); | ||
| 781 | while (n < max_s) { | ||
| 782 | const char *e; | ||
| 783 | reprepstate(&ms); /* (re)prepare state for new match */ | ||
| 784 | if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ | ||
| 785 | n++; | ||
| 786 | add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ | ||
| 787 | src = lastmatch = e; | ||
| 788 | } | ||
| 789 | else if (src < ms.src_end) /* otherwise, skip one character */ | ||
| 790 | luaL_addchar(&b, *src++); | ||
| 791 | else break; /* end of subject */ | ||
| 792 | if (anchor) break; | ||
| 793 | } | ||
| 794 | luaL_addlstring(&b, src, ms.src_end-src); | ||
| 795 | luaL_pushresult(&b); | ||
| 796 | lua_pushinteger(L, n); /* number of substitutions */ | ||
| 797 | return 2; | ||
| 798 | } | ||
| 799 | |||
| 800 | /* }====================================================== */ | ||
| 801 | |||
| 802 | |||
| 803 | |||
| 804 | /* | ||
| 805 | ** {====================================================== | ||
| 806 | ** STRING FORMAT | ||
| 807 | ** ======================================================= | ||
| 808 | */ | ||
| 809 | |||
| 810 | #if !defined(lua_number2strx) /* { */ | ||
| 811 | |||
| 812 | /* | ||
| 813 | ** Hexadecimal floating-point formatter | ||
| 814 | */ | ||
| 815 | |||
| 816 | #include <math.h> | ||
| 817 | |||
| 818 | #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) | ||
| 819 | |||
| 820 | |||
| 821 | /* | ||
| 822 | ** Number of bits that goes into the first digit. It can be any value | ||
| 823 | ** between 1 and 4; the following definition tries to align the number | ||
| 824 | ** to nibble boundaries by making what is left after that first digit a | ||
| 825 | ** multiple of 4. | ||
| 826 | */ | ||
| 827 | #define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) | ||
| 828 | |||
| 829 | |||
| 830 | /* | ||
| 831 | ** Add integer part of 'x' to buffer and return new 'x' | ||
| 832 | */ | ||
| 833 | static lua_Number adddigit (char *buff, int n, lua_Number x) { | ||
| 834 | lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ | ||
| 835 | int d = (int)dd; | ||
| 836 | buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ | ||
| 837 | return x - dd; /* return what is left */ | ||
| 838 | } | ||
| 839 | |||
| 840 | |||
| 841 | static int num2straux (char *buff, int sz, lua_Number x) { | ||
| 842 | /* if 'inf' or 'NaN', format it like '%g' */ | ||
| 843 | if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) | ||
| 844 | return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); | ||
| 845 | else if (x == 0) { /* can be -0... */ | ||
| 846 | /* create "0" or "-0" followed by exponent */ | ||
| 847 | return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); | ||
| 848 | } | ||
| 849 | else { | ||
| 850 | int e; | ||
| 851 | lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ | ||
| 852 | int n = 0; /* character count */ | ||
| 853 | if (m < 0) { /* is number negative? */ | ||
| 854 | buff[n++] = '-'; /* add signal */ | ||
| 855 | m = -m; /* make it positive */ | ||
| 856 | } | ||
| 857 | buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ | ||
| 858 | m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ | ||
| 859 | e -= L_NBFD; /* this digit goes before the radix point */ | ||
| 860 | if (m > 0) { /* more digits? */ | ||
| 861 | buff[n++] = lua_getlocaledecpoint(); /* add radix point */ | ||
| 862 | do { /* add as many digits as needed */ | ||
| 863 | m = adddigit(buff, n++, m * 16); | ||
| 864 | } while (m > 0); | ||
| 865 | } | ||
| 866 | n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ | ||
| 867 | lua_assert(n < sz); | ||
| 868 | return n; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 872 | |||
| 873 | static int lua_number2strx (lua_State *L, char *buff, int sz, | ||
| 874 | const char *fmt, lua_Number x) { | ||
| 875 | int n = num2straux(buff, sz, x); | ||
| 876 | if (fmt[SIZELENMOD] == 'A') { | ||
| 877 | int i; | ||
| 878 | for (i = 0; i < n; i++) | ||
| 879 | buff[i] = toupper(uchar(buff[i])); | ||
| 880 | } | ||
| 881 | else if (fmt[SIZELENMOD] != 'a') | ||
| 882 | luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); | ||
| 883 | return n; | ||
| 884 | } | ||
| 885 | |||
| 886 | #endif /* } */ | ||
| 887 | |||
| 888 | |||
| 889 | /* | ||
| 890 | ** Maximum size of each formatted item. This maximum size is produced | ||
| 891 | ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', | ||
| 892 | ** and '\0') + number of decimal digits to represent maxfloat (which | ||
| 893 | ** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra | ||
| 894 | ** expenses", such as locale-dependent stuff) | ||
| 895 | */ | ||
| 896 | #define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) | ||
| 897 | |||
| 898 | |||
| 899 | /* valid flags in a format specification */ | ||
| 900 | #define FLAGS "-+ #0" | ||
| 901 | |||
| 902 | /* | ||
| 903 | ** maximum size of each format specification (such as "%-099.99d") | ||
| 904 | */ | ||
| 905 | #define MAX_FORMAT 32 | ||
| 906 | |||
| 907 | |||
| 908 | static void addquoted (luaL_Buffer *b, const char *s, size_t len) { | ||
| 909 | luaL_addchar(b, '"'); | ||
| 910 | while (len--) { | ||
| 911 | if (*s == '"' || *s == '\\' || *s == '\n') { | ||
| 912 | luaL_addchar(b, '\\'); | ||
| 913 | luaL_addchar(b, *s); | ||
| 914 | } | ||
| 915 | else if (iscntrl(uchar(*s))) { | ||
| 916 | char buff[10]; | ||
| 917 | if (!isdigit(uchar(*(s+1)))) | ||
| 918 | l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); | ||
| 919 | else | ||
| 920 | l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); | ||
| 921 | luaL_addstring(b, buff); | ||
| 922 | } | ||
| 923 | else | ||
| 924 | luaL_addchar(b, *s); | ||
| 925 | s++; | ||
| 926 | } | ||
| 927 | luaL_addchar(b, '"'); | ||
| 928 | } | ||
| 929 | |||
| 930 | |||
| 931 | /* | ||
| 932 | ** Ensures the 'buff' string uses a dot as the radix character. | ||
| 933 | */ | ||
| 934 | static void checkdp (char *buff, int nb) { | ||
| 935 | if (memchr(buff, '.', nb) == NULL) { /* no dot? */ | ||
| 936 | char point = lua_getlocaledecpoint(); /* try locale point */ | ||
| 937 | char *ppoint = (char *)memchr(buff, point, nb); | ||
| 938 | if (ppoint) *ppoint = '.'; /* change it to a dot */ | ||
| 939 | } | ||
| 940 | } | ||
| 941 | |||
| 942 | |||
| 943 | static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { | ||
| 944 | switch (lua_type(L, arg)) { | ||
| 945 | case LUA_TSTRING: { | ||
| 946 | size_t len; | ||
| 947 | const char *s = lua_tolstring(L, arg, &len); | ||
| 948 | addquoted(b, s, len); | ||
| 949 | break; | ||
| 950 | } | ||
| 951 | case LUA_TNUMBER: { | ||
| 952 | char *buff = luaL_prepbuffsize(b, MAX_ITEM); | ||
| 953 | int nb; | ||
| 954 | if (!lua_isinteger(L, arg)) { /* float? */ | ||
| 955 | lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ | ||
| 956 | nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); | ||
| 957 | checkdp(buff, nb); /* ensure it uses a dot */ | ||
| 958 | } | ||
| 959 | else { /* integers */ | ||
| 960 | lua_Integer n = lua_tointeger(L, arg); | ||
| 961 | const char *format = (n == LUA_MININTEGER) /* corner case? */ | ||
| 962 | ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ | ||
| 963 | : LUA_INTEGER_FMT; /* else use default format */ | ||
| 964 | nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); | ||
| 965 | } | ||
| 966 | luaL_addsize(b, nb); | ||
| 967 | break; | ||
| 968 | } | ||
| 969 | case LUA_TNIL: case LUA_TBOOLEAN: { | ||
| 970 | luaL_tolstring(L, arg, NULL); | ||
| 971 | luaL_addvalue(b); | ||
| 972 | break; | ||
| 973 | } | ||
| 974 | default: { | ||
| 975 | luaL_argerror(L, arg, "value has no literal form"); | ||
| 976 | } | ||
| 977 | } | ||
| 978 | } | ||
| 979 | |||
| 980 | |||
| 981 | static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { | ||
| 982 | const char *p = strfrmt; | ||
| 983 | while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ | ||
| 984 | if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) | ||
| 985 | luaL_error(L, "invalid format (repeated flags)"); | ||
| 986 | if (isdigit(uchar(*p))) p++; /* skip width */ | ||
| 987 | if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ | ||
| 988 | if (*p == '.') { | ||
| 989 | p++; | ||
| 990 | if (isdigit(uchar(*p))) p++; /* skip precision */ | ||
| 991 | if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ | ||
| 992 | } | ||
| 993 | if (isdigit(uchar(*p))) | ||
| 994 | luaL_error(L, "invalid format (width or precision too long)"); | ||
| 995 | *(form++) = '%'; | ||
| 996 | memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); | ||
| 997 | form += (p - strfrmt) + 1; | ||
| 998 | *form = '\0'; | ||
| 999 | return p; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | |||
| 1003 | /* | ||
| 1004 | ** add length modifier into formats | ||
| 1005 | */ | ||
| 1006 | static void addlenmod (char *form, const char *lenmod) { | ||
| 1007 | size_t l = strlen(form); | ||
| 1008 | size_t lm = strlen(lenmod); | ||
| 1009 | char spec = form[l - 1]; | ||
| 1010 | strcpy(form + l - 1, lenmod); | ||
| 1011 | form[l + lm - 1] = spec; | ||
| 1012 | form[l + lm] = '\0'; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | |||
| 1016 | static int str_format (lua_State *L) { | ||
| 1017 | int top = lua_gettop(L); | ||
| 1018 | int arg = 1; | ||
| 1019 | size_t sfl; | ||
| 1020 | const char *strfrmt = luaL_checklstring(L, arg, &sfl); | ||
| 1021 | const char *strfrmt_end = strfrmt+sfl; | ||
| 1022 | luaL_Buffer b; | ||
| 1023 | luaL_buffinit(L, &b); | ||
| 1024 | while (strfrmt < strfrmt_end) { | ||
| 1025 | if (*strfrmt != L_ESC) | ||
| 1026 | luaL_addchar(&b, *strfrmt++); | ||
| 1027 | else if (*++strfrmt == L_ESC) | ||
| 1028 | luaL_addchar(&b, *strfrmt++); /* %% */ | ||
| 1029 | else { /* format item */ | ||
| 1030 | char form[MAX_FORMAT]; /* to store the format ('%...') */ | ||
| 1031 | char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ | ||
| 1032 | int nb = 0; /* number of bytes in added item */ | ||
| 1033 | if (++arg > top) | ||
| 1034 | luaL_argerror(L, arg, "no value"); | ||
| 1035 | strfrmt = scanformat(L, strfrmt, form); | ||
| 1036 | switch (*strfrmt++) { | ||
| 1037 | case 'c': { | ||
| 1038 | nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); | ||
| 1039 | break; | ||
| 1040 | } | ||
| 1041 | case 'd': case 'i': | ||
| 1042 | case 'o': case 'u': case 'x': case 'X': { | ||
| 1043 | lua_Integer n = luaL_checkinteger(L, arg); | ||
| 1044 | addlenmod(form, LUA_INTEGER_FRMLEN); | ||
| 1045 | nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); | ||
| 1046 | break; | ||
| 1047 | } | ||
| 1048 | case 'a': case 'A': | ||
| 1049 | addlenmod(form, LUA_NUMBER_FRMLEN); | ||
| 1050 | nb = lua_number2strx(L, buff, MAX_ITEM, form, | ||
| 1051 | luaL_checknumber(L, arg)); | ||
| 1052 | break; | ||
| 1053 | case 'e': case 'E': case 'f': | ||
| 1054 | case 'g': case 'G': { | ||
| 1055 | lua_Number n = luaL_checknumber(L, arg); | ||
| 1056 | addlenmod(form, LUA_NUMBER_FRMLEN); | ||
| 1057 | nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); | ||
| 1058 | break; | ||
| 1059 | } | ||
| 1060 | case 'q': { | ||
| 1061 | addliteral(L, &b, arg); | ||
| 1062 | break; | ||
| 1063 | } | ||
| 1064 | case 's': { | ||
| 1065 | size_t l; | ||
| 1066 | const char *s = luaL_tolstring(L, arg, &l); | ||
| 1067 | if (form[2] == '\0') /* no modifiers? */ | ||
| 1068 | luaL_addvalue(&b); /* keep entire string */ | ||
| 1069 | else { | ||
| 1070 | luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); | ||
| 1071 | if (!strchr(form, '.') && l >= 100) { | ||
| 1072 | /* no precision and string is too long to be formatted */ | ||
| 1073 | luaL_addvalue(&b); /* keep entire string */ | ||
| 1074 | } | ||
| 1075 | else { /* format the string into 'buff' */ | ||
| 1076 | nb = l_sprintf(buff, MAX_ITEM, form, s); | ||
| 1077 | lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | break; | ||
| 1081 | } | ||
| 1082 | default: { /* also treat cases 'pnLlh' */ | ||
| 1083 | return luaL_error(L, "invalid option '%%%c' to 'format'", | ||
| 1084 | *(strfrmt - 1)); | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | lua_assert(nb < MAX_ITEM); | ||
| 1088 | luaL_addsize(&b, nb); | ||
| 1089 | } | ||
| 1090 | } | ||
| 1091 | luaL_pushresult(&b); | ||
| 1092 | return 1; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | /* }====================================================== */ | ||
| 1096 | |||
| 1097 | |||
| 1098 | /* | ||
| 1099 | ** {====================================================== | ||
| 1100 | ** PACK/UNPACK | ||
| 1101 | ** ======================================================= | ||
| 1102 | */ | ||
| 1103 | |||
| 1104 | |||
| 1105 | /* value used for padding */ | ||
| 1106 | #if !defined(LUAL_PACKPADBYTE) | ||
| 1107 | #define LUAL_PACKPADBYTE 0x00 | ||
| 1108 | #endif | ||
| 1109 | |||
| 1110 | /* maximum size for the binary representation of an integer */ | ||
| 1111 | #define MAXINTSIZE 16 | ||
| 1112 | |||
| 1113 | /* number of bits in a character */ | ||
| 1114 | #define NB CHAR_BIT | ||
| 1115 | |||
| 1116 | /* mask for one character (NB 1's) */ | ||
| 1117 | #define MC ((1 << NB) - 1) | ||
| 1118 | |||
| 1119 | /* size of a lua_Integer */ | ||
| 1120 | #define SZINT ((int)sizeof(lua_Integer)) | ||
| 1121 | |||
| 1122 | |||
| 1123 | /* dummy union to get native endianness */ | ||
| 1124 | static const union { | ||
| 1125 | int dummy; | ||
| 1126 | char little; /* true iff machine is little endian */ | ||
| 1127 | } nativeendian = {1}; | ||
| 1128 | |||
| 1129 | |||
| 1130 | /* dummy structure to get native alignment requirements */ | ||
| 1131 | struct cD { | ||
| 1132 | char c; | ||
| 1133 | union { double d; void *p; lua_Integer i; lua_Number n; } u; | ||
| 1134 | }; | ||
| 1135 | |||
| 1136 | #define MAXALIGN (offsetof(struct cD, u)) | ||
| 1137 | |||
| 1138 | |||
| 1139 | /* | ||
| 1140 | ** Union for serializing floats | ||
| 1141 | */ | ||
| 1142 | typedef union Ftypes { | ||
| 1143 | float f; | ||
| 1144 | double d; | ||
| 1145 | lua_Number n; | ||
| 1146 | char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ | ||
| 1147 | } Ftypes; | ||
| 1148 | |||
| 1149 | |||
| 1150 | /* | ||
| 1151 | ** information to pack/unpack stuff | ||
| 1152 | */ | ||
| 1153 | typedef struct Header { | ||
| 1154 | lua_State *L; | ||
| 1155 | int islittle; | ||
| 1156 | int maxalign; | ||
| 1157 | } Header; | ||
| 1158 | |||
| 1159 | |||
| 1160 | /* | ||
| 1161 | ** options for pack/unpack | ||
| 1162 | */ | ||
| 1163 | typedef enum KOption { | ||
| 1164 | Kint, /* signed integers */ | ||
| 1165 | Kuint, /* unsigned integers */ | ||
| 1166 | Kfloat, /* floating-point numbers */ | ||
| 1167 | Kchar, /* fixed-length strings */ | ||
| 1168 | Kstring, /* strings with prefixed length */ | ||
| 1169 | Kzstr, /* zero-terminated strings */ | ||
| 1170 | Kpadding, /* padding */ | ||
| 1171 | Kpaddalign, /* padding for alignment */ | ||
| 1172 | Knop /* no-op (configuration or spaces) */ | ||
| 1173 | } KOption; | ||
| 1174 | |||
| 1175 | |||
| 1176 | /* | ||
| 1177 | ** Read an integer numeral from string 'fmt' or return 'df' if | ||
| 1178 | ** there is no numeral | ||
| 1179 | */ | ||
| 1180 | static int digit (int c) { return '0' <= c && c <= '9'; } | ||
| 1181 | |||
| 1182 | static int getnum (const char **fmt, int df) { | ||
| 1183 | if (!digit(**fmt)) /* no number? */ | ||
| 1184 | return df; /* return default value */ | ||
| 1185 | else { | ||
| 1186 | int a = 0; | ||
| 1187 | do { | ||
| 1188 | a = a*10 + (*((*fmt)++) - '0'); | ||
| 1189 | } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); | ||
| 1190 | return a; | ||
| 1191 | } | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | |||
| 1195 | /* | ||
| 1196 | ** Read an integer numeral and raises an error if it is larger | ||
| 1197 | ** than the maximum size for integers. | ||
| 1198 | */ | ||
| 1199 | static int getnumlimit (Header *h, const char **fmt, int df) { | ||
| 1200 | int sz = getnum(fmt, df); | ||
| 1201 | if (sz > MAXINTSIZE || sz <= 0) | ||
| 1202 | luaL_error(h->L, "integral size (%d) out of limits [1,%d]", | ||
| 1203 | sz, MAXINTSIZE); | ||
| 1204 | return sz; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | |||
| 1208 | /* | ||
| 1209 | ** Initialize Header | ||
| 1210 | */ | ||
| 1211 | static void initheader (lua_State *L, Header *h) { | ||
| 1212 | h->L = L; | ||
| 1213 | h->islittle = nativeendian.little; | ||
| 1214 | h->maxalign = 1; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | |||
| 1218 | /* | ||
| 1219 | ** Read and classify next option. 'size' is filled with option's size. | ||
| 1220 | */ | ||
| 1221 | static KOption getoption (Header *h, const char **fmt, int *size) { | ||
| 1222 | int opt = *((*fmt)++); | ||
| 1223 | *size = 0; /* default */ | ||
| 1224 | switch (opt) { | ||
| 1225 | case 'b': *size = sizeof(char); return Kint; | ||
| 1226 | case 'B': *size = sizeof(char); return Kuint; | ||
| 1227 | case 'h': *size = sizeof(short); return Kint; | ||
| 1228 | case 'H': *size = sizeof(short); return Kuint; | ||
| 1229 | case 'l': *size = sizeof(long); return Kint; | ||
| 1230 | case 'L': *size = sizeof(long); return Kuint; | ||
| 1231 | case 'j': *size = sizeof(lua_Integer); return Kint; | ||
| 1232 | case 'J': *size = sizeof(lua_Integer); return Kuint; | ||
| 1233 | case 'T': *size = sizeof(size_t); return Kuint; | ||
| 1234 | case 'f': *size = sizeof(float); return Kfloat; | ||
| 1235 | case 'd': *size = sizeof(double); return Kfloat; | ||
| 1236 | case 'n': *size = sizeof(lua_Number); return Kfloat; | ||
| 1237 | case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; | ||
| 1238 | case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; | ||
| 1239 | case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; | ||
| 1240 | case 'c': | ||
| 1241 | *size = getnum(fmt, -1); | ||
| 1242 | if (*size == -1) | ||
| 1243 | luaL_error(h->L, "missing size for format option 'c'"); | ||
| 1244 | return Kchar; | ||
| 1245 | case 'z': return Kzstr; | ||
| 1246 | case 'x': *size = 1; return Kpadding; | ||
| 1247 | case 'X': return Kpaddalign; | ||
| 1248 | case ' ': break; | ||
| 1249 | case '<': h->islittle = 1; break; | ||
| 1250 | case '>': h->islittle = 0; break; | ||
| 1251 | case '=': h->islittle = nativeendian.little; break; | ||
| 1252 | case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; | ||
| 1253 | default: luaL_error(h->L, "invalid format option '%c'", opt); | ||
| 1254 | } | ||
| 1255 | return Knop; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | |||
| 1259 | /* | ||
| 1260 | ** Read, classify, and fill other details about the next option. | ||
| 1261 | ** 'psize' is filled with option's size, 'notoalign' with its | ||
| 1262 | ** alignment requirements. | ||
| 1263 | ** Local variable 'size' gets the size to be aligned. (Kpadal option | ||
| 1264 | ** always gets its full alignment, other options are limited by | ||
| 1265 | ** the maximum alignment ('maxalign'). Kchar option needs no alignment | ||
| 1266 | ** despite its size. | ||
| 1267 | */ | ||
| 1268 | static KOption getdetails (Header *h, size_t totalsize, | ||
| 1269 | const char **fmt, int *psize, int *ntoalign) { | ||
| 1270 | KOption opt = getoption(h, fmt, psize); | ||
| 1271 | int align = *psize; /* usually, alignment follows size */ | ||
| 1272 | if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ | ||
| 1273 | if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) | ||
| 1274 | luaL_argerror(h->L, 1, "invalid next option for option 'X'"); | ||
| 1275 | } | ||
| 1276 | if (align <= 1 || opt == Kchar) /* need no alignment? */ | ||
| 1277 | *ntoalign = 0; | ||
| 1278 | else { | ||
| 1279 | if (align > h->maxalign) /* enforce maximum alignment */ | ||
| 1280 | align = h->maxalign; | ||
| 1281 | if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ | ||
| 1282 | luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); | ||
| 1283 | *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); | ||
| 1284 | } | ||
| 1285 | return opt; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | |||
| 1289 | /* | ||
| 1290 | ** Pack integer 'n' with 'size' bytes and 'islittle' endianness. | ||
| 1291 | ** The final 'if' handles the case when 'size' is larger than | ||
| 1292 | ** the size of a Lua integer, correcting the extra sign-extension | ||
| 1293 | ** bytes if necessary (by default they would be zeros). | ||
| 1294 | */ | ||
| 1295 | static void packint (luaL_Buffer *b, lua_Unsigned n, | ||
| 1296 | int islittle, int size, int neg) { | ||
| 1297 | char *buff = luaL_prepbuffsize(b, size); | ||
| 1298 | int i; | ||
| 1299 | buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ | ||
| 1300 | for (i = 1; i < size; i++) { | ||
| 1301 | n >>= NB; | ||
| 1302 | buff[islittle ? i : size - 1 - i] = (char)(n & MC); | ||
| 1303 | } | ||
| 1304 | if (neg && size > SZINT) { /* negative number need sign extension? */ | ||
| 1305 | for (i = SZINT; i < size; i++) /* correct extra bytes */ | ||
| 1306 | buff[islittle ? i : size - 1 - i] = (char)MC; | ||
| 1307 | } | ||
| 1308 | luaL_addsize(b, size); /* add result to buffer */ | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | |||
| 1312 | /* | ||
| 1313 | ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if | ||
| 1314 | ** given 'islittle' is different from native endianness. | ||
| 1315 | */ | ||
| 1316 | static void copywithendian (volatile char *dest, volatile const char *src, | ||
| 1317 | int size, int islittle) { | ||
| 1318 | if (islittle == nativeendian.little) { | ||
| 1319 | while (size-- != 0) | ||
| 1320 | *(dest++) = *(src++); | ||
| 1321 | } | ||
| 1322 | else { | ||
| 1323 | dest += size - 1; | ||
| 1324 | while (size-- != 0) | ||
| 1325 | *(dest--) = *(src++); | ||
| 1326 | } | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | |||
| 1330 | static int str_pack (lua_State *L) { | ||
| 1331 | luaL_Buffer b; | ||
| 1332 | Header h; | ||
| 1333 | const char *fmt = luaL_checkstring(L, 1); /* format string */ | ||
| 1334 | int arg = 1; /* current argument to pack */ | ||
| 1335 | size_t totalsize = 0; /* accumulate total size of result */ | ||
| 1336 | initheader(L, &h); | ||
| 1337 | lua_pushnil(L); /* mark to separate arguments from string buffer */ | ||
| 1338 | luaL_buffinit(L, &b); | ||
| 1339 | while (*fmt != '\0') { | ||
| 1340 | int size, ntoalign; | ||
| 1341 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); | ||
| 1342 | totalsize += ntoalign + size; | ||
| 1343 | while (ntoalign-- > 0) | ||
| 1344 | luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ | ||
| 1345 | arg++; | ||
| 1346 | switch (opt) { | ||
| 1347 | case Kint: { /* signed integers */ | ||
| 1348 | lua_Integer n = luaL_checkinteger(L, arg); | ||
| 1349 | if (size < SZINT) { /* need overflow check? */ | ||
| 1350 | lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); | ||
| 1351 | luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); | ||
| 1352 | } | ||
| 1353 | packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); | ||
| 1354 | break; | ||
| 1355 | } | ||
| 1356 | case Kuint: { /* unsigned integers */ | ||
| 1357 | lua_Integer n = luaL_checkinteger(L, arg); | ||
| 1358 | if (size < SZINT) /* need overflow check? */ | ||
| 1359 | luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), | ||
| 1360 | arg, "unsigned overflow"); | ||
| 1361 | packint(&b, (lua_Unsigned)n, h.islittle, size, 0); | ||
| 1362 | break; | ||
| 1363 | } | ||
| 1364 | case Kfloat: { /* floating-point options */ | ||
| 1365 | volatile Ftypes u; | ||
| 1366 | char *buff = luaL_prepbuffsize(&b, size); | ||
| 1367 | lua_Number n = luaL_checknumber(L, arg); /* get argument */ | ||
| 1368 | if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ | ||
| 1369 | else if (size == sizeof(u.d)) u.d = (double)n; | ||
| 1370 | else u.n = n; | ||
| 1371 | /* move 'u' to final result, correcting endianness if needed */ | ||
| 1372 | copywithendian(buff, u.buff, size, h.islittle); | ||
| 1373 | luaL_addsize(&b, size); | ||
| 1374 | break; | ||
| 1375 | } | ||
| 1376 | case Kchar: { /* fixed-size string */ | ||
| 1377 | size_t len; | ||
| 1378 | const char *s = luaL_checklstring(L, arg, &len); | ||
| 1379 | luaL_argcheck(L, len <= (size_t)size, arg, | ||
| 1380 | "string longer than given size"); | ||
| 1381 | luaL_addlstring(&b, s, len); /* add string */ | ||
| 1382 | while (len++ < (size_t)size) /* pad extra space */ | ||
| 1383 | luaL_addchar(&b, LUAL_PACKPADBYTE); | ||
| 1384 | break; | ||
| 1385 | } | ||
| 1386 | case Kstring: { /* strings with length count */ | ||
| 1387 | size_t len; | ||
| 1388 | const char *s = luaL_checklstring(L, arg, &len); | ||
| 1389 | luaL_argcheck(L, size >= (int)sizeof(size_t) || | ||
| 1390 | len < ((size_t)1 << (size * NB)), | ||
| 1391 | arg, "string length does not fit in given size"); | ||
| 1392 | packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ | ||
| 1393 | luaL_addlstring(&b, s, len); | ||
| 1394 | totalsize += len; | ||
| 1395 | break; | ||
| 1396 | } | ||
| 1397 | case Kzstr: { /* zero-terminated string */ | ||
| 1398 | size_t len; | ||
| 1399 | const char *s = luaL_checklstring(L, arg, &len); | ||
| 1400 | luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); | ||
| 1401 | luaL_addlstring(&b, s, len); | ||
| 1402 | luaL_addchar(&b, '\0'); /* add zero at the end */ | ||
| 1403 | totalsize += len + 1; | ||
| 1404 | break; | ||
| 1405 | } | ||
| 1406 | case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ | ||
| 1407 | case Kpaddalign: case Knop: | ||
| 1408 | arg--; /* undo increment */ | ||
| 1409 | break; | ||
| 1410 | } | ||
| 1411 | } | ||
| 1412 | luaL_pushresult(&b); | ||
| 1413 | return 1; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | |||
| 1417 | static int str_packsize (lua_State *L) { | ||
| 1418 | Header h; | ||
| 1419 | const char *fmt = luaL_checkstring(L, 1); /* format string */ | ||
| 1420 | size_t totalsize = 0; /* accumulate total size of result */ | ||
| 1421 | initheader(L, &h); | ||
| 1422 | while (*fmt != '\0') { | ||
| 1423 | int size, ntoalign; | ||
| 1424 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); | ||
| 1425 | size += ntoalign; /* total space used by option */ | ||
| 1426 | luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, | ||
| 1427 | "format result too large"); | ||
| 1428 | totalsize += size; | ||
| 1429 | switch (opt) { | ||
| 1430 | case Kstring: /* strings with length count */ | ||
| 1431 | case Kzstr: /* zero-terminated string */ | ||
| 1432 | luaL_argerror(L, 1, "variable-length format"); | ||
| 1433 | /* call never return, but to avoid warnings: *//* FALLTHROUGH */ | ||
| 1434 | default: break; | ||
| 1435 | } | ||
| 1436 | } | ||
| 1437 | lua_pushinteger(L, (lua_Integer)totalsize); | ||
| 1438 | return 1; | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | |||
| 1442 | /* | ||
| 1443 | ** Unpack an integer with 'size' bytes and 'islittle' endianness. | ||
| 1444 | ** If size is smaller than the size of a Lua integer and integer | ||
| 1445 | ** is signed, must do sign extension (propagating the sign to the | ||
| 1446 | ** higher bits); if size is larger than the size of a Lua integer, | ||
| 1447 | ** it must check the unread bytes to see whether they do not cause an | ||
| 1448 | ** overflow. | ||
| 1449 | */ | ||
| 1450 | static lua_Integer unpackint (lua_State *L, const char *str, | ||
| 1451 | int islittle, int size, int issigned) { | ||
| 1452 | lua_Unsigned res = 0; | ||
| 1453 | int i; | ||
| 1454 | int limit = (size <= SZINT) ? size : SZINT; | ||
| 1455 | for (i = limit - 1; i >= 0; i--) { | ||
| 1456 | res <<= NB; | ||
| 1457 | res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; | ||
| 1458 | } | ||
| 1459 | if (size < SZINT) { /* real size smaller than lua_Integer? */ | ||
| 1460 | if (issigned) { /* needs sign extension? */ | ||
| 1461 | lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); | ||
| 1462 | res = ((res ^ mask) - mask); /* do sign extension */ | ||
| 1463 | } | ||
| 1464 | } | ||
| 1465 | else if (size > SZINT) { /* must check unread bytes */ | ||
| 1466 | int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; | ||
| 1467 | for (i = limit; i < size; i++) { | ||
| 1468 | if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) | ||
| 1469 | luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); | ||
| 1470 | } | ||
| 1471 | } | ||
| 1472 | return (lua_Integer)res; | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | |||
| 1476 | static int str_unpack (lua_State *L) { | ||
| 1477 | Header h; | ||
| 1478 | const char *fmt = luaL_checkstring(L, 1); | ||
| 1479 | size_t ld; | ||
| 1480 | const char *data = luaL_checklstring(L, 2, &ld); | ||
| 1481 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; | ||
| 1482 | int n = 0; /* number of results */ | ||
| 1483 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); | ||
| 1484 | initheader(L, &h); | ||
| 1485 | while (*fmt != '\0') { | ||
| 1486 | int size, ntoalign; | ||
| 1487 | KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); | ||
| 1488 | if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) | ||
| 1489 | luaL_argerror(L, 2, "data string too short"); | ||
| 1490 | pos += ntoalign; /* skip alignment */ | ||
| 1491 | /* stack space for item + next position */ | ||
| 1492 | luaL_checkstack(L, 2, "too many results"); | ||
| 1493 | n++; | ||
| 1494 | switch (opt) { | ||
| 1495 | case Kint: | ||
| 1496 | case Kuint: { | ||
| 1497 | lua_Integer res = unpackint(L, data + pos, h.islittle, size, | ||
| 1498 | (opt == Kint)); | ||
| 1499 | lua_pushinteger(L, res); | ||
| 1500 | break; | ||
| 1501 | } | ||
| 1502 | case Kfloat: { | ||
| 1503 | volatile Ftypes u; | ||
| 1504 | lua_Number num; | ||
| 1505 | copywithendian(u.buff, data + pos, size, h.islittle); | ||
| 1506 | if (size == sizeof(u.f)) num = (lua_Number)u.f; | ||
| 1507 | else if (size == sizeof(u.d)) num = (lua_Number)u.d; | ||
| 1508 | else num = u.n; | ||
| 1509 | lua_pushnumber(L, num); | ||
| 1510 | break; | ||
| 1511 | } | ||
| 1512 | case Kchar: { | ||
| 1513 | lua_pushlstring(L, data + pos, size); | ||
| 1514 | break; | ||
| 1515 | } | ||
| 1516 | case Kstring: { | ||
| 1517 | size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); | ||
| 1518 | luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); | ||
| 1519 | lua_pushlstring(L, data + pos + size, len); | ||
| 1520 | pos += len; /* skip string */ | ||
| 1521 | break; | ||
| 1522 | } | ||
| 1523 | case Kzstr: { | ||
| 1524 | size_t len = (int)strlen(data + pos); | ||
| 1525 | lua_pushlstring(L, data + pos, len); | ||
| 1526 | pos += len + 1; /* skip string plus final '\0' */ | ||
| 1527 | break; | ||
| 1528 | } | ||
| 1529 | case Kpaddalign: case Kpadding: case Knop: | ||
| 1530 | n--; /* undo increment */ | ||
| 1531 | break; | ||
| 1532 | } | ||
| 1533 | pos += size; | ||
| 1534 | } | ||
| 1535 | lua_pushinteger(L, pos + 1); /* next position */ | ||
| 1536 | return n + 1; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | /* }====================================================== */ | ||
| 1540 | |||
| 1541 | |||
| 1542 | static const luaL_Reg strlib[] = { | ||
| 1543 | {"byte", str_byte}, | ||
| 1544 | {"char", str_char}, | ||
| 1545 | {"dump", str_dump}, | ||
| 1546 | {"find", str_find}, | ||
| 1547 | {"format", str_format}, | ||
| 1548 | {"gmatch", gmatch}, | ||
| 1549 | {"gsub", str_gsub}, | ||
| 1550 | {"len", str_len}, | ||
| 1551 | {"lower", str_lower}, | ||
| 1552 | {"match", str_match}, | ||
| 1553 | {"rep", str_rep}, | ||
| 1554 | {"reverse", str_reverse}, | ||
| 1555 | {"sub", str_sub}, | ||
| 1556 | {"upper", str_upper}, | ||
| 1557 | {"pack", str_pack}, | ||
| 1558 | {"packsize", str_packsize}, | ||
| 1559 | {"unpack", str_unpack}, | ||
| 1560 | {NULL, NULL} | ||
| 1561 | }; | ||
| 1562 | |||
| 1563 | |||
| 1564 | static void createmetatable (lua_State *L) { | ||
| 1565 | lua_createtable(L, 0, 1); /* table to be metatable for strings */ | ||
| 1566 | lua_pushliteral(L, ""); /* dummy string */ | ||
| 1567 | lua_pushvalue(L, -2); /* copy table */ | ||
| 1568 | lua_setmetatable(L, -2); /* set table as metatable for strings */ | ||
| 1569 | lua_pop(L, 1); /* pop dummy string */ | ||
| 1570 | lua_pushvalue(L, -2); /* get string library */ | ||
| 1571 | lua_setfield(L, -2, "__index"); /* metatable.__index = string */ | ||
| 1572 | lua_pop(L, 1); /* pop metatable */ | ||
| 1573 | } | ||
| 1574 | |||
| 1575 | |||
| 1576 | /* | ||
| 1577 | ** Open string library | ||
| 1578 | */ | ||
| 1579 | LUAMOD_API int luaopen_string (lua_State *L) { | ||
| 1580 | luaL_newlib(L, strlib); | ||
| 1581 | createmetatable(L); | ||
| 1582 | return 1; | ||
| 1583 | } | ||
| 1584 | |||
diff --git a/vendor/compat53/ltablib.c b/vendor/compat53/ltablib.c new file mode 100644 index 0000000..98b2f87 --- /dev/null +++ b/vendor/compat53/ltablib.c | |||
| @@ -0,0 +1,450 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ | ||
| 3 | ** Library for Table Manipulation | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | #define ltablib_c | ||
| 8 | #define LUA_LIB | ||
| 9 | |||
| 10 | #include "lprefix.h" | ||
| 11 | |||
| 12 | |||
| 13 | #include <limits.h> | ||
| 14 | #include <stddef.h> | ||
| 15 | #include <string.h> | ||
| 16 | |||
| 17 | #include "lua.h" | ||
| 18 | |||
| 19 | #include "lauxlib.h" | ||
| 20 | #include "lualib.h" | ||
| 21 | |||
| 22 | |||
| 23 | /* | ||
| 24 | ** Operations that an object must define to mimic a table | ||
| 25 | ** (some functions only need some of them) | ||
| 26 | */ | ||
| 27 | #define TAB_R 1 /* read */ | ||
| 28 | #define TAB_W 2 /* write */ | ||
| 29 | #define TAB_L 4 /* length */ | ||
| 30 | #define TAB_RW (TAB_R | TAB_W) /* read/write */ | ||
| 31 | |||
| 32 | |||
| 33 | #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) | ||
| 34 | |||
| 35 | |||
| 36 | static int checkfield (lua_State *L, const char *key, int n) { | ||
| 37 | lua_pushstring(L, key); | ||
| 38 | return (lua_rawget(L, -n) != LUA_TNIL); | ||
| 39 | } | ||
| 40 | |||
| 41 | |||
| 42 | /* | ||
| 43 | ** Check that 'arg' either is a table or can behave like one (that is, | ||
| 44 | ** has a metatable with the required metamethods) | ||
| 45 | */ | ||
| 46 | static void checktab (lua_State *L, int arg, int what) { | ||
| 47 | if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ | ||
| 48 | int n = 1; /* number of elements to pop */ | ||
| 49 | if (lua_getmetatable(L, arg) && /* must have metatable */ | ||
| 50 | (!(what & TAB_R) || checkfield(L, "__index", ++n)) && | ||
| 51 | (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && | ||
| 52 | (!(what & TAB_L) || checkfield(L, "__len", ++n))) { | ||
| 53 | lua_pop(L, n); /* pop metatable and tested metamethods */ | ||
| 54 | } | ||
| 55 | else | ||
| 56 | luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | |||
| 61 | #if defined(LUA_COMPAT_MAXN) | ||
| 62 | static int maxn (lua_State *L) { | ||
| 63 | lua_Number max = 0; | ||
| 64 | luaL_checktype(L, 1, LUA_TTABLE); | ||
| 65 | lua_pushnil(L); /* first key */ | ||
| 66 | while (lua_next(L, 1)) { | ||
| 67 | lua_pop(L, 1); /* remove value */ | ||
| 68 | if (lua_type(L, -1) == LUA_TNUMBER) { | ||
| 69 | lua_Number v = lua_tonumber(L, -1); | ||
| 70 | if (v > max) max = v; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | lua_pushnumber(L, max); | ||
| 74 | return 1; | ||
| 75 | } | ||
| 76 | #endif | ||
| 77 | |||
| 78 | |||
| 79 | static int tinsert (lua_State *L) { | ||
| 80 | lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ | ||
| 81 | lua_Integer pos; /* where to insert new element */ | ||
| 82 | switch (lua_gettop(L)) { | ||
| 83 | case 2: { /* called with only 2 arguments */ | ||
| 84 | pos = e; /* insert new element at the end */ | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | case 3: { | ||
| 88 | lua_Integer i; | ||
| 89 | pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ | ||
| 90 | luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); | ||
| 91 | for (i = e; i > pos; i--) { /* move up elements */ | ||
| 92 | lua_geti(L, 1, i - 1); | ||
| 93 | lua_seti(L, 1, i); /* t[i] = t[i - 1] */ | ||
| 94 | } | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | default: { | ||
| 98 | return luaL_error(L, "wrong number of arguments to 'insert'"); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | lua_seti(L, 1, pos); /* t[pos] = v */ | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | static int tremove (lua_State *L) { | ||
| 107 | lua_Integer size = aux_getn(L, 1, TAB_RW); | ||
| 108 | lua_Integer pos = luaL_optinteger(L, 2, size); | ||
| 109 | if (pos != size) /* validate 'pos' if given */ | ||
| 110 | luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); | ||
| 111 | lua_geti(L, 1, pos); /* result = t[pos] */ | ||
| 112 | for ( ; pos < size; pos++) { | ||
| 113 | lua_geti(L, 1, pos + 1); | ||
| 114 | lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ | ||
| 115 | } | ||
| 116 | lua_pushnil(L); | ||
| 117 | lua_seti(L, 1, pos); /* t[pos] = nil */ | ||
| 118 | return 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | |||
| 122 | /* | ||
| 123 | ** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever | ||
| 124 | ** possible, copy in increasing order, which is better for rehashing. | ||
| 125 | ** "possible" means destination after original range, or smaller | ||
| 126 | ** than origin, or copying to another table. | ||
| 127 | */ | ||
| 128 | static int tmove (lua_State *L) { | ||
| 129 | lua_Integer f = luaL_checkinteger(L, 2); | ||
| 130 | lua_Integer e = luaL_checkinteger(L, 3); | ||
| 131 | lua_Integer t = luaL_checkinteger(L, 4); | ||
| 132 | int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ | ||
| 133 | checktab(L, 1, TAB_R); | ||
| 134 | checktab(L, tt, TAB_W); | ||
| 135 | if (e >= f) { /* otherwise, nothing to move */ | ||
| 136 | lua_Integer n, i; | ||
| 137 | luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, | ||
| 138 | "too many elements to move"); | ||
| 139 | n = e - f + 1; /* number of elements to move */ | ||
| 140 | luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, | ||
| 141 | "destination wrap around"); | ||
| 142 | if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { | ||
| 143 | for (i = 0; i < n; i++) { | ||
| 144 | lua_geti(L, 1, f + i); | ||
| 145 | lua_seti(L, tt, t + i); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | else { | ||
| 149 | for (i = n - 1; i >= 0; i--) { | ||
| 150 | lua_geti(L, 1, f + i); | ||
| 151 | lua_seti(L, tt, t + i); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | } | ||
| 155 | lua_pushvalue(L, tt); /* return destination table */ | ||
| 156 | return 1; | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { | ||
| 161 | lua_geti(L, 1, i); | ||
| 162 | if (!lua_isstring(L, -1)) | ||
| 163 | luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", | ||
| 164 | luaL_typename(L, -1), i); | ||
| 165 | luaL_addvalue(b); | ||
| 166 | } | ||
| 167 | |||
| 168 | |||
| 169 | static int tconcat (lua_State *L) { | ||
| 170 | luaL_Buffer b; | ||
| 171 | lua_Integer last = aux_getn(L, 1, TAB_R); | ||
| 172 | size_t lsep; | ||
| 173 | const char *sep = luaL_optlstring(L, 2, "", &lsep); | ||
| 174 | lua_Integer i = luaL_optinteger(L, 3, 1); | ||
| 175 | last = luaL_optinteger(L, 4, last); | ||
| 176 | luaL_buffinit(L, &b); | ||
| 177 | for (; i < last; i++) { | ||
| 178 | addfield(L, &b, i); | ||
| 179 | luaL_addlstring(&b, sep, lsep); | ||
| 180 | } | ||
| 181 | if (i == last) /* add last value (if interval was not empty) */ | ||
| 182 | addfield(L, &b, i); | ||
| 183 | luaL_pushresult(&b); | ||
| 184 | return 1; | ||
| 185 | } | ||
| 186 | |||
| 187 | |||
| 188 | /* | ||
| 189 | ** {====================================================== | ||
| 190 | ** Pack/unpack | ||
| 191 | ** ======================================================= | ||
| 192 | */ | ||
| 193 | |||
| 194 | static int pack (lua_State *L) { | ||
| 195 | int i; | ||
| 196 | int n = lua_gettop(L); /* number of elements to pack */ | ||
| 197 | lua_createtable(L, n, 1); /* create result table */ | ||
| 198 | lua_insert(L, 1); /* put it at index 1 */ | ||
| 199 | for (i = n; i >= 1; i--) /* assign elements */ | ||
| 200 | lua_seti(L, 1, i); | ||
| 201 | lua_pushinteger(L, n); | ||
| 202 | lua_setfield(L, 1, "n"); /* t.n = number of elements */ | ||
| 203 | return 1; /* return table */ | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | static int unpack (lua_State *L) { | ||
| 208 | lua_Unsigned n; | ||
| 209 | lua_Integer i = luaL_optinteger(L, 2, 1); | ||
| 210 | lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); | ||
| 211 | if (i > e) return 0; /* empty range */ | ||
| 212 | n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ | ||
| 213 | if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) | ||
| 214 | return luaL_error(L, "too many results to unpack"); | ||
| 215 | for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ | ||
| 216 | lua_geti(L, 1, i); | ||
| 217 | } | ||
| 218 | lua_geti(L, 1, e); /* push last element */ | ||
| 219 | return (int)n; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* }====================================================== */ | ||
| 223 | |||
| 224 | |||
| 225 | |||
| 226 | /* | ||
| 227 | ** {====================================================== | ||
| 228 | ** Quicksort | ||
| 229 | ** (based on 'Algorithms in MODULA-3', Robert Sedgewick; | ||
| 230 | ** Addison-Wesley, 1993.) | ||
| 231 | ** ======================================================= | ||
| 232 | */ | ||
| 233 | |||
| 234 | |||
| 235 | /* type for array indices */ | ||
| 236 | typedef unsigned int IdxT; | ||
| 237 | |||
| 238 | |||
| 239 | /* | ||
| 240 | ** Produce a "random" 'unsigned int' to randomize pivot choice. This | ||
| 241 | ** macro is used only when 'sort' detects a big imbalance in the result | ||
| 242 | ** of a partition. (If you don't want/need this "randomness", ~0 is a | ||
| 243 | ** good choice.) | ||
| 244 | */ | ||
| 245 | #if !defined(l_randomizePivot) /* { */ | ||
| 246 | |||
| 247 | #include <time.h> | ||
| 248 | |||
| 249 | /* size of 'e' measured in number of 'unsigned int's */ | ||
| 250 | #define sof(e) (sizeof(e) / sizeof(unsigned int)) | ||
| 251 | |||
| 252 | /* | ||
| 253 | ** Use 'time' and 'clock' as sources of "randomness". Because we don't | ||
| 254 | ** know the types 'clock_t' and 'time_t', we cannot cast them to | ||
| 255 | ** anything without risking overflows. A safe way to use their values | ||
| 256 | ** is to copy them to an array of a known type and use the array values. | ||
| 257 | */ | ||
| 258 | static unsigned int l_randomizePivot (void) { | ||
| 259 | clock_t c = clock(); | ||
| 260 | time_t t = time(NULL); | ||
| 261 | unsigned int buff[sof(c) + sof(t)]; | ||
| 262 | unsigned int i, rnd = 0; | ||
| 263 | memcpy(buff, &c, sof(c) * sizeof(unsigned int)); | ||
| 264 | memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); | ||
| 265 | for (i = 0; i < sof(buff); i++) | ||
| 266 | rnd += buff[i]; | ||
| 267 | return rnd; | ||
| 268 | } | ||
| 269 | |||
| 270 | #endif /* } */ | ||
| 271 | |||
| 272 | |||
| 273 | /* arrays larger than 'RANLIMIT' may use randomized pivots */ | ||
| 274 | #define RANLIMIT 100u | ||
| 275 | |||
| 276 | |||
| 277 | static void set2 (lua_State *L, IdxT i, IdxT j) { | ||
| 278 | lua_seti(L, 1, i); | ||
| 279 | lua_seti(L, 1, j); | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | /* | ||
| 284 | ** Return true iff value at stack index 'a' is less than the value at | ||
| 285 | ** index 'b' (according to the order of the sort). | ||
| 286 | */ | ||
| 287 | static int sort_comp (lua_State *L, int a, int b) { | ||
| 288 | if (lua_isnil(L, 2)) /* no function? */ | ||
| 289 | return lua_compare(L, a, b, LUA_OPLT); /* a < b */ | ||
| 290 | else { /* function */ | ||
| 291 | int res; | ||
| 292 | lua_pushvalue(L, 2); /* push function */ | ||
| 293 | lua_pushvalue(L, a-1); /* -1 to compensate function */ | ||
| 294 | lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ | ||
| 295 | lua_call(L, 2, 1); /* call function */ | ||
| 296 | res = lua_toboolean(L, -1); /* get result */ | ||
| 297 | lua_pop(L, 1); /* pop result */ | ||
| 298 | return res; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | |||
| 303 | /* | ||
| 304 | ** Does the partition: Pivot P is at the top of the stack. | ||
| 305 | ** precondition: a[lo] <= P == a[up-1] <= a[up], | ||
| 306 | ** so it only needs to do the partition from lo + 1 to up - 2. | ||
| 307 | ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] | ||
| 308 | ** returns 'i'. | ||
| 309 | */ | ||
| 310 | static IdxT partition (lua_State *L, IdxT lo, IdxT up) { | ||
| 311 | IdxT i = lo; /* will be incremented before first use */ | ||
| 312 | IdxT j = up - 1; /* will be decremented before first use */ | ||
| 313 | /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ | ||
| 314 | for (;;) { | ||
| 315 | /* next loop: repeat ++i while a[i] < P */ | ||
| 316 | while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { | ||
| 317 | if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ | ||
| 318 | luaL_error(L, "invalid order function for sorting"); | ||
| 319 | lua_pop(L, 1); /* remove a[i] */ | ||
| 320 | } | ||
| 321 | /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ | ||
| 322 | /* next loop: repeat --j while P < a[j] */ | ||
| 323 | while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { | ||
| 324 | if (j < i) /* j < i but a[j] > P ?? */ | ||
| 325 | luaL_error(L, "invalid order function for sorting"); | ||
| 326 | lua_pop(L, 1); /* remove a[j] */ | ||
| 327 | } | ||
| 328 | /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ | ||
| 329 | if (j < i) { /* no elements out of place? */ | ||
| 330 | /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ | ||
| 331 | lua_pop(L, 1); /* pop a[j] */ | ||
| 332 | /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ | ||
| 333 | set2(L, up - 1, i); | ||
| 334 | return i; | ||
| 335 | } | ||
| 336 | /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ | ||
| 337 | set2(L, i, j); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | |||
| 342 | /* | ||
| 343 | ** Choose an element in the middle (2nd-3th quarters) of [lo,up] | ||
| 344 | ** "randomized" by 'rnd' | ||
| 345 | */ | ||
| 346 | static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { | ||
| 347 | IdxT r4 = (up - lo) / 4; /* range/4 */ | ||
| 348 | IdxT p = rnd % (r4 * 2) + (lo + r4); | ||
| 349 | lua_assert(lo + r4 <= p && p <= up - r4); | ||
| 350 | return p; | ||
| 351 | } | ||
| 352 | |||
| 353 | |||
| 354 | /* | ||
| 355 | ** QuickSort algorithm (recursive function) | ||
| 356 | */ | ||
| 357 | static void auxsort (lua_State *L, IdxT lo, IdxT up, | ||
| 358 | unsigned int rnd) { | ||
| 359 | while (lo < up) { /* loop for tail recursion */ | ||
| 360 | IdxT p; /* Pivot index */ | ||
| 361 | IdxT n; /* to be used later */ | ||
| 362 | /* sort elements 'lo', 'p', and 'up' */ | ||
| 363 | lua_geti(L, 1, lo); | ||
| 364 | lua_geti(L, 1, up); | ||
| 365 | if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ | ||
| 366 | set2(L, lo, up); /* swap a[lo] - a[up] */ | ||
| 367 | else | ||
| 368 | lua_pop(L, 2); /* remove both values */ | ||
| 369 | if (up - lo == 1) /* only 2 elements? */ | ||
| 370 | return; /* already sorted */ | ||
| 371 | if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ | ||
| 372 | p = (lo + up)/2; /* middle element is a good pivot */ | ||
| 373 | else /* for larger intervals, it is worth a random pivot */ | ||
| 374 | p = choosePivot(lo, up, rnd); | ||
| 375 | lua_geti(L, 1, p); | ||
| 376 | lua_geti(L, 1, lo); | ||
| 377 | if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ | ||
| 378 | set2(L, p, lo); /* swap a[p] - a[lo] */ | ||
| 379 | else { | ||
| 380 | lua_pop(L, 1); /* remove a[lo] */ | ||
| 381 | lua_geti(L, 1, up); | ||
| 382 | if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ | ||
| 383 | set2(L, p, up); /* swap a[up] - a[p] */ | ||
| 384 | else | ||
| 385 | lua_pop(L, 2); | ||
| 386 | } | ||
| 387 | if (up - lo == 2) /* only 3 elements? */ | ||
| 388 | return; /* already sorted */ | ||
| 389 | lua_geti(L, 1, p); /* get middle element (Pivot) */ | ||
| 390 | lua_pushvalue(L, -1); /* push Pivot */ | ||
| 391 | lua_geti(L, 1, up - 1); /* push a[up - 1] */ | ||
| 392 | set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ | ||
| 393 | p = partition(L, lo, up); | ||
| 394 | /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ | ||
| 395 | if (p - lo < up - p) { /* lower interval is smaller? */ | ||
| 396 | auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ | ||
| 397 | n = p - lo; /* size of smaller interval */ | ||
| 398 | lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ | ||
| 399 | } | ||
| 400 | else { | ||
| 401 | auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ | ||
| 402 | n = up - p; /* size of smaller interval */ | ||
| 403 | up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ | ||
| 404 | } | ||
| 405 | if ((up - lo) / 128 > n) /* partition too imbalanced? */ | ||
| 406 | rnd = l_randomizePivot(); /* try a new randomization */ | ||
| 407 | } /* tail call auxsort(L, lo, up, rnd) */ | ||
| 408 | } | ||
| 409 | |||
| 410 | |||
| 411 | static int sort (lua_State *L) { | ||
| 412 | lua_Integer n = aux_getn(L, 1, TAB_RW); | ||
| 413 | if (n > 1) { /* non-trivial interval? */ | ||
| 414 | luaL_argcheck(L, n < INT_MAX, 1, "array too big"); | ||
| 415 | if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ | ||
| 416 | luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ | ||
| 417 | lua_settop(L, 2); /* make sure there are two arguments */ | ||
| 418 | auxsort(L, 1, (IdxT)n, 0); | ||
| 419 | } | ||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | /* }====================================================== */ | ||
| 424 | |||
| 425 | |||
| 426 | static const luaL_Reg tab_funcs[] = { | ||
| 427 | {"concat", tconcat}, | ||
| 428 | #if defined(LUA_COMPAT_MAXN) | ||
| 429 | {"maxn", maxn}, | ||
| 430 | #endif | ||
| 431 | {"insert", tinsert}, | ||
| 432 | {"pack", pack}, | ||
| 433 | {"unpack", unpack}, | ||
| 434 | {"remove", tremove}, | ||
| 435 | {"move", tmove}, | ||
| 436 | {"sort", sort}, | ||
| 437 | {NULL, NULL} | ||
| 438 | }; | ||
| 439 | |||
| 440 | |||
| 441 | LUAMOD_API int luaopen_table (lua_State *L) { | ||
| 442 | luaL_newlib(L, tab_funcs); | ||
| 443 | #if defined(LUA_COMPAT_UNPACK) | ||
| 444 | /* _G.unpack = table.unpack */ | ||
| 445 | lua_getfield(L, -1, "unpack"); | ||
| 446 | lua_setglobal(L, "unpack"); | ||
| 447 | #endif | ||
| 448 | return 1; | ||
| 449 | } | ||
| 450 | |||
diff --git a/vendor/compat53/lutf8lib.c b/vendor/compat53/lutf8lib.c new file mode 100644 index 0000000..de9e3dc --- /dev/null +++ b/vendor/compat53/lutf8lib.c | |||
| @@ -0,0 +1,256 @@ | |||
| 1 | /* | ||
| 2 | ** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $ | ||
| 3 | ** Standard library for UTF-8 manipulation | ||
| 4 | ** See Copyright Notice in lua.h | ||
| 5 | */ | ||
| 6 | |||
| 7 | #define lutf8lib_c | ||
| 8 | #define LUA_LIB | ||
| 9 | |||
| 10 | #include "lprefix.h" | ||
| 11 | |||
| 12 | |||
| 13 | #include <assert.h> | ||
| 14 | #include <limits.h> | ||
| 15 | #include <stdlib.h> | ||
| 16 | #include <string.h> | ||
| 17 | |||
| 18 | #include "lua.h" | ||
| 19 | |||
| 20 | #include "lauxlib.h" | ||
| 21 | #include "lualib.h" | ||
| 22 | |||
| 23 | #define MAXUNICODE 0x10FFFF | ||
| 24 | |||
| 25 | #define iscont(p) ((*(p) & 0xC0) == 0x80) | ||
| 26 | |||
| 27 | |||
| 28 | /* from strlib */ | ||
| 29 | /* translate a relative string position: negative means back from end */ | ||
| 30 | static lua_Integer u_posrelat (lua_Integer pos, size_t len) { | ||
| 31 | if (pos >= 0) return pos; | ||
| 32 | else if (0u - (size_t)pos > len) return 0; | ||
| 33 | else return (lua_Integer)len + pos + 1; | ||
| 34 | } | ||
| 35 | |||
| 36 | |||
| 37 | /* | ||
| 38 | ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. | ||
| 39 | */ | ||
| 40 | static const char *utf8_decode (const char *o, int *val) { | ||
| 41 | static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; | ||
| 42 | const unsigned char *s = (const unsigned char *)o; | ||
| 43 | unsigned int c = s[0]; | ||
| 44 | unsigned int res = 0; /* final result */ | ||
| 45 | if (c < 0x80) /* ascii? */ | ||
| 46 | res = c; | ||
| 47 | else { | ||
| 48 | int count = 0; /* to count number of continuation bytes */ | ||
| 49 | while (c & 0x40) { /* still have continuation bytes? */ | ||
| 50 | int cc = s[++count]; /* read next byte */ | ||
| 51 | if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ | ||
| 52 | return NULL; /* invalid byte sequence */ | ||
| 53 | res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ | ||
| 54 | c <<= 1; /* to test next bit */ | ||
| 55 | } | ||
| 56 | res |= ((c & 0x7F) << (count * 5)); /* add first byte */ | ||
| 57 | if (count > 3 || res > MAXUNICODE || res <= limits[count]) | ||
| 58 | return NULL; /* invalid byte sequence */ | ||
| 59 | s += count; /* skip continuation bytes read */ | ||
| 60 | } | ||
| 61 | if (val) *val = res; | ||
| 62 | return (const char *)s + 1; /* +1 to include first byte */ | ||
| 63 | } | ||
| 64 | |||
| 65 | |||
| 66 | /* | ||
| 67 | ** utf8len(s [, i [, j]]) --> number of characters that start in the | ||
| 68 | ** range [i,j], or nil + current position if 's' is not well formed in | ||
| 69 | ** that interval | ||
| 70 | */ | ||
| 71 | static int utflen (lua_State *L) { | ||
| 72 | int n = 0; | ||
| 73 | size_t len; | ||
| 74 | const char *s = luaL_checklstring(L, 1, &len); | ||
| 75 | lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); | ||
| 76 | lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); | ||
| 77 | luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, | ||
| 78 | "initial position out of string"); | ||
| 79 | luaL_argcheck(L, --posj < (lua_Integer)len, 3, | ||
| 80 | "final position out of string"); | ||
| 81 | while (posi <= posj) { | ||
| 82 | const char *s1 = utf8_decode(s + posi, NULL); | ||
| 83 | if (s1 == NULL) { /* conversion error? */ | ||
| 84 | lua_pushnil(L); /* return nil ... */ | ||
| 85 | lua_pushinteger(L, posi + 1); /* ... and current position */ | ||
| 86 | return 2; | ||
| 87 | } | ||
| 88 | posi = s1 - s; | ||
| 89 | n++; | ||
| 90 | } | ||
| 91 | lua_pushinteger(L, n); | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | /* | ||
| 97 | ** codepoint(s, [i, [j]]) -> returns codepoints for all characters | ||
| 98 | ** that start in the range [i,j] | ||
| 99 | */ | ||
| 100 | static int codepoint (lua_State *L) { | ||
| 101 | size_t len; | ||
| 102 | const char *s = luaL_checklstring(L, 1, &len); | ||
| 103 | lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); | ||
| 104 | lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); | ||
| 105 | int n; | ||
| 106 | const char *se; | ||
| 107 | luaL_argcheck(L, posi >= 1, 2, "out of range"); | ||
| 108 | luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); | ||
| 109 | if (posi > pose) return 0; /* empty interval; return no values */ | ||
| 110 | if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ | ||
| 111 | return luaL_error(L, "string slice too long"); | ||
| 112 | n = (int)(pose - posi) + 1; | ||
| 113 | luaL_checkstack(L, n, "string slice too long"); | ||
| 114 | n = 0; | ||
| 115 | se = s + pose; | ||
| 116 | for (s += posi - 1; s < se;) { | ||
| 117 | int code; | ||
| 118 | s = utf8_decode(s, &code); | ||
| 119 | if (s == NULL) | ||
| 120 | return luaL_error(L, "invalid UTF-8 code"); | ||
| 121 | lua_pushinteger(L, code); | ||
| 122 | n++; | ||
| 123 | } | ||
| 124 | return n; | ||
| 125 | } | ||
| 126 | |||
| 127 | |||
| 128 | static void pushutfchar (lua_State *L, int arg) { | ||
| 129 | lua_Integer code = luaL_checkinteger(L, arg); | ||
| 130 | luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); | ||
| 131 | lua_pushfstring(L, "%U", (long)code); | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | /* | ||
| 136 | ** utfchar(n1, n2, ...) -> char(n1)..char(n2)... | ||
| 137 | */ | ||
| 138 | static int utfchar (lua_State *L) { | ||
| 139 | int n = lua_gettop(L); /* number of arguments */ | ||
| 140 | if (n == 1) /* optimize common case of single char */ | ||
| 141 | pushutfchar(L, 1); | ||
| 142 | else { | ||
| 143 | int i; | ||
| 144 | luaL_Buffer b; | ||
| 145 | luaL_buffinit(L, &b); | ||
| 146 | for (i = 1; i <= n; i++) { | ||
| 147 | pushutfchar(L, i); | ||
| 148 | luaL_addvalue(&b); | ||
| 149 | } | ||
| 150 | luaL_pushresult(&b); | ||
| 151 | } | ||
| 152 | return 1; | ||
| 153 | } | ||
| 154 | |||
| 155 | |||
| 156 | /* | ||
| 157 | ** offset(s, n, [i]) -> index where n-th character counting from | ||
| 158 | ** position 'i' starts; 0 means character at 'i'. | ||
| 159 | */ | ||
| 160 | static int byteoffset (lua_State *L) { | ||
| 161 | size_t len; | ||
| 162 | const char *s = luaL_checklstring(L, 1, &len); | ||
| 163 | lua_Integer n = luaL_checkinteger(L, 2); | ||
| 164 | lua_Integer posi = (n >= 0) ? 1 : len + 1; | ||
| 165 | posi = u_posrelat(luaL_optinteger(L, 3, posi), len); | ||
| 166 | luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, | ||
| 167 | "position out of range"); | ||
| 168 | if (n == 0) { | ||
| 169 | /* find beginning of current byte sequence */ | ||
| 170 | while (posi > 0 && iscont(s + posi)) posi--; | ||
| 171 | } | ||
| 172 | else { | ||
| 173 | if (iscont(s + posi)) | ||
| 174 | luaL_error(L, "initial position is a continuation byte"); | ||
| 175 | if (n < 0) { | ||
| 176 | while (n < 0 && posi > 0) { /* move back */ | ||
| 177 | do { /* find beginning of previous character */ | ||
| 178 | posi--; | ||
| 179 | } while (posi > 0 && iscont(s + posi)); | ||
| 180 | n++; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | else { | ||
| 184 | n--; /* do not move for 1st character */ | ||
| 185 | while (n > 0 && posi < (lua_Integer)len) { | ||
| 186 | do { /* find beginning of next character */ | ||
| 187 | posi++; | ||
| 188 | } while (iscont(s + posi)); /* (cannot pass final '\0') */ | ||
| 189 | n--; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | if (n == 0) /* did it find given character? */ | ||
| 194 | lua_pushinteger(L, posi + 1); | ||
| 195 | else /* no such character */ | ||
| 196 | lua_pushnil(L); | ||
| 197 | return 1; | ||
| 198 | } | ||
| 199 | |||
| 200 | |||
| 201 | static int iter_aux (lua_State *L) { | ||
| 202 | size_t len; | ||
| 203 | const char *s = luaL_checklstring(L, 1, &len); | ||
| 204 | lua_Integer n = lua_tointeger(L, 2) - 1; | ||
| 205 | if (n < 0) /* first iteration? */ | ||
| 206 | n = 0; /* start from here */ | ||
| 207 | else if (n < (lua_Integer)len) { | ||
| 208 | n++; /* skip current byte */ | ||
| 209 | while (iscont(s + n)) n++; /* and its continuations */ | ||
| 210 | } | ||
| 211 | if (n >= (lua_Integer)len) | ||
| 212 | return 0; /* no more codepoints */ | ||
| 213 | else { | ||
| 214 | int code; | ||
| 215 | const char *next = utf8_decode(s + n, &code); | ||
| 216 | if (next == NULL || iscont(next)) | ||
| 217 | return luaL_error(L, "invalid UTF-8 code"); | ||
| 218 | lua_pushinteger(L, n + 1); | ||
| 219 | lua_pushinteger(L, code); | ||
| 220 | return 2; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | |||
| 225 | static int iter_codes (lua_State *L) { | ||
| 226 | luaL_checkstring(L, 1); | ||
| 227 | lua_pushcfunction(L, iter_aux); | ||
| 228 | lua_pushvalue(L, 1); | ||
| 229 | lua_pushinteger(L, 0); | ||
| 230 | return 3; | ||
| 231 | } | ||
| 232 | |||
| 233 | |||
| 234 | /* pattern to match a single UTF-8 character */ | ||
| 235 | #define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" | ||
| 236 | |||
| 237 | |||
| 238 | static const luaL_Reg funcs[] = { | ||
| 239 | {"offset", byteoffset}, | ||
| 240 | {"codepoint", codepoint}, | ||
| 241 | {"char", utfchar}, | ||
| 242 | {"len", utflen}, | ||
| 243 | {"codes", iter_codes}, | ||
| 244 | /* placeholders */ | ||
| 245 | {"charpattern", NULL}, | ||
| 246 | {NULL, NULL} | ||
| 247 | }; | ||
| 248 | |||
| 249 | |||
| 250 | LUAMOD_API int luaopen_utf8 (lua_State *L) { | ||
| 251 | luaL_newlib(L, funcs); | ||
| 252 | lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); | ||
| 253 | lua_setfield(L, -2, "charpattern"); | ||
| 254 | return 1; | ||
| 255 | } | ||
| 256 | |||
diff --git a/vendor/compat53/rockspecs/compat53-0.1-1.rockspec b/vendor/compat53/rockspecs/compat53-0.1-1.rockspec new file mode 100644 index 0000000..0ff56b0 --- /dev/null +++ b/vendor/compat53/rockspecs/compat53-0.1-1.rockspec | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | package = "compat53" | ||
| 2 | version = "0.1-1" | ||
| 3 | source = { | ||
| 4 | url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.1.zip", | ||
| 5 | dir = "lua-compat-5.3-0.1", | ||
| 6 | } | ||
| 7 | description = { | ||
| 8 | summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", | ||
| 9 | detailed = [[ | ||
| 10 | This is a small module that aims to make it easier to write Lua | ||
| 11 | code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. | ||
| 12 | It does *not* make Lua 5.2 (or even 5.1) entirely compatible | ||
| 13 | with Lua 5.3, but it brings the API closer to that of Lua 5.3. | ||
| 14 | ]], | ||
| 15 | homepage = "https://github.com/keplerproject/lua-compat-5.3", | ||
| 16 | license = "MIT" | ||
| 17 | } | ||
| 18 | dependencies = { | ||
| 19 | "lua >= 5.1, < 5.4", | ||
| 20 | --"struct" -- make Roberto's struct module optional | ||
| 21 | } | ||
| 22 | build = { | ||
| 23 | type = "builtin", | ||
| 24 | modules = { | ||
| 25 | ["compat53"] = "compat53.lua", | ||
| 26 | ["compat53.utf8"] = "lutf8lib.c", | ||
| 27 | ["compat53.table"] = "ltablib.c", | ||
| 28 | ["compat53.string"] = "lstrlib.c", | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
diff --git a/vendor/compat53/rockspecs/compat53-0.2-1.rockspec b/vendor/compat53/rockspecs/compat53-0.2-1.rockspec new file mode 100644 index 0000000..1b3c80e --- /dev/null +++ b/vendor/compat53/rockspecs/compat53-0.2-1.rockspec | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | package = "compat53" | ||
| 2 | version = "0.2-1" | ||
| 3 | source = { | ||
| 4 | url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.2.zip", | ||
| 5 | dir = "lua-compat-5.3-0.2", | ||
| 6 | } | ||
| 7 | description = { | ||
| 8 | summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", | ||
| 9 | detailed = [[ | ||
| 10 | This is a small module that aims to make it easier to write Lua | ||
| 11 | code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. | ||
| 12 | It does *not* make Lua 5.2 (or even 5.1) entirely compatible | ||
| 13 | with Lua 5.3, but it brings the API closer to that of Lua 5.3. | ||
| 14 | ]], | ||
| 15 | homepage = "https://github.com/keplerproject/lua-compat-5.3", | ||
| 16 | license = "MIT" | ||
| 17 | } | ||
| 18 | dependencies = { | ||
| 19 | "lua >= 5.1, < 5.4", | ||
| 20 | --"struct" -- make Roberto's struct module optional | ||
| 21 | } | ||
| 22 | build = { | ||
| 23 | type = "builtin", | ||
| 24 | modules = { | ||
| 25 | ["compat53.init"] = "compat53/init.lua", | ||
| 26 | ["compat53.module"] = "compat53/module.lua", | ||
| 27 | ["compat53.utf8"] = "lutf8lib.c", | ||
| 28 | ["compat53.table"] = "ltablib.c", | ||
| 29 | ["compat53.string"] = "lstrlib.c", | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
diff --git a/vendor/compat53/rockspecs/compat53-0.3-1.rockspec b/vendor/compat53/rockspecs/compat53-0.3-1.rockspec new file mode 100644 index 0000000..43f53d2 --- /dev/null +++ b/vendor/compat53/rockspecs/compat53-0.3-1.rockspec | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | package = "compat53" | ||
| 2 | version = "0.3-1" | ||
| 3 | source = { | ||
| 4 | url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.3.zip", | ||
| 5 | dir = "lua-compat-5.3-0.3", | ||
| 6 | } | ||
| 7 | description = { | ||
| 8 | summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", | ||
| 9 | detailed = [[ | ||
| 10 | This is a small module that aims to make it easier to write Lua | ||
| 11 | code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. | ||
| 12 | It does *not* make Lua 5.2 (or even 5.1) entirely compatible | ||
| 13 | with Lua 5.3, but it brings the API closer to that of Lua 5.3. | ||
| 14 | ]], | ||
| 15 | homepage = "https://github.com/keplerproject/lua-compat-5.3", | ||
| 16 | license = "MIT" | ||
| 17 | } | ||
| 18 | dependencies = { | ||
| 19 | "lua >= 5.1, < 5.4", | ||
| 20 | --"struct" -- make Roberto's struct module optional | ||
| 21 | } | ||
| 22 | build = { | ||
| 23 | type = "builtin", | ||
| 24 | modules = { | ||
| 25 | ["compat53.init"] = "compat53/init.lua", | ||
| 26 | ["compat53.module"] = "compat53/module.lua", | ||
| 27 | ["compat53.utf8"] = "lutf8lib.c", | ||
| 28 | ["compat53.table"] = "ltablib.c", | ||
| 29 | ["compat53.string"] = "lstrlib.c", | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
diff --git a/vendor/compat53/rockspecs/compat53-0.4-1.rockspec b/vendor/compat53/rockspecs/compat53-0.4-1.rockspec new file mode 100644 index 0000000..9331e19 --- /dev/null +++ b/vendor/compat53/rockspecs/compat53-0.4-1.rockspec | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | package = "compat53" | ||
| 2 | version = "0.4-1" | ||
| 3 | source = { | ||
| 4 | url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.4.zip", | ||
| 5 | dir = "lua-compat-5.3-0.4", | ||
| 6 | } | ||
| 7 | description = { | ||
| 8 | summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", | ||
| 9 | detailed = [[ | ||
| 10 | This is a small module that aims to make it easier to write Lua | ||
| 11 | code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. | ||
| 12 | It does *not* make Lua 5.2 (or even 5.1) entirely compatible | ||
| 13 | with Lua 5.3, but it brings the API closer to that of Lua 5.3. | ||
| 14 | ]], | ||
| 15 | homepage = "https://github.com/keplerproject/lua-compat-5.3", | ||
| 16 | license = "MIT" | ||
| 17 | } | ||
| 18 | dependencies = { | ||
| 19 | "lua >= 5.1, < 5.4", | ||
| 20 | --"struct" -- make Roberto's struct module optional | ||
| 21 | } | ||
| 22 | build = { | ||
| 23 | type = "builtin", | ||
| 24 | modules = { | ||
| 25 | ["compat53.init"] = "compat53/init.lua", | ||
| 26 | ["compat53.module"] = "compat53/module.lua", | ||
| 27 | ["compat53.utf8"] = "lutf8lib.c", | ||
| 28 | ["compat53.table"] = "ltablib.c", | ||
| 29 | ["compat53.string"] = "lstrlib.c", | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
diff --git a/vendor/compat53/rockspecs/compat53-0.5-1.rockspec b/vendor/compat53/rockspecs/compat53-0.5-1.rockspec new file mode 100644 index 0000000..3cceccd --- /dev/null +++ b/vendor/compat53/rockspecs/compat53-0.5-1.rockspec | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | package = "compat53" | ||
| 2 | version = "0.5-1" | ||
| 3 | source = { | ||
| 4 | url = "https://github.com/keplerproject/lua-compat-5.3/archive/v0.5.zip", | ||
| 5 | dir = "lua-compat-5.3-0.5", | ||
| 6 | } | ||
| 7 | description = { | ||
| 8 | summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", | ||
| 9 | detailed = [[ | ||
| 10 | This is a small module that aims to make it easier to write Lua | ||
| 11 | code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. | ||
| 12 | It does *not* make Lua 5.2 (or even 5.1) entirely compatible | ||
| 13 | with Lua 5.3, but it brings the API closer to that of Lua 5.3. | ||
| 14 | ]], | ||
| 15 | homepage = "https://github.com/keplerproject/lua-compat-5.3", | ||
| 16 | license = "MIT" | ||
| 17 | } | ||
| 18 | dependencies = { | ||
| 19 | "lua >= 5.1, < 5.4", | ||
| 20 | --"struct" -- make Roberto's struct module optional | ||
| 21 | } | ||
| 22 | build = { | ||
| 23 | type = "builtin", | ||
| 24 | modules = { | ||
| 25 | ["compat53.init"] = "compat53/init.lua", | ||
| 26 | ["compat53.module"] = "compat53/module.lua", | ||
| 27 | ["compat53.utf8"] = "lutf8lib.c", | ||
| 28 | ["compat53.table"] = "ltablib.c", | ||
| 29 | ["compat53.string"] = "lstrlib.c", | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
diff --git a/vendor/compat53/rockspecs/compat53-scm-0.rockspec b/vendor/compat53/rockspecs/compat53-scm-0.rockspec new file mode 100644 index 0000000..317e18c --- /dev/null +++ b/vendor/compat53/rockspecs/compat53-scm-0.rockspec | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | package = "compat53" | ||
| 2 | version = "scm-0" | ||
| 3 | source = { | ||
| 4 | url = "https://github.com/keplerproject/lua-compat-5.3/archive/master.zip", | ||
| 5 | dir = "lua-compat-5.3-master", | ||
| 6 | } | ||
| 7 | description = { | ||
| 8 | summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", | ||
| 9 | detailed = [[ | ||
| 10 | This is a small module that aims to make it easier to write Lua | ||
| 11 | code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. | ||
| 12 | It does *not* make Lua 5.2 (or even 5.1) entirely compatible | ||
| 13 | with Lua 5.3, but it brings the API closer to that of Lua 5.3. | ||
| 14 | ]], | ||
| 15 | homepage = "https://github.com/keplerproject/lua-compat-5.3", | ||
| 16 | license = "MIT" | ||
| 17 | } | ||
| 18 | dependencies = { | ||
| 19 | "lua >= 5.1, < 5.4", | ||
| 20 | --"struct" -- make Roberto's struct module optional | ||
| 21 | } | ||
| 22 | build = { | ||
| 23 | type = "builtin", | ||
| 24 | modules = { | ||
| 25 | ["compat53.init"] = "compat53/init.lua", | ||
| 26 | ["compat53.module"] = "compat53/module.lua", | ||
| 27 | ["compat53.utf8"] = "lutf8lib.c", | ||
| 28 | ["compat53.table"] = "ltablib.c", | ||
| 29 | ["compat53.string"] = "lstrlib.c", | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
diff --git a/vendor/compat53/tests/test.lua b/vendor/compat53/tests/test.lua new file mode 100755 index 0000000..582f55e --- /dev/null +++ b/vendor/compat53/tests/test.lua | |||
| @@ -0,0 +1,789 @@ | |||
| 1 | #!/usr/bin/env lua | ||
| 2 | |||
| 3 | local F, tproxy, writefile, noprint, ___ | ||
| 4 | do | ||
| 5 | local type, unpack = type, table.unpack or unpack | ||
| 6 | local assert, io = assert, io | ||
| 7 | function F(...) | ||
| 8 | local args, n = { ... }, select('#', ...) | ||
| 9 | for i = 1, n do | ||
| 10 | local t = type(args[i]) | ||
| 11 | if t ~= "string" and t ~= "number" and t ~= "boolean" then | ||
| 12 | args[i] = t | ||
| 13 | end | ||
| 14 | end | ||
| 15 | return unpack(args, 1, n) | ||
| 16 | end | ||
| 17 | function tproxy(t) | ||
| 18 | return setmetatable({}, { | ||
| 19 | __index = t, | ||
| 20 | __newindex = t, | ||
| 21 | __len = function() return #t end, | ||
| 22 | }), t | ||
| 23 | end | ||
| 24 | function writefile(name, contents, bin) | ||
| 25 | local f = assert(io.open(name, bin and "wb" or "w")) | ||
| 26 | f:write(contents) | ||
| 27 | f:close() | ||
| 28 | end | ||
| 29 | function noprint() end | ||
| 30 | local sep = ("="):rep(70) | ||
| 31 | function ___() | ||
| 32 | print(sep) | ||
| 33 | end | ||
| 34 | end | ||
| 35 | |||
| 36 | local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") | ||
| 37 | if jit then V = "jit" end | ||
| 38 | |||
| 39 | local mode = "global" | ||
| 40 | if arg[1] == "module" then | ||
| 41 | mode = "module" | ||
| 42 | end | ||
| 43 | |||
| 44 | |||
| 45 | package.path = "../?.lua;../?/init.lua" | ||
| 46 | package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" | ||
| 47 | if mode == "module" then | ||
| 48 | print("testing Lua API using `compat53.module` ...") | ||
| 49 | _ENV = require("compat53.module") | ||
| 50 | if setfenv then setfenv(1, _ENV) end | ||
| 51 | else | ||
| 52 | print("testing Lua API using `compat53` ...") | ||
| 53 | require("compat53") | ||
| 54 | end | ||
| 55 | |||
| 56 | |||
| 57 | ___'' | ||
| 58 | do | ||
| 59 | print("assert", F(pcall(assert, false))) | ||
| 60 | print("assert", F(pcall(assert, false, nil))) | ||
| 61 | print("assert", F(pcall(assert, false, "error msg"))) | ||
| 62 | print("assert", F(pcall(assert, nil, {}))) | ||
| 63 | print("assert", F(pcall(assert, 1, 2, 3))) | ||
| 64 | end | ||
| 65 | |||
| 66 | |||
| 67 | ___'' | ||
| 68 | do | ||
| 69 | local t = setmetatable({}, { __index = { 1, false, "three" } }) | ||
| 70 | for i,v in ipairs(t) do | ||
| 71 | print("ipairs", i, v) | ||
| 72 | end | ||
| 73 | end | ||
| 74 | |||
| 75 | |||
| 76 | ___'' | ||
| 77 | do | ||
| 78 | local p, t = tproxy{ "a", "b", "c" } | ||
| 79 | print("table.concat", table.concat(p)) | ||
| 80 | print("table.concat", table.concat(p, ",", 2)) | ||
| 81 | print("table.concat", table.concat(p, ".", 1, 2)) | ||
| 82 | print("table.concat", table.concat(t)) | ||
| 83 | print("table.concat", table.concat(t, ",", 2)) | ||
| 84 | print("table.concat", table.concat(t, ".", 1, 2)) | ||
| 85 | end | ||
| 86 | |||
| 87 | |||
| 88 | ___'' | ||
| 89 | do | ||
| 90 | local p, t = tproxy{ "a", "b", "c" } | ||
| 91 | table.insert(p, "d") | ||
| 92 | print("table.insert", next(p), t[4]) | ||
| 93 | table.insert(p, 1, "z") | ||
| 94 | print("table.insert", next(p), t[1], t[2]) | ||
| 95 | table.insert(p, 2, "y") | ||
| 96 | print("table.insert", next(p), t[1], t[2], p[3]) | ||
| 97 | t = { "a", "b", "c" } | ||
| 98 | table.insert(t, "d") | ||
| 99 | print("table.insert", t[1], t[2], t[3], t[4]) | ||
| 100 | table.insert(t, 1, "z") | ||
| 101 | print("table.insert", t[1], t[2], t[3], t[4], t[5]) | ||
| 102 | table.insert(t, 2, "y") | ||
| 103 | print("table.insert", t[1], t[2], t[3], t[4], t[5]) | ||
| 104 | end | ||
| 105 | |||
| 106 | |||
| 107 | ___'' | ||
| 108 | do | ||
| 109 | local ps, s = tproxy{ "a", "b", "c", "d" } | ||
| 110 | local pd, d = tproxy{ "A", "B", "C", "D" } | ||
| 111 | table.move(ps, 1, 4, 1, pd) | ||
| 112 | print("table.move", next(pd), d[1], d[2], d[3], d[4]) | ||
| 113 | pd, d = tproxy{ "A", "B", "C", "D" } | ||
| 114 | table.move(ps, 2, 4, 1, pd) | ||
| 115 | print("table.move", next(pd), d[1], d[2], d[3], d[4]) | ||
| 116 | pd, d = tproxy{ "A", "B", "C", "D" } | ||
| 117 | table.move(ps, 2, 3, 4, pd) | ||
| 118 | print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5]) | ||
| 119 | table.move(ps, 2, 4, 1) | ||
| 120 | print("table.move", next(ps), s[1], s[2], s[3], s[4]) | ||
| 121 | ps, s = tproxy{ "a", "b", "c", "d" } | ||
| 122 | table.move(ps, 2, 3, 4) | ||
| 123 | print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5]) | ||
| 124 | s = { "a", "b", "c", "d" } | ||
| 125 | d = { "A", "B", "C", "D" } | ||
| 126 | table.move(s, 1, 4, 1, d) | ||
| 127 | print("table.move", d[1], d[2], d[3], d[4]) | ||
| 128 | d = { "A", "B", "C", "D" } | ||
| 129 | table.move(s, 2, 4, 1, d) | ||
| 130 | print("table.move", d[1], d[2], d[3], d[4]) | ||
| 131 | d = { "A", "B", "C", "D" } | ||
| 132 | table.move(s, 2, 3, 4, d) | ||
| 133 | print("table.move", d[1], d[2], d[3], d[4], d[5]) | ||
| 134 | table.move(s, 2, 4, 1) | ||
| 135 | print("table.move", s[1], s[2], s[3], s[4]) | ||
| 136 | s = { "a", "b", "c", "d" } | ||
| 137 | table.move(s, 2, 3, 4) | ||
| 138 | print("table.move", s[1], s[2], s[3], s[4], s[5]) | ||
| 139 | end | ||
| 140 | |||
| 141 | |||
| 142 | ___'' | ||
| 143 | do | ||
| 144 | local p, t = tproxy{ "a", "b", "c", "d", "e" } | ||
| 145 | print("table.remove", table.remove(p)) | ||
| 146 | print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5]) | ||
| 147 | print("table.remove", table.remove(p, 1)) | ||
| 148 | print("table.remove", next(p), t[1], t[2], t[3], t[4]) | ||
| 149 | print("table.remove", table.remove(p, 2)) | ||
| 150 | print("table.remove", next(p), t[1], t[2], t[3]) | ||
| 151 | print("table.remove", table.remove(p, 3)) | ||
| 152 | print("table.remove", next(p), t[1], t[2], t[3]) | ||
| 153 | p, t = tproxy{} | ||
| 154 | print("table.remove", table.remove(p)) | ||
| 155 | print("table.remove", next(p), next(t)) | ||
| 156 | t = { "a", "b", "c", "d", "e" } | ||
| 157 | print("table.remove", table.remove(t)) | ||
| 158 | print("table.remove", t[1], t[2], t[3], t[4], t[5]) | ||
| 159 | print("table.remove", table.remove(t, 1)) | ||
| 160 | print("table.remove", t[1], t[2], t[3], t[4]) | ||
| 161 | print("table.remove", table.remove(t, 2)) | ||
| 162 | print("table.remove", t[1], t[2], t[3]) | ||
| 163 | print("table.remove", table.remove(t, 3)) | ||
| 164 | print("table.remove", t[1], t[2], t[3]) | ||
| 165 | t = {} | ||
| 166 | print("table.remove", table.remove(t)) | ||
| 167 | print("table.remove", next(t)) | ||
| 168 | end | ||
| 169 | |||
| 170 | ___'' | ||
| 171 | do | ||
| 172 | local p, t = tproxy{ 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } | ||
| 173 | table.sort(p) | ||
| 174 | print("table.sort", next(p)) | ||
| 175 | for i,v in ipairs(t) do | ||
| 176 | print("table.sort", i, v) | ||
| 177 | end | ||
| 178 | table.sort(p) | ||
| 179 | print("table.sort", next(p)) | ||
| 180 | for i,v in ipairs(t) do | ||
| 181 | print("table.sort", i, v) | ||
| 182 | end | ||
| 183 | p, t = tproxy{ 9, 8, 7, 6, 5, 4, 3, 2, 1 } | ||
| 184 | table.sort(p) | ||
| 185 | print("table.sort", next(p)) | ||
| 186 | for i,v in ipairs(t) do | ||
| 187 | print("table.sort", i, v) | ||
| 188 | end | ||
| 189 | table.sort(p, function(a, b) return a > b end) | ||
| 190 | print("table.sort", next(p)) | ||
| 191 | for i,v in ipairs(t) do | ||
| 192 | print("table.sort", i, v) | ||
| 193 | end | ||
| 194 | p, t = tproxy{ 1, 1, 1, 1, 1 } | ||
| 195 | print("table.sort", next(p)) | ||
| 196 | for i,v in ipairs(t) do | ||
| 197 | print("table.sort", i, v) | ||
| 198 | end | ||
| 199 | t = { 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } | ||
| 200 | table.sort(t) | ||
| 201 | for i,v in ipairs(t) do | ||
| 202 | print("table.sort", i, v) | ||
| 203 | end | ||
| 204 | table.sort(t, function(a, b) return a > b end) | ||
| 205 | for i,v in ipairs(t) do | ||
| 206 | print("table.sort", i, v) | ||
| 207 | end | ||
| 208 | end | ||
| 209 | |||
| 210 | |||
| 211 | ___'' | ||
| 212 | do | ||
| 213 | local p, t = tproxy{ "a", "b", "c" } | ||
| 214 | print("table.unpack", table.unpack(p)) | ||
| 215 | print("table.unpack", table.unpack(p, 2)) | ||
| 216 | print("table.unpack", table.unpack(p, 1, 2)) | ||
| 217 | print("table.unpack", table.unpack(t)) | ||
| 218 | print("table.unpack", table.unpack(t, 2)) | ||
| 219 | print("table.unpack", table.unpack(t, 1, 2)) | ||
| 220 | end | ||
| 221 | |||
| 222 | |||
| 223 | ___'' | ||
| 224 | print("math.maxinteger", math.maxinteger+1 > math.maxinteger) | ||
| 225 | print("math.mininteger", math.mininteger-1 < math.mininteger) | ||
| 226 | |||
| 227 | |||
| 228 | ___'' | ||
| 229 | print("math.tointeger", math.tointeger(0)) | ||
| 230 | print("math.tointeger", math.tointeger(math.pi)) | ||
| 231 | print("math.tointeger", math.tointeger("hello")) | ||
| 232 | print("math.tointeger", math.tointeger(math.maxinteger+2.0)) | ||
| 233 | print("math.tointeger", math.tointeger(math.mininteger*2.0)) | ||
| 234 | |||
| 235 | |||
| 236 | ___'' | ||
| 237 | print("math.type", math.type(0)) | ||
| 238 | print("math.type", math.type(math.pi)) | ||
| 239 | print("math.type", math.type("hello")) | ||
| 240 | |||
| 241 | |||
| 242 | ___'' | ||
| 243 | print("math.ult", math.ult(1, 2), math.ult(2, 1)) | ||
| 244 | print("math.ult", math.ult(-1, 2), math.ult(2, -1)) | ||
| 245 | print("math.ult", math.ult(-1, -2), math.ult(-2, -1)) | ||
| 246 | print("math.ult", pcall(math.ult, "x", 2)) | ||
| 247 | print("math.ult", pcall(math.ult, 1, 2.1)) | ||
| 248 | ___'' | ||
| 249 | |||
| 250 | |||
| 251 | if utf8.len then | ||
| 252 | local unpack = table.unpack or unpack | ||
| 253 | local function utf8rt(s) | ||
| 254 | local t = { utf8.codepoint(s, 1, #s) } | ||
| 255 | local ps, cs = {}, {} | ||
| 256 | for p,c in utf8.codes(s) do | ||
| 257 | ps[#ps+1], cs[#cs+1] = p, c | ||
| 258 | end | ||
| 259 | print("utf8.codes", unpack(ps)) | ||
| 260 | print("utf8.codes", unpack(cs)) | ||
| 261 | print("utf8.codepoint", unpack(t)) | ||
| 262 | print("utf8.len", utf8.len(s), #t, #s) | ||
| 263 | print("utf8.char", utf8.char(unpack(t))) | ||
| 264 | end | ||
| 265 | utf8rt("äöüßÄÖÜ") | ||
| 266 | utf8rt("abcdefg") | ||
| 267 | ___'' | ||
| 268 | local s = "äöüßÄÖÜ" | ||
| 269 | print("utf8.offset", utf8.offset(s, 1, 1)) | ||
| 270 | print("utf8.offset", utf8.offset(s, 2, 1)) | ||
| 271 | print("utf8.offset", utf8.offset(s, 3, 1)) | ||
| 272 | print("utf8.offset", pcall(utf8.offset, s, 3, 2)) | ||
| 273 | print("utf8.offset", utf8.offset(s, 3, 3)) | ||
| 274 | print("utf8.offset", utf8.offset(s, -1, 7)) | ||
| 275 | print("utf8.offset", utf8.offset(s, -2, 7)) | ||
| 276 | print("utf8.offset", utf8.offset(s, -3, 7)) | ||
| 277 | print("utf8.offset", utf8.offset(s, -1)) | ||
| 278 | ___'' | ||
| 279 | else | ||
| 280 | print("XXX: utf8 module not available") | ||
| 281 | end | ||
| 282 | |||
| 283 | |||
| 284 | if string.pack then | ||
| 285 | local format = "bBhHlLjJdc3z" | ||
| 286 | local s = string.pack(format, -128, 255, -32768, 65535, -2147483648, 4294967295, -32768, 65536, 1.25, "abc", "defgh") | ||
| 287 | print("string.unpack", string.unpack(format, s)) | ||
| 288 | ___'' | ||
| 289 | else | ||
| 290 | print("XXX: string packing not available") | ||
| 291 | end | ||
| 292 | |||
| 293 | |||
| 294 | print("testing Lua API for Lua 5.1 ...") | ||
| 295 | |||
| 296 | ___'' | ||
| 297 | print("debug.getuservalue()", F(debug.getuservalue(false))) | ||
| 298 | print("debug.setuservalue()", pcall(function() | ||
| 299 | debug.setuservalue(false, {}) | ||
| 300 | end)) | ||
| 301 | print("debug.setmetatable()", F(debug.setmetatable({}, {}))) | ||
| 302 | |||
| 303 | |||
| 304 | ___'' | ||
| 305 | do | ||
| 306 | local t = setmetatable({}, { | ||
| 307 | __pairs = function() return pairs({ a = "a" }) end, | ||
| 308 | }) | ||
| 309 | for k,v in pairs(t) do | ||
| 310 | print("pairs()", k, v) | ||
| 311 | end | ||
| 312 | end | ||
| 313 | |||
| 314 | |||
| 315 | ___'' | ||
| 316 | do | ||
| 317 | local code = "print('hello world')\n" | ||
| 318 | local badcode = "print('blub\n" | ||
| 319 | print("load()", pcall(function() load(true) end)) | ||
| 320 | print("load()", F(load(badcode))) | ||
| 321 | print("load()", F(load(code))) | ||
| 322 | print("load()", F(load(code, "[L]"))) | ||
| 323 | print("load()", F(load(code, "[L]", "b"))) | ||
| 324 | print("load()", F(load(code, "[L]", "t"))) | ||
| 325 | print("load()", F(load(code, "[L]", "bt"))) | ||
| 326 | local f = load(code, "[L]", "bt", {}) | ||
| 327 | print("load()", pcall(f)) | ||
| 328 | f = load(code, "[L]", "bt", { print = noprint }) | ||
| 329 | print("load()", pcall(f)) | ||
| 330 | local bytecode = string.dump(f) | ||
| 331 | print("load()", F(load(bytecode))) | ||
| 332 | print("load()", F(load(bytecode, "[L]"))) | ||
| 333 | print("load()", F(load(bytecode, "[L]", "b"))) | ||
| 334 | print("load()", F(load(bytecode, "[L]", "t"))) | ||
| 335 | print("load()", F(load(bytecode, "[L]", "bt"))) | ||
| 336 | f = load(bytecode, "[L]", "bt", {}) | ||
| 337 | print("load()", pcall(f)) | ||
| 338 | f = load(bytecode, "[L]", "bt", { print = noprint }) | ||
| 339 | print("load()", pcall(f)) | ||
| 340 | local function make_loader(code) | ||
| 341 | local mid = math.floor( #code/2 ) | ||
| 342 | local array = { code:sub(1, mid), code:sub(mid+1) } | ||
| 343 | local i = 0 | ||
| 344 | return function() | ||
| 345 | i = i + 1 | ||
| 346 | return array[i] | ||
| 347 | end | ||
| 348 | end | ||
| 349 | print("load()", F(load(make_loader(badcode)))) | ||
| 350 | print("load()", F(load(make_loader(code)))) | ||
| 351 | print("load()", F(load(make_loader(code), "[L]"))) | ||
| 352 | print("load()", F(load(make_loader(code), "[L]", "b"))) | ||
| 353 | print("load()", F(load(make_loader(code), "[L]", "t"))) | ||
| 354 | print("load()", F(load(make_loader(code), "[L]", "bt"))) | ||
| 355 | f = load(make_loader(code), "[L]", "bt", {}) | ||
| 356 | print("load()", pcall(f)) | ||
| 357 | f = load(make_loader(code), "[L]", "bt", { print = noprint }) | ||
| 358 | print("load()", pcall(f)) | ||
| 359 | print("load()", F(load(make_loader(bytecode)))) | ||
| 360 | print("load()", F(load(make_loader(bytecode), "[L]"))) | ||
| 361 | print("load()", F(load(make_loader(bytecode), "[L]", "b"))) | ||
| 362 | print("load()", F(load(make_loader(bytecode), "[L]", "t"))) | ||
| 363 | print("load()", F(load(make_loader(bytecode), "[L]", "bt"))) | ||
| 364 | f = load(make_loader(bytecode), "[L]", "bt", {}) | ||
| 365 | print("load()", pcall(f)) | ||
| 366 | f = load(make_loader(bytecode), "[L]", "bt", { print = noprint }) | ||
| 367 | print("load()", pcall(f)) | ||
| 368 | writefile("good.lua", code) | ||
| 369 | writefile("bad.lua", badcode) | ||
| 370 | writefile("good.luac", bytecode, true) | ||
| 371 | print("loadfile()", F(loadfile("bad.lua"))) | ||
| 372 | print("loadfile()", F(loadfile("good.lua"))) | ||
| 373 | print("loadfile()", F(loadfile("good.lua", "b"))) | ||
| 374 | print("loadfile()", F(loadfile("good.lua", "t"))) | ||
| 375 | print("loadfile()", F(loadfile("good.lua", "bt"))) | ||
| 376 | f = loadfile("good.lua", "bt", {}) | ||
| 377 | print("loadfile()", pcall(f)) | ||
| 378 | f = loadfile("good.lua", "bt", { print = noprint }) | ||
| 379 | print("loadfile()", pcall(f)) | ||
| 380 | print("loadfile()", F(loadfile("good.luac"))) | ||
| 381 | print("loadfile()", F(loadfile("good.luac", "b"))) | ||
| 382 | print("loadfile()", F(loadfile("good.luac", "t"))) | ||
| 383 | print("loadfile()", F(loadfile("good.luac", "bt"))) | ||
| 384 | f = loadfile("good.luac", "bt", {}) | ||
| 385 | print("loadfile()", pcall(f)) | ||
| 386 | f = loadfile("good.luac", "bt", { print = noprint }) | ||
| 387 | print("loadfile()", pcall(f)) | ||
| 388 | os.remove("good.lua") | ||
| 389 | os.remove("bad.lua") | ||
| 390 | os.remove("good.luac") | ||
| 391 | end | ||
| 392 | |||
| 393 | |||
| 394 | ___'' | ||
| 395 | do | ||
| 396 | local function func(throw) | ||
| 397 | if throw then | ||
| 398 | error("argh") | ||
| 399 | else | ||
| 400 | return 1, 2, 3 | ||
| 401 | end | ||
| 402 | end | ||
| 403 | local function tb(err) return "|"..err.."|" end | ||
| 404 | print("xpcall()", xpcall(func, debug.traceback, false)) | ||
| 405 | print("xpcall()", xpcall(func, debug.traceback, true)) | ||
| 406 | print("xpcall()", xpcall(func, tb, true)) | ||
| 407 | if mode ~= "module" then | ||
| 408 | local function func2(cb) | ||
| 409 | print("xpcall()", xpcall(cb, debug.traceback, "str")) | ||
| 410 | end | ||
| 411 | local function func3(cb) | ||
| 412 | print("pcall()", pcall(cb, "str")) | ||
| 413 | end | ||
| 414 | local function cb(arg) | ||
| 415 | coroutine.yield(2) | ||
| 416 | return arg | ||
| 417 | end | ||
| 418 | local c = coroutine.wrap(func2) | ||
| 419 | print("xpcall()", c(cb)) | ||
| 420 | print("xpcall()", c()) | ||
| 421 | local c = coroutine.wrap(func3) | ||
| 422 | print("pcall()", c(cb)) | ||
| 423 | print("pcall()", c()) | ||
| 424 | end | ||
| 425 | end | ||
| 426 | |||
| 427 | |||
| 428 | ___'' | ||
| 429 | do | ||
| 430 | local t = setmetatable({ 1 }, { __len = function() return 5 end }) | ||
| 431 | print("rawlen()", rawlen(t), rawlen("123")) | ||
| 432 | end | ||
| 433 | |||
| 434 | |||
| 435 | ___'' | ||
| 436 | print("os.execute()", os.execute("exit 1")) | ||
| 437 | io.flush() | ||
| 438 | print("os.execute()", os.execute("echo 'hello world!'")) | ||
| 439 | io.flush() | ||
| 440 | print("os.execute()", os.execute("no_such_file")) | ||
| 441 | |||
| 442 | |||
| 443 | ___'' | ||
| 444 | do | ||
| 445 | local t = table.pack("a", nil, "b", nil) | ||
| 446 | print("table.(un)pack()", t.n, table.unpack(t, 1, t.n)) | ||
| 447 | end | ||
| 448 | |||
| 449 | |||
| 450 | ___'' | ||
| 451 | do | ||
| 452 | print("coroutine.running()", F(coroutine.wrap(function() | ||
| 453 | return coroutine.running() | ||
| 454 | end)())) | ||
| 455 | print("coroutine.running()", F(coroutine.running())) | ||
| 456 | local main_co, co1, co2 = coroutine.running() | ||
| 457 | -- coroutine.yield | ||
| 458 | if mode ~= "module" then | ||
| 459 | print("coroutine.yield()", pcall(function() | ||
| 460 | coroutine.yield(1, 2, 3) | ||
| 461 | end)) | ||
| 462 | end | ||
| 463 | print("coroutine.yield()", coroutine.wrap(function() | ||
| 464 | coroutine.yield(1, 2, 3) | ||
| 465 | end)()) | ||
| 466 | print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3)) | ||
| 467 | co1 = coroutine.create(function(a, b, c) | ||
| 468 | print("coroutine.resume()", a, b, c) | ||
| 469 | return a, b, c | ||
| 470 | end) | ||
| 471 | print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3)) | ||
| 472 | co1 = coroutine.create(function() | ||
| 473 | print("coroutine.status()", "[co1] main is", coroutine.status(main_co)) | ||
| 474 | print("coroutine.status()", "[co1] co2 is", coroutine.status(co2)) | ||
| 475 | end) | ||
| 476 | co2 = coroutine.create(function() | ||
| 477 | print("coroutine.status()", "[co2] main is", coroutine.status(main_co)) | ||
| 478 | print("coroutine.status()", "[co2] co2 is", coroutine.status(co2)) | ||
| 479 | coroutine.yield() | ||
| 480 | coroutine.resume(co1) | ||
| 481 | end) | ||
| 482 | print("coroutine.status()", coroutine.status(main_co)) | ||
| 483 | print("coroutine.status()", coroutine.status(co2)) | ||
| 484 | coroutine.resume(co2) | ||
| 485 | print("coroutine.status()", F(coroutine.status(co2))) | ||
| 486 | coroutine.resume(co2) | ||
| 487 | print("coroutine.status()", F(coroutine.status(co2))) | ||
| 488 | end | ||
| 489 | |||
| 490 | |||
| 491 | ___'' | ||
| 492 | print("math.log()", math.log(1000)) | ||
| 493 | print("math.log()", math.log(1000, 10)) | ||
| 494 | |||
| 495 | |||
| 496 | ___'' | ||
| 497 | do | ||
| 498 | local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" | ||
| 499 | print(prefix, package.searchpath("no.such.module", path)) | ||
| 500 | print(prefix, package.searchpath("no.such.module", "")) | ||
| 501 | print(prefix, package.searchpath("compat53", path)) | ||
| 502 | print(prefix, package.searchpath("no:such:module", path, ":", "|")) | ||
| 503 | end | ||
| 504 | |||
| 505 | |||
| 506 | ___'' | ||
| 507 | if mode ~= "module" then | ||
| 508 | local function mod_func() return {} end | ||
| 509 | local function my_searcher(name) | ||
| 510 | if name == "my.module" then | ||
| 511 | print("package.searchers", "my.module found") | ||
| 512 | return mod_func | ||
| 513 | end | ||
| 514 | end | ||
| 515 | local function my_searcher2(name) | ||
| 516 | if name == "my.module" then | ||
| 517 | print("package.searchers", "my.module found 2") | ||
| 518 | return mod_func | ||
| 519 | end | ||
| 520 | end | ||
| 521 | table.insert(package.searchers, my_searcher) | ||
| 522 | require("my.module") | ||
| 523 | package.loaded["my.module"] = nil | ||
| 524 | local new_s = { my_searcher2 } | ||
| 525 | for i,f in ipairs(package.searchers) do | ||
| 526 | new_s[i+1] = f | ||
| 527 | end | ||
| 528 | package.searchers = new_s | ||
| 529 | require("my.module") | ||
| 530 | end | ||
| 531 | |||
| 532 | |||
| 533 | ___'' | ||
| 534 | do | ||
| 535 | print("string.find()", string.find("abc\0abc\0abc", "[^a\0]+")) | ||
| 536 | print("string.find()", string.find("abc\0abc\0abc", "%w+\0", 5)) | ||
| 537 | for x in string.gmatch("abc\0def\0ghi", "[^\0]+") do | ||
| 538 | print("string.gmatch()", x) | ||
| 539 | end | ||
| 540 | for x in string.gmatch("abc\0def\0ghi", "%w*\0") do | ||
| 541 | print("string.gmatch()", #x) | ||
| 542 | end | ||
| 543 | print("string.gsub()", string.gsub("abc\0def\0ghi", "[\0]", "X")) | ||
| 544 | print("string.gsub()", string.gsub("abc\0def\0ghi", "%w*\0", "X")) | ||
| 545 | print("string.gsub()", string.gsub("abc\0def\0ghi", "%A", "X")) | ||
| 546 | print("string.match()", string.match("abc\0abc\0abc", "([^\0a]+)")) | ||
| 547 | print("string.match()", #string.match("abc\0abc\0abc", ".*\0")) | ||
| 548 | print("string.rep()", string.rep("a", 0)) | ||
| 549 | print("string.rep()", string.rep("b", 1)) | ||
| 550 | print("string.rep()", string.rep("c", 4)) | ||
| 551 | print("string.rep()", string.rep("a", 0, "|")) | ||
| 552 | print("string.rep()", string.rep("b", 1, "|")) | ||
| 553 | print("string.rep()", string.rep("c", 4, "|")) | ||
| 554 | local _tostring = tostring | ||
| 555 | function tostring(v) | ||
| 556 | if type(v) == "number" then | ||
| 557 | return "(".._tostring(v)..")" | ||
| 558 | else | ||
| 559 | return _tostring(v) | ||
| 560 | end | ||
| 561 | end | ||
| 562 | print("string.format()", string.format("%q", "\"\\\0000\0010\002\r\n0\t0\"")) | ||
| 563 | print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {})) | ||
| 564 | print("string.format()", string.format("%-3f %%%s %%s", 3.1, true)) | ||
| 565 | print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil)) | ||
| 566 | print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout)) | ||
| 567 | print("string.format()", pcall(function() | ||
| 568 | print("string.format()", string.format("%d %%s", {})) | ||
| 569 | end)) | ||
| 570 | tostring = _tostring | ||
| 571 | end | ||
| 572 | |||
| 573 | |||
| 574 | ___'' | ||
| 575 | do | ||
| 576 | print("io.write()", io.type(io.write("hello world\n"))) | ||
| 577 | local f = assert(io.tmpfile()) | ||
| 578 | print("file:write()", io.type(f:write("hello world\n"))) | ||
| 579 | f:close() | ||
| 580 | end | ||
| 581 | |||
| 582 | |||
| 583 | ___'' | ||
| 584 | do | ||
| 585 | writefile("data.txt", "123 18.8 hello world\ni'm here\n") | ||
| 586 | io.input("data.txt") | ||
| 587 | print("io.read()", io.read("*n", "*number", "*l", "*a")) | ||
| 588 | io.input("data.txt") | ||
| 589 | print("io.read()", io.read("n", "number", "l", "a")) | ||
| 590 | io.input(io.stdin) | ||
| 591 | if mode ~= "module" then | ||
| 592 | local f = assert(io.open("data.txt", "r")) | ||
| 593 | print("file:read()", f:read("*n", "*number", "*l", "*a")) | ||
| 594 | f:close() | ||
| 595 | f = assert(io.open("data.txt", "r")) | ||
| 596 | print("file:read()", f:read("n", "number", "l", "a")) | ||
| 597 | f:close() | ||
| 598 | end | ||
| 599 | os.remove("data.txt") | ||
| 600 | end | ||
| 601 | |||
| 602 | |||
| 603 | ___'' | ||
| 604 | do | ||
| 605 | writefile("data.txt", "123 18.8 hello world\ni'm here\n") | ||
| 606 | for a,b in io.lines("test.lua", 2, "*l") do | ||
| 607 | print("io.lines()", a, b) | ||
| 608 | break | ||
| 609 | end | ||
| 610 | for l in io.lines("test.lua") do | ||
| 611 | print("io.lines()", l) | ||
| 612 | break | ||
| 613 | end | ||
| 614 | for n1,n2,rest in io.lines("data.txt", "*n", "n", "*a") do | ||
| 615 | print("io.lines()", n1, n2, rest) | ||
| 616 | end | ||
| 617 | for l in io.lines("data.txt") do | ||
| 618 | print("io.lines()", l) | ||
| 619 | end | ||
| 620 | print("io.lines()", pcall(function() | ||
| 621 | for l in io.lines("data.txt", "*x") do print(l) end | ||
| 622 | end)) | ||
| 623 | print("io.lines()", pcall(function() | ||
| 624 | for l in io.lines("no_such_file.txt") do print(l) end | ||
| 625 | end)) | ||
| 626 | if mode ~= "module" then | ||
| 627 | local f = assert(io.open("test.lua", "r")) | ||
| 628 | for a,b in f:lines(2, "*l") do | ||
| 629 | print("file:lines()", a, b) | ||
| 630 | break | ||
| 631 | end | ||
| 632 | f:close() | ||
| 633 | f = assert(io.open("data.txt", "r")) | ||
| 634 | for n1,n2,rest in f:lines("*n", "n", "*a") do | ||
| 635 | print("file:lines()", n1, n2, rest) | ||
| 636 | end | ||
| 637 | f:close() | ||
| 638 | f = assert(io.open("data.txt", "r")) | ||
| 639 | for l in f:lines() do | ||
| 640 | print("file:lines()", l) | ||
| 641 | end | ||
| 642 | f:close() | ||
| 643 | print("file:lines()", pcall(function() | ||
| 644 | for l in f:lines() do print(l) end | ||
| 645 | end)) | ||
| 646 | print("file:lines()", pcall(function() | ||
| 647 | local f = assert(io.open("data.txt", "r")) | ||
| 648 | for l in f:lines("*l", "*x") do print(l) end | ||
| 649 | f:close() | ||
| 650 | end)) | ||
| 651 | end | ||
| 652 | os.remove("data.txt") | ||
| 653 | end | ||
| 654 | ___'' | ||
| 655 | |||
| 656 | |||
| 657 | print("testing C API ...") | ||
| 658 | local mod = require("testmod") | ||
| 659 | ___'' | ||
| 660 | print(mod.isinteger(1)) | ||
| 661 | print(mod.isinteger(0)) | ||
| 662 | print(mod.isinteger(1234567)) | ||
| 663 | print(mod.isinteger(12.3)) | ||
| 664 | print(mod.isinteger(math.huge)) | ||
| 665 | print(mod.isinteger(math.sqrt(-1))) | ||
| 666 | |||
| 667 | |||
| 668 | ___'' | ||
| 669 | print(mod.rotate(1, 1, 2, 3, 4, 5, 6)) | ||
| 670 | print(mod.rotate(-1, 1, 2, 3, 4, 5, 6)) | ||
| 671 | print(mod.rotate(4, 1, 2, 3, 4, 5, 6)) | ||
| 672 | print(mod.rotate(-4, 1, 2, 3, 4, 5, 6)) | ||
| 673 | |||
| 674 | |||
| 675 | ___'' | ||
| 676 | print(mod.strtonum("+123")) | ||
| 677 | print(mod.strtonum(" 123 ")) | ||
| 678 | print(mod.strtonum("-1.23")) | ||
| 679 | print(mod.strtonum(" 123 abc")) | ||
| 680 | print(mod.strtonum("jkl")) | ||
| 681 | |||
| 682 | |||
| 683 | ___'' | ||
| 684 | local a, b, c = mod.requiref() | ||
| 685 | print( type(a), type(b), type(c), | ||
| 686 | a.boolean, b.boolean, c.boolean, | ||
| 687 | type(requiref1), type(requiref2), type(requiref3)) | ||
| 688 | |||
| 689 | ___'' | ||
| 690 | local proxy, backend = {}, {} | ||
| 691 | setmetatable(proxy, { __index = backend, __newindex = backend }) | ||
| 692 | print(rawget(proxy, 1), rawget(backend, 1)) | ||
| 693 | print(mod.getseti(proxy, 1)) | ||
| 694 | print(rawget(proxy, 1), rawget(backend, 1)) | ||
| 695 | print(mod.getseti(proxy, 1)) | ||
| 696 | print(rawget(proxy, 1), rawget(backend, 1)) | ||
| 697 | |||
| 698 | -- tests for Lua 5.1 | ||
| 699 | ___'' | ||
| 700 | print(mod.tonumber(12)) | ||
| 701 | print(mod.tonumber("12")) | ||
| 702 | print(mod.tonumber("0")) | ||
| 703 | print(mod.tonumber(false)) | ||
| 704 | print(mod.tonumber("error")) | ||
| 705 | |||
| 706 | ___'' | ||
| 707 | print(mod.tointeger(12)) | ||
| 708 | print(mod.tointeger("12")) | ||
| 709 | print(mod.tointeger("0")) | ||
| 710 | print( "aaa" ) | ||
| 711 | print(mod.tointeger(math.pi)) | ||
| 712 | print( "bbb" ) | ||
| 713 | print(mod.tointeger(false)) | ||
| 714 | print(mod.tointeger("error")) | ||
| 715 | |||
| 716 | ___'' | ||
| 717 | print(mod.len("123")) | ||
| 718 | print(mod.len({ 1, 2, 3})) | ||
| 719 | print(pcall(mod.len, true)) | ||
| 720 | local ud, meta = mod.newproxy() | ||
| 721 | meta.__len = function() return 5 end | ||
| 722 | print(mod.len(ud)) | ||
| 723 | meta.__len = function() return true end | ||
| 724 | print(pcall(mod.len, ud)) | ||
| 725 | |||
| 726 | ___'' | ||
| 727 | print(mod.copy(true, "string", {}, 1)) | ||
| 728 | |||
| 729 | ___'' | ||
| 730 | print(mod.rawxetp()) | ||
| 731 | print(mod.rawxetp("I'm back")) | ||
| 732 | |||
| 733 | ___'' | ||
| 734 | print(F(mod.globals()), mod.globals() == _G) | ||
| 735 | |||
| 736 | ___'' | ||
| 737 | local t = {} | ||
| 738 | print(F(mod.subtable(t))) | ||
| 739 | local x, msg = mod.subtable(t) | ||
| 740 | print(F(x, msg, x == t.xxx)) | ||
| 741 | |||
| 742 | ___'' | ||
| 743 | print(F(mod.udata())) | ||
| 744 | print(mod.udata("nosuchtype")) | ||
| 745 | |||
| 746 | ___'' | ||
| 747 | print(F(mod.uservalue())) | ||
| 748 | |||
| 749 | ___'' | ||
| 750 | print(mod.getupvalues()) | ||
| 751 | |||
| 752 | ___'' | ||
| 753 | print(mod.absindex("hi", true)) | ||
| 754 | |||
| 755 | ___'' | ||
| 756 | print(mod.arith(2, 1)) | ||
| 757 | print(mod.arith(3, 5)) | ||
| 758 | |||
| 759 | ___'' | ||
| 760 | print(mod.compare(1, 1)) | ||
| 761 | print(mod.compare(2, 1)) | ||
| 762 | print(mod.compare(1, 2)) | ||
| 763 | |||
| 764 | ___'' | ||
| 765 | print(mod.tolstring("string")) | ||
| 766 | local t = setmetatable({}, { | ||
| 767 | __tostring = function(v) return "mytable" end | ||
| 768 | }) | ||
| 769 | print(mod.tolstring(t)) | ||
| 770 | local t = setmetatable({}, { | ||
| 771 | __tostring = function(v) return nil end | ||
| 772 | }) | ||
| 773 | print(pcall(mod.tolstring, t)) | ||
| 774 | local ud, meta = mod.newproxy() | ||
| 775 | meta.__name = "XXX" | ||
| 776 | print(mod.tolstring(ud):gsub(":.*$", ": yyy")) | ||
| 777 | |||
| 778 | ___'' | ||
| 779 | print(mod.pushstring()) | ||
| 780 | |||
| 781 | ___'' | ||
| 782 | print(mod.buffer()) | ||
| 783 | |||
| 784 | ___'' | ||
| 785 | print(mod.exec("exit 0")) | ||
| 786 | print(mod.exec("exit 1")) | ||
| 787 | print(mod.exec("exit 25")) | ||
| 788 | ___'' | ||
| 789 | |||
diff --git a/vendor/compat53/tests/testmod.c b/vendor/compat53/tests/testmod.c new file mode 100644 index 0000000..868136b --- /dev/null +++ b/vendor/compat53/tests/testmod.c | |||
| @@ -0,0 +1,318 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <lua.h> | ||
| 4 | #include <lauxlib.h> | ||
| 5 | #include "compat-5.3.h" | ||
| 6 | |||
| 7 | |||
| 8 | static int test_isinteger (lua_State *L) { | ||
| 9 | lua_pushboolean(L, lua_isinteger(L, 1)); | ||
| 10 | return 1; | ||
| 11 | } | ||
| 12 | |||
| 13 | |||
| 14 | static int test_rotate (lua_State *L) { | ||
| 15 | int r = luaL_checkint(L, 1); | ||
| 16 | int n = lua_gettop(L)-1; | ||
| 17 | luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments"); | ||
| 18 | lua_rotate(L, 2, r); | ||
| 19 | return n; | ||
| 20 | } | ||
| 21 | |||
| 22 | |||
| 23 | static int test_str2num (lua_State *L) { | ||
| 24 | const char *s = luaL_checkstring(L, 1); | ||
| 25 | size_t len = lua_stringtonumber(L, s); | ||
| 26 | if (len == 0) | ||
| 27 | lua_pushnumber(L, 0); | ||
| 28 | lua_pushinteger(L, (lua_Integer)len); | ||
| 29 | return 2; | ||
| 30 | } | ||
| 31 | |||
| 32 | |||
| 33 | static int my_mod (lua_State *L ) { | ||
| 34 | lua_newtable(L); | ||
| 35 | lua_pushboolean(L, 1); | ||
| 36 | lua_setfield(L, -2, "boolean"); | ||
| 37 | return 1; | ||
| 38 | } | ||
| 39 | |||
| 40 | static int test_requiref (lua_State *L) { | ||
| 41 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | ||
| 42 | lua_newtable(L); | ||
| 43 | lua_pushboolean(L, 0); | ||
| 44 | lua_setfield(L, -2, "boolean"); | ||
| 45 | lua_setfield(L, -2, "requiref3"); | ||
| 46 | lua_pop(L, 1); | ||
| 47 | luaL_requiref(L, "requiref1", my_mod, 0); | ||
| 48 | luaL_requiref(L, "requiref2", my_mod, 1); | ||
| 49 | luaL_requiref(L, "requiref3", my_mod, 1); | ||
| 50 | return 3; | ||
| 51 | } | ||
| 52 | |||
| 53 | static int test_getseti (lua_State *L) { | ||
| 54 | lua_Integer k = luaL_checkinteger(L, 2); | ||
| 55 | lua_Integer n = 0; | ||
| 56 | if (lua_geti(L, 1, k) == LUA_TNUMBER) { | ||
| 57 | n = lua_tointeger(L, -1); | ||
| 58 | } else { | ||
| 59 | lua_pop(L, 1); | ||
| 60 | lua_pushinteger(L, n); | ||
| 61 | } | ||
| 62 | lua_pushinteger(L, n+1); | ||
| 63 | lua_seti(L, 1, k); | ||
| 64 | return 1; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | /* additional tests for Lua5.1 */ | ||
| 69 | #define NUP 3 | ||
| 70 | |||
| 71 | static int test_newproxy (lua_State *L) { | ||
| 72 | lua_settop(L, 0); | ||
| 73 | lua_newuserdata(L, 0); | ||
| 74 | lua_newtable(L); | ||
| 75 | lua_pushvalue(L, -1); | ||
| 76 | lua_pushboolean(L, 1); | ||
| 77 | lua_setfield(L, -2, "__gc"); | ||
| 78 | lua_setmetatable(L, -3); | ||
| 79 | return 2; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int test_absindex (lua_State *L) { | ||
| 83 | int i = 1; | ||
| 84 | for (i = 1; i <= NUP; ++i) | ||
| 85 | lua_pushvalue(L, lua_absindex(L, lua_upvalueindex(i))); | ||
| 86 | lua_pushvalue(L, lua_absindex(L, LUA_REGISTRYINDEX)); | ||
| 87 | lua_pushstring(L, lua_typename(L, lua_type(L, lua_absindex(L, -1)))); | ||
| 88 | lua_replace(L, lua_absindex(L, -2)); | ||
| 89 | lua_pushvalue(L, lua_absindex(L, -2)); | ||
| 90 | lua_pushvalue(L, lua_absindex(L, -4)); | ||
| 91 | lua_pushvalue(L, lua_absindex(L, -6)); | ||
| 92 | i += 3; | ||
| 93 | lua_pushvalue(L, lua_absindex(L, 1)); | ||
| 94 | lua_pushvalue(L, lua_absindex(L, 2)); | ||
| 95 | lua_pushvalue(L, lua_absindex(L, 3)); | ||
| 96 | i += 3; | ||
| 97 | return i; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int test_arith (lua_State *L) { | ||
| 101 | lua_settop(L, 2); | ||
| 102 | lua_pushvalue(L, 1); | ||
| 103 | lua_pushvalue(L, 2); | ||
| 104 | lua_arith(L, LUA_OPADD); | ||
| 105 | lua_pushvalue(L, 1); | ||
| 106 | lua_pushvalue(L, 2); | ||
| 107 | lua_arith(L, LUA_OPSUB); | ||
| 108 | lua_pushvalue(L, 1); | ||
| 109 | lua_pushvalue(L, 2); | ||
| 110 | lua_arith(L, LUA_OPMUL); | ||
| 111 | lua_pushvalue(L, 1); | ||
| 112 | lua_pushvalue(L, 2); | ||
| 113 | lua_arith(L, LUA_OPDIV); | ||
| 114 | lua_pushvalue(L, 1); | ||
| 115 | lua_pushvalue(L, 2); | ||
| 116 | lua_arith(L, LUA_OPMOD); | ||
| 117 | lua_pushvalue(L, 1); | ||
| 118 | lua_pushvalue(L, 2); | ||
| 119 | lua_arith(L, LUA_OPPOW); | ||
| 120 | lua_pushvalue(L, 1); | ||
| 121 | lua_arith(L, LUA_OPUNM); | ||
| 122 | return lua_gettop(L)-2; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int test_compare (lua_State *L) { | ||
| 126 | luaL_checknumber(L, 1); | ||
| 127 | luaL_checknumber(L, 2); | ||
| 128 | lua_settop(L, 2); | ||
| 129 | lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPEQ)); | ||
| 130 | lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLT)); | ||
| 131 | lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLE)); | ||
| 132 | return 3; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int test_globals (lua_State *L) { | ||
| 136 | lua_pushglobaltable(L); | ||
| 137 | return 1; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int test_tonumber (lua_State *L) { | ||
| 141 | int isnum = 0; | ||
| 142 | lua_Number n = lua_tonumberx(L, 1, &isnum); | ||
| 143 | if (!isnum) | ||
| 144 | lua_pushnil(L); | ||
| 145 | else | ||
| 146 | lua_pushnumber(L, n); | ||
| 147 | return 1; | ||
| 148 | } | ||
| 149 | |||
| 150 | static int test_tointeger (lua_State *L) { | ||
| 151 | int isnum = 0; | ||
| 152 | lua_Integer n = lua_tointegerx(L, 1, &isnum); | ||
| 153 | if (!isnum) | ||
| 154 | lua_pushnil(L); | ||
| 155 | else | ||
| 156 | lua_pushinteger(L, n); | ||
| 157 | return 1; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int test_len (lua_State *L) { | ||
| 161 | luaL_checkany(L, 1); | ||
| 162 | lua_len(L, 1); | ||
| 163 | lua_pushinteger(L, luaL_len(L, 1)); | ||
| 164 | return 2; | ||
| 165 | } | ||
| 166 | |||
| 167 | static int test_copy (lua_State *L) { | ||
| 168 | int args = lua_gettop(L); | ||
| 169 | if (args >= 2) { | ||
| 170 | int i = 0; | ||
| 171 | for (i = args-1; i > 0; --i) | ||
| 172 | lua_copy(L, args, i); | ||
| 173 | } | ||
| 174 | return args; | ||
| 175 | } | ||
| 176 | |||
| 177 | /* need an address */ | ||
| 178 | static char const dummy = 0; | ||
| 179 | |||
| 180 | static int test_rawxetp (lua_State *L) { | ||
| 181 | if (lua_gettop(L) > 0) | ||
| 182 | lua_pushvalue(L, 1); | ||
| 183 | else | ||
| 184 | lua_pushliteral(L, "hello again"); | ||
| 185 | lua_rawsetp(L, LUA_REGISTRYINDEX, &dummy); | ||
| 186 | lua_settop(L, 0); | ||
| 187 | lua_rawgetp(L, LUA_REGISTRYINDEX, &dummy); | ||
| 188 | return 1; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int test_udata (lua_State *L) { | ||
| 192 | const char *tname = luaL_optstring(L, 1, "utype1"); | ||
| 193 | void *u1 = lua_newuserdata(L, 1); | ||
| 194 | int u1pos = lua_gettop(L); | ||
| 195 | void *u2 = lua_newuserdata(L, 1); | ||
| 196 | int u2pos = lua_gettop(L); | ||
| 197 | luaL_newmetatable(L, "utype1"); | ||
| 198 | luaL_newmetatable(L, "utype2"); | ||
| 199 | lua_pop(L, 2); | ||
| 200 | luaL_setmetatable(L, "utype2"); | ||
| 201 | lua_pushvalue(L, u1pos); | ||
| 202 | luaL_setmetatable(L, "utype1"); | ||
| 203 | lua_pop(L, 1); | ||
| 204 | (void)u1; | ||
| 205 | (void)u2; | ||
| 206 | lua_pushlightuserdata(L, luaL_testudata(L, u1pos, tname)); | ||
| 207 | lua_pushlightuserdata(L, luaL_testudata(L, u2pos, tname)); | ||
| 208 | luaL_getmetatable(L, "utype1"); | ||
| 209 | lua_getfield(L, -1, "__name"); | ||
| 210 | lua_replace(L, -2); | ||
| 211 | return 3; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int test_subtable (lua_State *L) { | ||
| 215 | luaL_checktype(L, 1, LUA_TTABLE); | ||
| 216 | lua_settop(L, 1); | ||
| 217 | if (luaL_getsubtable(L, 1, "xxx")) { | ||
| 218 | lua_pushliteral(L, "oldtable"); | ||
| 219 | } else { | ||
| 220 | lua_pushliteral(L, "newtable"); | ||
| 221 | } | ||
| 222 | return 2; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int test_uservalue (lua_State *L) { | ||
| 226 | void *udata = lua_newuserdata(L, 1); | ||
| 227 | int ui = lua_gettop(L); | ||
| 228 | lua_newtable(L); | ||
| 229 | lua_setuservalue(L, ui); | ||
| 230 | lua_getuservalue(L, ui); | ||
| 231 | (void)udata; | ||
| 232 | return 1; | ||
| 233 | } | ||
| 234 | |||
| 235 | static int test_upvalues (lua_State *L) { | ||
| 236 | int i = 1; | ||
| 237 | for (i = 1; i <= NUP; ++i) | ||
| 238 | lua_pushvalue(L, lua_upvalueindex(i)); | ||
| 239 | return NUP; | ||
| 240 | } | ||
| 241 | |||
| 242 | static int test_tolstring (lua_State *L) { | ||
| 243 | size_t len = 0; | ||
| 244 | luaL_tolstring(L, 1, &len); | ||
| 245 | lua_pushinteger(L, (int)len); | ||
| 246 | return 2; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int test_pushstring (lua_State *L) { | ||
| 250 | lua_pushstring(L, lua_pushliteral(L, "abc")); | ||
| 251 | lua_pushstring(L, lua_pushlstring(L, "abc", 2)); | ||
| 252 | lua_pushstring(L, lua_pushlstring(L, NULL, 0)); | ||
| 253 | lua_pushstring(L, lua_pushstring(L, "abc")); | ||
| 254 | lua_pushboolean(L, NULL == lua_pushstring(L, NULL)); | ||
| 255 | return 10; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int test_buffer (lua_State *L) { | ||
| 259 | luaL_Buffer b; | ||
| 260 | char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1); | ||
| 261 | p[0] = 'a'; | ||
| 262 | p[1] = 'b'; | ||
| 263 | luaL_addsize(&b, 2); | ||
| 264 | luaL_addstring(&b, "c"); | ||
| 265 | lua_pushliteral(L, "d"); | ||
| 266 | luaL_addvalue(&b); | ||
| 267 | luaL_addchar(&b, 'e'); | ||
| 268 | luaL_pushresult(&b); | ||
| 269 | return 1; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int test_exec (lua_State *L) { | ||
| 273 | const char *cmd = luaL_checkstring(L, 1); | ||
| 274 | return luaL_execresult(L, system(cmd)); | ||
| 275 | } | ||
| 276 | |||
| 277 | |||
| 278 | static const luaL_Reg funcs[] = { | ||
| 279 | { "isinteger", test_isinteger }, | ||
| 280 | { "rotate", test_rotate }, | ||
| 281 | { "strtonum", test_str2num }, | ||
| 282 | { "requiref", test_requiref }, | ||
| 283 | { "getseti", test_getseti }, | ||
| 284 | { "newproxy", test_newproxy }, | ||
| 285 | { "arith", test_arith }, | ||
| 286 | { "compare", test_compare }, | ||
| 287 | { "tonumber", test_tonumber }, | ||
| 288 | { "tointeger", test_tointeger }, | ||
| 289 | { "len", test_len }, | ||
| 290 | { "copy", test_copy }, | ||
| 291 | { "rawxetp", test_rawxetp }, | ||
| 292 | { "subtable", test_subtable }, | ||
| 293 | { "udata", test_udata }, | ||
| 294 | { "uservalue", test_uservalue }, | ||
| 295 | { "globals", test_globals }, | ||
| 296 | { "tolstring", test_tolstring }, | ||
| 297 | { "pushstring", test_pushstring }, | ||
| 298 | { "buffer", test_buffer }, | ||
| 299 | { "exec", test_exec }, | ||
| 300 | { NULL, NULL } | ||
| 301 | }; | ||
| 302 | |||
| 303 | static const luaL_Reg more_funcs[] = { | ||
| 304 | { "getupvalues", test_upvalues }, | ||
| 305 | { "absindex", test_absindex }, | ||
| 306 | { NULL, NULL } | ||
| 307 | }; | ||
| 308 | |||
| 309 | |||
| 310 | int luaopen_testmod (lua_State *L) { | ||
| 311 | int i = 1; | ||
| 312 | luaL_newlib(L, funcs); | ||
| 313 | for (i = 1; i <= NUP; ++i) | ||
| 314 | lua_pushnumber(L, i); | ||
| 315 | luaL_setfuncs(L, more_funcs, NUP); | ||
| 316 | return 1; | ||
| 317 | } | ||
| 318 | |||
