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 /vendor | |
parent | b92fca3b68e551d2583754c80196d524890e5ee4 (diff) | |
parent | 7333333568b13db56136e2354c55556adc7714ed (diff) | |
download | luaossl-b8e3766294b6bf11d70a8a202e633b2569675e77.tar.gz luaossl-b8e3766294b6bf11d70a8a202e633b2569675e77.tar.bz2 luaossl-b8e3766294b6bf11d70a8a202e633b2569675e77.zip |
Merge commit '7333333568b13db56136e2354c55556adc7714ed' as 'vendor/compat53'
Diffstat (limited to 'vendor')
-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 | |||