From 6f8c0f3abda585b3ee1d87e3b8e19c729b52b4a6 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Mon, 14 Jul 2025 17:51:23 -0500 Subject: [PATCH 01/33] Added compat53 support and fixed bugged non-interactive mode --- .github/workflows/build.yml | 5 +- .gitignore | 4 + .gitmodules | 7 + et | 132 ++ .../workflows/bit32-multi-arch-tests.yml | 52 + .../.github/workflows/compat53-tests.yml | 69 + lib/compat53/.gitignore | 10 + lib/compat53/.travis.yml | 47 + lib/compat53/LICENSE | 21 + lib/compat53/README.md | 243 +++ lib/compat53/c-api/compat-5.3.c | 957 ++++++++++ lib/compat53/c-api/compat-5.3.h | 421 +++++ lib/compat53/compat53/file_mt.lua | 71 + lib/compat53/compat53/init.lua | 325 ++++ lib/compat53/compat53/module.lua | 894 ++++++++++ lib/compat53/lbitlib.c | 243 +++ lib/compat53/liolib.c | 776 ++++++++ lib/compat53/lprefix.h | 282 +++ lib/compat53/lstrlib.c | 1584 +++++++++++++++++ lib/compat53/ltablib.c | 450 +++++ lib/compat53/lutf8lib.c | 256 +++ lib/compat53/rockspecs/bit32-5.3.5-1.rockspec | 28 + .../rockspecs/bit32-5.3.5.1-1.rockspec | 28 + lib/compat53/rockspecs/bit32-scm-1.rockspec | 28 + .../rockspecs/compat53-0.1-1.rockspec | 31 + .../rockspecs/compat53-0.11-1.rockspec | 33 + .../rockspecs/compat53-0.12-1.rockspec | 33 + .../rockspecs/compat53-0.13-1.rockspec | 32 + .../rockspecs/compat53-0.14-1.rockspec | 33 + .../rockspecs/compat53-0.14.1-1.rockspec | 33 + .../rockspecs/compat53-0.14.2-1.rockspec | 32 + .../rockspecs/compat53-0.14.3-1.rockspec | 32 + .../rockspecs/compat53-0.14.4-1.rockspec | 32 + .../rockspecs/compat53-0.2-1.rockspec | 32 + .../rockspecs/compat53-0.3-1.rockspec | 32 + .../rockspecs/compat53-0.4-1.rockspec | 32 + .../rockspecs/compat53-0.5-1.rockspec | 32 + .../rockspecs/compat53-0.7-1.rockspec | 32 + .../rockspecs/compat53-0.8-1.rockspec | 32 + .../rockspecs/compat53-scm-1.rockspec | 34 + lib/compat53/tests/test-bit32.lua | 10 + lib/compat53/tests/test.lua | 866 +++++++++ lib/compat53/tests/testmod.c | 370 ++++ premake5.lua | 10 +- src/lush.c | 60 +- test/compat_test.lua | 60 + 46 files changed, 8789 insertions(+), 37 deletions(-) create mode 100644 .gitmodules create mode 100644 et create mode 100644 lib/compat53/.github/workflows/bit32-multi-arch-tests.yml create mode 100644 lib/compat53/.github/workflows/compat53-tests.yml create mode 100644 lib/compat53/.gitignore create mode 100644 lib/compat53/.travis.yml create mode 100644 lib/compat53/LICENSE create mode 100644 lib/compat53/README.md create mode 100644 lib/compat53/c-api/compat-5.3.c create mode 100644 lib/compat53/c-api/compat-5.3.h create mode 100644 lib/compat53/compat53/file_mt.lua create mode 100644 lib/compat53/compat53/init.lua create mode 100644 lib/compat53/compat53/module.lua create mode 100644 lib/compat53/lbitlib.c create mode 100644 lib/compat53/liolib.c create mode 100644 lib/compat53/lprefix.h create mode 100644 lib/compat53/lstrlib.c create mode 100644 lib/compat53/ltablib.c create mode 100644 lib/compat53/lutf8lib.c create mode 100644 lib/compat53/rockspecs/bit32-5.3.5-1.rockspec create mode 100644 lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec create mode 100644 lib/compat53/rockspecs/bit32-scm-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.1-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.11-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.12-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.13-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.14-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.14.1-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.14.2-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.14.3-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.14.4-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.2-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.3-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.4-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.5-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.7-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-0.8-1.rockspec create mode 100644 lib/compat53/rockspecs/compat53-scm-1.rockspec create mode 100755 lib/compat53/tests/test-bit32.lua create mode 100755 lib/compat53/tests/test.lua create mode 100644 lib/compat53/tests/testmod.c create mode 100644 test/compat_test.lua diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a05697e..36cee10 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - + + - name: Initialize submodules + run: git submodule update --init --recursive + - name: Set up dependencies run: | sudo apt-get update diff --git a/.gitignore b/.gitignore index a861fad..6025dec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ Makefile *.make +*.log bin obj .cache +.vscode/ +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8e625f2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "lib/compat53"] + path = lib/compat53 + url = https://github.com/lunarmodules/lua-compat-5.3.git +[submodule "lib/hashmap"] + path = lib/hashmap + url = https://github.com/tidwall/hashmap.c.git + diff --git a/et b/et new file mode 100644 index 0000000..1a9eb09 --- /dev/null +++ b/et @@ -0,0 +1,132 @@ +* 1982f1c (fork/main, fork/HEAD) Smarter tracer: backup +* 5e49f57 Re-init submodules: backup +* bd4cfd2 Arch dis Backup: lisp logs included +* 9bf7f1f Backup: moving from Ubun to Arch +* 2b1f666 (HEAD -> my-feature-branch, tag: v0.3.2, origin/main, origin/HEAD, fork/my-feature-branch, main) v0.3.2 +* 17aadc3 added ability to configure alternate shell +* 9b85e55 (tag: v0.3.1) v0.3.1 +* a1cdb80 add api method to enable/disable inline suggestions +* ce3f1d2 (tag: v0.3.0) v0.3.0 +* 640221c add globbing to command mode +* 6f2e940 added wildcard globbing +* 823a5a4 fixed --version bug +* a87df81 made constant for lush_lua builtin index +* e373f9a added trap builtin +* 3904d58 added command string mode +* 5638f1b Update README.md +* c3afa71 removed history test out of convenience +* 6295ae2 updated help messages +* 6936fee (tag: v0.2.3) v0.2.3 +* a0d5695 added redirect/append for stdout, stderr, or both +* 68ce253 added exit api function +* b29a99b fixed chaining execution attempting to execute operator +* 4028df2 (tag: v0.2.2) v0.2.2 +* 80588be updated history tests +* cd55487 fixed crash in redirect operator +* 4cf1cba (tag: v0.2.1) v0.2.1 +* eda09a9 fixed semicolon chaining functionality +* e61e70d (tag: v0.2.0) v0.2.0 +* 4730d17 fixed crash from incorrect pointer indexing +* e13e23b added append chaining operator +* f7922ea added output redirection with +* e067ca5 added ; chaining operator +* ccf4047 added || chaining operator +* 0539674 Update README.md +* c6e9097 fixed lua api exit status issue +* 69592d5 fixed splitting within quoted string +* 1c41c12 made and operator actually conditional +* 6d0ff4d fixed operator chaining to handle commands terminating with an operator +* e85cb6b implemented background process operator +* b578aef Merge pull request #2 from BanceDev/chaining-operators +|\ +| * 863b097 implemented piping into new chaining method +| * ecfbc1f fixed && chaining for builtins +| * b7718ed added basic && chaining +| * b850121 changed tokenizer to handle all the chaining operators +|/ +* 8997142 Update README.md +* 5914d2e added better clarification to help menu +* c3eb4b2 improved installation instructions +* 6f4a6c4 (tag: v0.1.1) v0.1.1 +* b5857f5 fixed bug in input buffer handling due to misplaced print +* 0dc9a6a Update build.yml checkout v4 +* 58a4647 Update build.yml to artifact v4 +* 0b9c467 fixed exit status issue with non interative mode +* 2c7d28a added non interative mode for running lua scripts +* ee88d00 temporary github action fix until non-interactive mode is implemented +* d41d846 attempt to update build script to accept input into lush shell +* 2fdc7cc prevent lush workflow from getting stuck in tests +* f21f5a8 removed chsh in workflow +* 11b81de Create build.yml +* d25fc21 updated documentation +* 2870751 added e2e testing to cover basic shell functionality +* 9fffa2e updated buffer size for date to account for compiler warning +* 0381ae7 added glob function to lua APi +* daace6e (tag: v0.1.0) v0.1.0 +* 6b3be9c initialized OLDPWD properly +* d5874c5 added HOSTNAME envar +* 3165d96 added OLDPWD environment var and cd - to go to OLDPWD +* 68904ae added date format specifier for prompt +* 32ee824 spelling error in readme demo +* 10910fd updated readme with visuals +* 4361507 fixed off-by-one error with prompt wrapping +* e28bd74 added tab to accept inline autocomplete +* 3742e0b basic current directory suggestions +* 8389686 made it so that lua args properly reset between commands +* e21a4d0 removed demo image to cleanup +* 2c3e681 higher quality image for readme +* 23fb50c added better demo to readme +* 86cadef added handling for when prompt gets longer than terminal width +* 50d69ad added support for multiline prompts +* a0ff5b1 lua api functions for getting terminal width and height +* 5e403a6 added coloring to help command +* 521316d add aliasing to init.lua +* 49fe61d bugfix to inline backspace and delete on multiline buffer +* 0ec71db fixed line wrapping when deleting inline +* 4cdf16f updated gitignore +* d6c203a fixed wrapping bug due to not using updated prompt_length +* 73d9858 added stripping of escape sequences from prompt size to allow for coloring +* 0f4b5ff Merge pull request #1 from Makaze/patch-1 +|\ +| * b6e478c docs: update path +* | 49de8d3 added support for init.lua for configuring shell +|/ +* 6a2689d added getenv and putenv to Lua API +* bfa2768 added lua api functions for indexing history +* ea0eb66 added support for cli args for lua scripts +* c638ce8 added --version flag +* 0edfb38 fixed error in install.sh instructions +* 29c052c fixed bug with cursor alignment when adding text within the buffer +* 29f1b14 added API guide to readme +* 305b17a Update README.md +* ff06726 better readme +* 0b263c3 Create FUNDING.yml +* e6700fc Update README.md +* 9c301c1 fixed crash when no history exists yet and polls for history +* d864cde fixed inability to move cursor between lines +* d63e0e1 cleaned up syntax +* b020cf5 Update CONTRIBUTING.md +* 41f8b9a bugfix on arrowkey movement after browsing history +* 58cb10f updated readme +* 99b8bb5 upadted contribution guidelines +* 64c61c4 Create CONTRIBUTING.md +* bbcf154 fixed bugs with multi line history elements +* 65d523b added api functions for isFile, isDirectory, isReadable, and isWriteable +* e828e25 command history scrolling implemented +* 995e8da history saving implemented +* eea1194 added exists function to lua api +* 7dea3ee added missing lua registrations +* 8936264 updated the example.lua to use new cd command +* 86b8b0e added cd to lua api +* 72f5958 fixed a bug where multiline commands printed wrong +* 5568fba removed need for lush command to execute lua files +* 3577398 added debug mode for scripting +* d5d3f94 update lua api to table and added getcwd to api +* 4fee5ce fixed crash in cd when no path found +* 4375a8e searches .lush/scripts for lua files +* ebdd4e8 added basic lua scripting +* 8ddcd6b added arrow key movement +* 112a831 updated help and fixed SIGINT +* 5c2b255 lunar shell logo +* 58966d4 changed prompt +* f6d7b19 initial commit diff --git a/lib/compat53/.github/workflows/bit32-multi-arch-tests.yml b/lib/compat53/.github/workflows/bit32-multi-arch-tests.yml new file mode 100644 index 0000000..aff29db --- /dev/null +++ b/lib/compat53/.github/workflows/bit32-multi-arch-tests.yml @@ -0,0 +1,52 @@ +name: bit32-multi-arch-tests +on: + push: + branches: ["master"] + pull_request: +jobs: + bit32-test: + runs-on: ubuntu-latest + name: bit32 tests on ${{ matrix.luaVersion }} ${{ matrix.arch }} + strategy: + fail-fast: false + matrix: + luaVersion: ["5.1.5", "5.4.1"] + luaRocksVersion: ["3.3.1"] + arch: ["armv7", "aarch64"] + steps: + - uses: actions/checkout@v2 + - uses: actions/cache@v2 + id: lua-cache + with: + path: .install/${{ matrix.arch }}/lua-${{ matrix.luaVersion }} + key: lua-on-linux-${{ matrix.arch }}-${{ matrix.luaVersion }} + - uses: uraimo/run-on-arch-action@v2 + with: + arch: ${{ matrix.arch }} + distro: ubuntu_rolling + githubToken: ${{ github.token }} + setup: | + mkdir -p ".install/${{ matrix.arch }}" + install: | + apt-get update -q -y + apt-get install -q -y curl unzip build-essential libreadline-dev libncurses-dev clang + rm -rf /var/lib/apt/lists/* + run: | + v() { + echo -n -e "\033[36m" >&2 + echo -n "# $*" >&2 + echo -e "\033[0m" >&2 + "$@" + } + export CC=clang + if [ "${{ steps.lua-cache.outputs.cache-hit }}" != true ]; then + (set -o pipefail; cd ".install/${{ matrix.arch }}" && v curl --fail --silent --location "http://www.lua.org/ftp/lua-${{ matrix.luaVersion }}.tar.gz" | tar xzpf -) + (cd ".install/${{ matrix.arch }}/lua-${{ matrix.luaVersion }}" && v make linux) + fi + (cd ".install/${{ matrix.arch }}/lua-${{ matrix.luaVersion }}" && v make install) + (set -o pipefail; cd .install && v curl --fail --silent --location "http://luarocks.org/releases/luarocks-${{ matrix.luaRocksVersion }}.tar.gz" | tar xzpf -) + (cd ".install/luarocks-${{ matrix.luaRocksVersion }}" && v ./configure && v make bootstrap) + eval "$(luarocks path)" + v luarocks make rockspecs/bit32-scm-1.rockspec + v lua tests/test-bit32.lua + diff --git a/lib/compat53/.github/workflows/compat53-tests.yml b/lib/compat53/.github/workflows/compat53-tests.yml new file mode 100644 index 0000000..623837f --- /dev/null +++ b/lib/compat53/.github/workflows/compat53-tests.yml @@ -0,0 +1,69 @@ +name: compat53-tests +on: + push: + branches: ["master"] + pull_request: +jobs: + compat53-test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - luaVersion: "lua=5.1" + compiler: gcc + external: false + - luaVersion: "lua=5.1" + compiler: gcc + external: true + - luaVersion: "lua=5.1" + compiler: g++ + external: true + - luaVersion: "lua=5.1" + compiler: clang + external: false + - luaVersion: "luajit=@v2.1 --compat=none" + compiler: gcc + external: false + - luaVersion: "luajit=@v2.1 --compat=none" + compiler: gcc + external: true + - luaVersion: "luajit=@v2.1 --compat=all" + compiler: gcc + external: false + - luaVersion: "luajit=@v2.1 --compat=all" + compiler: gcc + external: true + - luaVersion: "lua=5.2" + compiler: gcc + external: false + - luaVersion: "lua=5.2" + compiler: gcc + external: true + - luaVersion: "lua=5.2" + compiler: g++ + external: true + steps: + - uses: actions/checkout@v2 + - name: install Lua + run: | + sudo apt install libreadline-dev + pip3 install --user hererocks + ~/.local/bin/hererocks old --${{ matrix.luaVersion }} + test -e old/bin/lua || (cd old/bin && ln -s luajit* lua) + ~/.local/bin/hererocks new --lua=5.3 + - name: compile C modules + run: | + export CC=${{ matrix.compiler }} CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC" + export DEF="" SRC="" + if [ "${{ matrix.external }}" = true ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi + ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC} + ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC} + ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c liolib.c ${SRC} + - name: run test scripts + run: | + (cd old && bin/lua ../tests/test.lua) > old.txt + (cd new && bin/lua ../tests/test.lua) > new.txt + - name: compare script output + run: diff old.txt new.txt || true + diff --git a/lib/compat53/.gitignore b/lib/compat53/.gitignore new file mode 100644 index 0000000..67c1b76 --- /dev/null +++ b/lib/compat53/.gitignore @@ -0,0 +1,10 @@ +# generated files +*.so +*.dll +*.o +*.obj +HISTO + +# vim temporaries +.*.swp + diff --git a/lib/compat53/.travis.yml b/lib/compat53/.travis.yml new file mode 100644 index 0000000..44ae3a0 --- /dev/null +++ b/lib/compat53/.travis.yml @@ -0,0 +1,47 @@ +language: c +compiler: gcc + +sudo: false + +env: + - LUA="lua=5.1" + - LUA="lua=5.1" EXTERNAL=true + - LUA="lua=5.1" COMPILER="g++" + - LUA="lua=5.1" EXTERNAL=true COMPILER="g++" + - LUA="luajit=@v2.1 --compat=none" + - LUA="luajit=@v2.1 --compat=none" EXTERNAL=true + - LUA="luajit=@v2.1 --compat=all" + - LUA="luajit=@v2.1 --compat=all" EXTERNAL=true + - LUA="lua=5.2" + - LUA="lua=5.2" EXTERNAL=true + - LUA="lua=5.2" COMPILER="g++" + - LUA="lua=5.2" EXTERNAL=true COMPILER="g++" + +branches: + only: + - master + +git: + depth: 3 + +notifications: + email: false + +before_install: + - pip install --user hererocks + - hererocks old --$LUA + - test -e old/bin/lua || (cd old/bin && ln -s luajit* lua) + - hererocks new --lua=5.3 + +install: + - export CC="${COMPILER:-gcc}" DEF="" SRC="" CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC" + - if [ "x${EXTERNAL:-}" = xtrue ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi + - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC} + - ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC} + - gcc ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c liolib.c ${SRC} + +script: + - (cd old && bin/lua ../tests/test.lua) > old.txt + - (cd new && bin/lua ../tests/test.lua) > new.txt + - diff old.txt new.txt || true + diff --git a/lib/compat53/LICENSE b/lib/compat53/LICENSE new file mode 100644 index 0000000..193ed12 --- /dev/null +++ b/lib/compat53/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 1994-2020 Lua.org, PUC-Rio. +Copyright (C) 2013-2023 The Lua-Compat-5.3 authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/compat53/README.md b/lib/compat53/README.md new file mode 100644 index 0000000..3ee6acf --- /dev/null +++ b/lib/compat53/README.md @@ -0,0 +1,243 @@ +[![Compat53 Status](https://github.com/lunarmodules/lua-compat-5.3/workflows/compat53-tests/badge.svg)](https://github.com/lunarmodules/lua-compat-5.3/actions?workflow=compat53-tests) +[![Bit32 Status](https://github.com/lunarmodules/lua-compat-5.3/workflows/bit32-multi-arch-tests/badge.svg)](https://github.com/lunarmodules/lua-compat-5.3/actions?workflow=bit32-multi-arch-tests) + +# lua-compat-5.3 + +Lua-5.3-style APIs for Lua 5.2 and 5.1. + +## What is it + +This is a small module that aims to make it easier to write code +in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua +5.3. This does *not* make Lua 5.2 (or even Lua 5.1) entirely +compatible with Lua 5.3, but it brings the API closer to that of Lua +5.3. + +It includes: + +* _For writing Lua_: The Lua module `compat53`, which can be require'd + from Lua scripts and run in Lua 5.1, 5.2, and 5.3, including a + backport of the `utf8` module, the 5.3 `table` module, and the + string packing functions straight from the Lua 5.3 sources. +* _For writing C_: A C header and file which can be linked to your + Lua module written in C, providing some functions from the C API + of Lua 5.3 that do not exist in Lua 5.2 or 5.1, making it easier to + write C code that compiles with all three versions of liblua. + +## How to use it + +### Lua module + +```lua +require("compat53") +``` + +`compat53` makes changes to your global environment and does not return +a meaningful return value, so the usual idiom of storing the return of +`require` in a local variable makes no sense. + +When run under Lua 5.3+, this module does nothing. + +When run under Lua 5.2 or 5.1, it replaces some of your standard +functions and adds new ones to bring your environment closer to that +of Lua 5.3. It also tries to load the backported `utf8`, `table`, and +string packing modules automatically. If unsuccessful, pure Lua +versions of the new `table` functions are used as a fallback, and +[Roberto's struct library][1] is tried for string packing. + +#### Lua submodules + +```lua +local _ENV = require("compat53.module") +if setfenv then setfenv(1, _ENV) end +``` + +The `compat53.module` module does not modify the global environment, +and so it is safe to use in modules without affecting other Lua files. +It is supposed to be set as the current environment (see above), i.e. +cherry picking individual functions from this module is expressly +*not* supported!). Not all features are available when using this +module (e.g. yieldable (x)pcall support, string/file methods, etc.), +so it is recommended to use plain `require("compat53")` whenever +possible. + +### C code + +There are two ways of adding the C API compatibility functions/macros to +your project: +* If `COMPAT53_PREFIX` is *not* `#define`d, `compat-5.3.h` `#include`s + `compat-5.3.c`, and all functions are made `static`. You don't have to + compile/link/add `compat-5.3.c` yourself. This is useful for one-file + projects. +* If `COMPAT53_PREFIX` is `#define`d, all exported functions are renamed + behind the scenes using this prefix to avoid linker conflicts with other + code using this package. This doesn't change the way you call the + compatibility functions in your code. You have to compile and link + `compat-5.3.c` to your project yourself. You can change the way the + functions are exported using the `COMPAT53_API` macro (e.g. if you need + some `__declspec` magic). While it is technically possible to use + the "lua" prefix (and it looks better in the debugger), this is + discouraged because LuaJIT has started to implement its own Lua 5.2+ + C API functions, and with the "lua" prefix you'd violate the + one-definition rule with recent LuaJIT versions. + +## What's implemented + +### Lua + +* the `utf8` module backported from the Lua 5.3 sources +* `string.pack`, `string.packsize`, and `string.unpack` from the Lua + 5.3 sources or from the `struct` module. (`struct` is not 100% + compatible to Lua 5.3's string packing!) (See [here][4]) +* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`, + and `math.ult` (see [here][5]) +* `assert` accepts non-string error messages +* `ipairs` respects `__index` metamethod +* `table.move` +* `table` library respects metamethods + +For Lua 5.1 additionally: +* `load` and `loadfile` accept `mode` and `env` parameters +* `table.pack` and `table.unpack` +* string patterns may contain embedded zeros (but see [here][6]) +* `string.rep` accepts `sep` argument +* `string.format` calls `tostring` on arguments for `%s` +* `math.log` accepts base argument +* `xpcall` takes additional arguments +* `pcall` and `xpcall` can execute functions that yield (see + [here][22] for a possible problem with `coroutine.running`) +* `pairs` respects `__pairs` metamethod (see [here][7]) +* `rawlen` (but `#` still doesn't respect `__len` for tables) +* `package.searchers` as alias for `package.loaders` +* `package.searchpath` (see [here][8]) +* `coroutine` functions dealing with the main coroutine (see + [here][22] for a possible problem with `coroutine.running`) +* `coroutine.create` accepts functions written in C +* return code of `os.execute` (see [here][9]) +* `io.write` and `file:write` return file handle +* `io.lines` and `file:lines` accept format arguments (like `io.read`) + (see [here][10] and [here][11]) +* `file:close` returns three results when a process is opened + with `io.popen` +* `debug.setmetatable` returns object +* `debug.getuservalue` (see [here][12]) +* `debug.setuservalue` (see [here][13]) + +### C + +* `lua_KContext` (see [here][14]) +* `lua_KFunction` (see [here][14]) +* `lua_dump` (extra `strip` parameter, ignored, see [here][15]) +* `lua_getextraspace` (limited compatibilitiy, see [here][24]) +* `lua_getfield` (return value) +* `lua_geti` and `lua_seti` +* `lua_getglobal` (return value) +* `lua_getmetafield` (return value) +* `lua_gettable` (return value) +* `lua_getuservalue` (limited compatibility, see [here][16]) +* `lua_setuservalue` (limited compatibility, see [here][17]) +* `lua_isinteger` +* `lua_numbertointeger` +* `lua_callk` and `lua_pcallk` (limited compatibility, see [here][14]) +* `lua_resume` +* `lua_rawget` and `lua_rawgeti` (return values) +* `lua_rawgetp` and `lua_rawsetp` +* `luaL_requiref` (now checks `package.loaded` first) +* `lua_rotate` +* `lua_stringtonumber` (see [here][18]) + +For Lua 5.1 additionally: +* `LUA_OK` +* `LUA_ERRGCMM` +* `LUA_OP*` macros for `lua_arith` and `lua_compare` +* `LUA_FILEHANDLE` +* `lua_Unsigned` +* `luaL_Stream` (limited compatibility, see [here][19]) +* `lua_absindex` +* `lua_arith` (see [here][20]) +* `lua_compare` +* `lua_len`, `lua_rawlen`, and `luaL_len` +* `lua_load` (mode argument) +* `lua_pushstring`, `lua_pushlstring` (return value) +* `lua_copy` +* `lua_pushglobaltable` +* `luaL_testudata` +* `luaL_setfuncs`, `luaL_newlibtable`, and `luaL_newlib` +* `luaL_setmetatable` +* `luaL_getsubtable` +* `luaL_traceback` +* `luaL_execresult` +* `luaL_fileresult` +* `luaL_loadbufferx` +* `luaL_loadfilex` +* `luaL_checkversion` (with empty body, only to avoid compile errors, + see [here][21]) +* `luaL_tolstring` +* `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize` + (see [here][22]) +* `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`, + `luaL_checkunsigned`, `luaL_optunsigned`, if + `LUA_COMPAT_APIINTCASTS` is defined. + +## What's not implemented + +* bit operators +* integer division operator +* utf8 escape sequences +* 64 bit integers +* `coroutine.isyieldable` +* Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See + [`lua-compat-5.2`][2] for a detailed list. +* the following C API functions/macros: + * `lua_isyieldable` + * `lua_arith` (new operators missing) + * `lua_push(v)fstring` (new formats missing) + * `lua_upvalueid` (5.1) + * `lua_upvaluejoin` (5.1) + * `lua_version` (5.1) + * `lua_yieldk` (5.1) + +## See also + +* For Lua-5.2-style APIs under Lua 5.1, see [lua-compat-5.2][2], + which also is the basis for most of the code in this project. +* For Lua-5.1-style APIs under Lua 5.0, see [Compat-5.1][3] + +## Credits + +This package contains code written by: + +* [The Lua Team](http://www.lua.org) +* Philipp Janda ([@siffiejoe](http://github.com/siffiejoe)) +* Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola)) +* Hisham Muhammad ([@hishamhm](http://github.com/hishamhm)) +* Renato Maia ([@renatomaia](http://github.com/renatomaia)) +* [@ThePhD](http://github.com/ThePhD) +* [@Daurnimator](http://github.com/Daurnimator) + + + [1]: http://www.inf.puc-rio.br/~roberto/struct/ + [2]: http://github.com/lunarmodules/lua-compat-5.2/ + [3]: http://lunarmodules.org/compat/ + [4]: https://github.com/lunarmodules/lua-compat-5.3/wiki/string_packing + [5]: https://github.com/lunarmodules/lua-compat-5.3/wiki/math.type + [6]: https://github.com/lunarmodules/lua-compat-5.3/wiki/pattern_matching + [7]: https://github.com/lunarmodules/lua-compat-5.3/wiki/pairs + [8]: https://github.com/lunarmodules/lua-compat-5.3/wiki/package.searchpath + [9]: https://github.com/lunarmodules/lua-compat-5.3/wiki/os.execute + [10]: https://github.com/lunarmodules/lua-compat-5.3/wiki/io.lines + [11]: https://github.com/lunarmodules/lua-compat-5.3/wiki/file.lines + [12]: https://github.com/lunarmodules/lua-compat-5.3/wiki/debug.getuservalue + [13]: https://github.com/lunarmodules/lua-compat-5.3/wiki/debug.setuservalue + [14]: https://github.com/lunarmodules/lua-compat-5.3/wiki/yieldable_c_functions + [15]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_dump + [16]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_getuservalue + [17]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_setuservalue + [18]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_stringtonumber + [19]: https://github.com/lunarmodules/lua-compat-5.3/wiki/luaL_Stream + [20]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_arith + [21]: https://github.com/lunarmodules/lua-compat-5.3/wiki/luaL_checkversion + [22]: https://github.com/lunarmodules/lua-compat-5.3/wiki/luaL_Buffer + [23]: https://github.com/lunarmodules/lua-compat-5.3/wiki/coroutine.running + [24]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_getextraspace + diff --git a/lib/compat53/c-api/compat-5.3.c b/lib/compat53/c-api/compat-5.3.c new file mode 100644 index 0000000..1901a82 --- /dev/null +++ b/lib/compat53/c-api/compat-5.3.c @@ -0,0 +1,957 @@ +#include +#include +#include +#include +#include +#include +#include "compat-5.3.h" + +/* don't compile it again if it already is included via compat53.h */ +#ifndef COMPAT53_C_ +#define COMPAT53_C_ + + + +/* definitions for Lua 5.1 only */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 + +#ifndef COMPAT53_FOPEN_NO_LOCK +# if defined(_MSC_VER) +# define COMPAT53_FOPEN_NO_LOCK 1 +# else /* otherwise */ +# define COMPAT53_FOPEN_NO_LOCK 0 +# endif /* VC++ only so far */ +#endif /* No-lock fopen_s usage if possible */ + +#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK +# include +#endif /* VC++ _fsopen for share-allowed file read */ + +#ifndef COMPAT53_HAVE_STRERROR_R +# if (!defined(_WIN32)) && \ + ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || \ + defined(__APPLE__)) +# define COMPAT53_HAVE_STRERROR_R 1 +# else /* none of the defines matched: define to 0 */ +# define COMPAT53_HAVE_STRERROR_R 0 +# endif /* have strerror_r of some form */ +#endif /* strerror_r */ + +#ifndef COMPAT53_HAVE_STRERROR_S +# if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \ + defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__) +# define COMPAT53_HAVE_STRERROR_S 1 +# else /* not VC++ or C11 */ +# define COMPAT53_HAVE_STRERROR_S 0 +# endif /* strerror_s from VC++ or C11 */ +#endif /* strerror_s */ + +#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE +# define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 +#endif /* Lua File Buffer Size */ + + +static char* compat53_strerror (int en, char* buff, size_t sz) { +#if COMPAT53_HAVE_STRERROR_R + /* use strerror_r here, because it's available on these specific platforms */ + if (sz > 0) { + buff[0] = '\0'; + /* we don't care whether the GNU version or the XSI version is used: */ + if (strerror_r(en, buff, sz)) { + /* Yes, we really DO want to ignore the return value! + * GCC makes that extra hard, not even a (void) cast will do. */ + } + if (buff[0] == '\0') { + /* Buffer is unchanged, so we probably have called GNU strerror_r which + * returned a static constant string. Chances are that strerror will + * return the same static constant string and therefore be thread-safe. */ + return strerror(en); + } + } + return buff; /* sz is 0 *or* strerror_r wrote into the buffer */ +#elif COMPAT53_HAVE_STRERROR_S + /* for MSVC and other C11 implementations, use strerror_s since it's + * provided by default by the libraries */ + strerror_s(buff, sz, en); + return buff; +#else + /* fallback, but strerror is not guaranteed to be threadsafe due to modifying + * errno itself and some impls not locking a static buffer for it ... but most + * known systems have threadsafe errno: this might only change if the locale + * is changed out from under someone while this function is being called */ + (void)buff; + (void)sz; + return strerror(en); +#endif +} + + +COMPAT53_API int lua_absindex (lua_State *L, int i) { + if (i < 0 && i > LUA_REGISTRYINDEX) + i += lua_gettop(L) + 1; + return i; +} + + +static void compat53_call_lua (lua_State *L, char const code[], size_t len, + int nargs, int nret) { + lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); + if (lua_type(L, -1) != LUA_TFUNCTION) { + lua_pop(L, 1); + if (luaL_loadbuffer(L, code, len, "=none")) + lua_error(L); + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); + } + lua_insert(L, -nargs-1); + lua_call(L, nargs, nret); +} + + +static const char compat53_arith_code[] = + "local op,a,b=...\n" + "if op==0 then return a+b\n" + "elseif op==1 then return a-b\n" + "elseif op==2 then return a*b\n" + "elseif op==3 then return a/b\n" + "elseif op==4 then return a%b\n" + "elseif op==5 then return a^b\n" + "elseif op==6 then return -a\n" + "end\n"; + +COMPAT53_API void lua_arith (lua_State *L, int op) { + if (op < LUA_OPADD || op > LUA_OPUNM) + luaL_error(L, "invalid 'op' argument for lua_arith"); + luaL_checkstack(L, 5, "not enough stack slots"); + if (op == LUA_OPUNM) + lua_pushvalue(L, -1); + lua_pushnumber(L, op); + lua_insert(L, -3); + compat53_call_lua(L, compat53_arith_code, + sizeof(compat53_arith_code)-1, 3, 1); +} + + +static const char compat53_compare_code[] = + "local a,b=...\n" + "return a<=b\n"; + +COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op) { + int result = 0; + switch (op) { + case LUA_OPEQ: + return lua_equal(L, idx1, idx2); + case LUA_OPLT: + return lua_lessthan(L, idx1, idx2); + case LUA_OPLE: + luaL_checkstack(L, 5, "not enough stack slots"); + idx1 = lua_absindex(L, idx1); + idx2 = lua_absindex(L, idx2); + lua_pushvalue(L, idx1); + lua_pushvalue(L, idx2); + compat53_call_lua(L, compat53_compare_code, + sizeof(compat53_compare_code)-1, 2, 1); + result = lua_toboolean(L, -1); + lua_pop(L, 1); + return result; + default: + luaL_error(L, "invalid 'op' argument for lua_compare"); + } + return 0; +} + + +COMPAT53_API void lua_copy (lua_State *L, int from, int to) { + int abs_to = lua_absindex(L, to); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushvalue(L, from); + lua_replace(L, abs_to); +} + + +COMPAT53_API void lua_len (lua_State *L, int i) { + switch (lua_type(L, i)) { + case LUA_TSTRING: + lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); + break; + case LUA_TTABLE: + if (!luaL_callmeta(L, i, "__len")) + lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); + break; + case LUA_TUSERDATA: + if (luaL_callmeta(L, i, "__len")) + break; + /* FALLTHROUGH */ + default: + luaL_error(L, "attempt to get length of a %s value", + lua_typename(L, lua_type(L, i))); + } +} + + +COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p) { + int abs_i = lua_absindex(L, i); + lua_pushlightuserdata(L, (void*)p); + lua_rawget(L, abs_i); + return lua_type(L, -1); +} + +COMPAT53_API void lua_rawsetp (lua_State *L, int i, const void *p) { + int abs_i = lua_absindex(L, i); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, (void*)p); + lua_insert(L, -2); + lua_rawset(L, abs_i); +} + + +COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) { + lua_Number n = lua_tonumber(L, i); + if (isnum != NULL) { + *isnum = (n != 0 || lua_isnumber(L, i)); + } + return n; +} + + +COMPAT53_API void luaL_checkversion (lua_State *L) { + (void)L; +} + + +COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg) { + if (!lua_checkstack(L, sp+LUA_MINSTACK)) { + if (msg != NULL) + luaL_error(L, "stack overflow (%s)", msg); + else { + lua_pushliteral(L, "stack overflow"); + lua_error(L); + } + } +} + + +COMPAT53_API int luaL_getsubtable (lua_State *L, int i, const char *name) { + int abs_i = lua_absindex(L, i); + luaL_checkstack(L, 3, "not enough stack slots"); + lua_pushstring(L, name); + lua_gettable(L, abs_i); + if (lua_istable(L, -1)) + return 1; + lua_pop(L, 1); + lua_newtable(L); + lua_pushstring(L, name); + lua_pushvalue(L, -2); + lua_settable(L, abs_i); + return 0; +} + + +COMPAT53_API lua_Integer luaL_len (lua_State *L, int i) { + lua_Integer res = 0; + int isnum = 0; + luaL_checkstack(L, 1, "not enough stack slots"); + lua_len(L, i); + res = lua_tointegerx(L, -1, &isnum); + lua_pop(L, 1); + if (!isnum) + luaL_error(L, "object length is not an integer"); + return res; +} + + +COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup+1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup + 1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ + } + lua_pop(L, nup); /* remove upvalues */ +} + + +COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname) { + luaL_checkstack(L, 1, "not enough stack slots"); + luaL_getmetatable(L, tname); + lua_setmetatable(L, -2); +} + + +COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname) { + void *p = lua_touserdata(L, i); + luaL_checkstack(L, 2, "not enough stack slots"); + if (p == NULL || !lua_getmetatable(L, i)) + return NULL; + else { + int res = 0; + luaL_getmetatable(L, tname); + res = lua_rawequal(L, -1, -2); + lua_pop(L, 2); + if (!res) + p = NULL; + } + return p; +} + + +static int compat53_countlevels (lua_State *L) { + lua_Debug ar; + int li = 1, le = 1; + /* find an upper bound */ + while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } + /* do a binary search */ + while (li < le) { + int m = (li + le)/2; + if (lua_getstack(L, m, &ar)) li = m + 1; + else le = m; + } + return le - 1; +} + +static int compat53_findfield (lua_State *L, int objidx, int level) { + if (level == 0 || !lua_istable(L, -1)) + return 0; /* not found */ + lua_pushnil(L); /* start 'next' loop */ + while (lua_next(L, -2)) { /* for each pair in table */ + if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ + if (lua_rawequal(L, objidx, -1)) { /* found object? */ + lua_pop(L, 1); /* remove value (but keep name) */ + return 1; + } + else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ + lua_remove(L, -2); /* remove table (but keep name) */ + lua_pushliteral(L, "."); + lua_insert(L, -2); /* place '.' between the two names */ + lua_concat(L, 3); + return 1; + } + } + lua_pop(L, 1); /* remove value */ + } + return 0; /* not found */ +} + +static int compat53_pushglobalfuncname (lua_State *L, lua_Debug *ar) { + int top = lua_gettop(L); + lua_getinfo(L, "f", ar); /* push function */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + if (compat53_findfield(L, top + 1, 2)) { + lua_copy(L, -1, top + 1); /* move name to proper place */ + lua_pop(L, 2); /* remove pushed values */ + return 1; + } + else { + lua_settop(L, top); /* remove function and global table */ + return 0; + } +} + +static void compat53_pushfuncname (lua_State *L, lua_Debug *ar) { + if (*ar->namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, "function " LUA_QS, ar->name); + else if (*ar->what == 'm') /* main? */ + lua_pushliteral(L, "main chunk"); + else if (*ar->what == 'C') { + if (compat53_pushglobalfuncname(L, ar)) { + lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else + lua_pushliteral(L, "?"); + } + else + lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); +} + +#define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ +#define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ + +COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, + const char *msg, int level) { + lua_Debug ar; + int top = lua_gettop(L); + int numlevels = compat53_countlevels(L1); + int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; + if (msg) lua_pushfstring(L, "%s\n", msg); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, &ar)) { + if (level == mark) { /* too many levels? */ + lua_pushliteral(L, "\n\t..."); /* add a '...' */ + level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ + } + else { + lua_getinfo(L1, "Slnt", &ar); + lua_pushfstring(L, "\n\t%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + lua_pushliteral(L, " in "); + compat53_pushfuncname(L, &ar); + lua_concat(L, lua_gettop(L) - top); + } + } + lua_concat(L, lua_gettop(L) - top); +} + + +COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { + const char *serr = NULL; + int en = errno; /* calls to Lua API may change this value */ + char buf[512] = { 0 }; + if (stat) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + serr = compat53_strerror(en, buf, sizeof(buf)); + if (fname) + lua_pushfstring(L, "%s: %s", fname, serr); + else + lua_pushstring(L, serr); + lua_pushnumber(L, (lua_Number)en); + return 3; + } +} + + +static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) { + if (mode && strchr(mode, modename[0]) == NULL) { + lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); + return err; + } + return LUA_OK; +} + + +typedef struct { + lua_Reader reader; + void *ud; + int has_peeked_data; + const char *peeked_data; + size_t peeked_data_size; +} compat53_reader_data; + + +static const char *compat53_reader (lua_State *L, void *ud, size_t *size) { + compat53_reader_data *data = (compat53_reader_data *)ud; + if (data->has_peeked_data) { + data->has_peeked_data = 0; + *size = data->peeked_data_size; + return data->peeked_data; + } else + return data->reader(L, data->ud, size); +} + + +COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) { + int status = LUA_OK; + compat53_reader_data compat53_data = { 0, NULL, 1, 0, 0 }; + compat53_data.reader = reader; + compat53_data.ud = data; + compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size)); + if (compat53_data.peeked_data && compat53_data.peeked_data_size && + compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ + status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); + else + status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); + if (status != LUA_OK) + return status; + /* we need to call the original 5.1 version of lua_load! */ +#undef lua_load + return lua_load(L, compat53_reader, &compat53_data, source); +#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) +} + + +typedef struct { + int n; /* number of pre-read characters */ + FILE *f; /* file being read */ + char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */ +} compat53_LoadF; + + +static const char *compat53_getF (lua_State *L, void *ud, size_t *size) { + compat53_LoadF *lf = (compat53_LoadF *)ud; + (void)L; /* not used */ + if (lf->n > 0) { /* are there pre-read characters to be read? */ + *size = lf->n; /* return them (chars already in buffer) */ + lf->n = 0; /* no more pre-read characters */ + } + else { /* read a block from file */ + /* 'fread' can return > 0 *and* set the EOF flag. If next call to + 'compat53_getF' called 'fread', it might still wait for user input. + The next check avoids this problem. */ + if (feof(lf->f)) return NULL; + *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ + } + return lf->buff; +} + + +static int compat53_errfile (lua_State *L, const char *what, int fnameindex) { + char buf[512] = {0}; + const char *serr = compat53_strerror(errno, buf, sizeof(buf)); + const char *filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; +} + + +static int compat53_skipBOM (compat53_LoadF *lf) { + const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ + int c; + lf->n = 0; + do { + c = getc(lf->f); + if (c == EOF || c != *(const unsigned char *)p++) return c; + lf->buff[lf->n++] = (char)c; /* to be read by the parser */ + } while (*p != '\0'); + lf->n = 0; /* prefix matched; discard it */ + return getc(lf->f); /* return next character */ +} + + +/* +** reads the first character of file 'f' and skips an optional BOM mark +** in its beginning plus its first line if it starts with '#'. Returns +** true if it skipped the first line. In any case, '*cp' has the +** first "valid" character of the file (after the optional BOM and +** a first-line comment). +*/ +static int compat53_skipcomment (compat53_LoadF *lf, int *cp) { + int c = *cp = compat53_skipBOM(lf); + if (c == '#') { /* first line is a comment (Unix exec. file)? */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n'); + *cp = getc(lf->f); /* skip end-of-line, if present */ + return 1; /* there was a comment */ + } + else return 0; /* no comment */ +} + + +COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { + compat53_LoadF lf; + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + if (filename == NULL) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); +#if defined(_MSC_VER) + /* This code is here to stop a deprecation error that stops builds + * if a certain macro is defined. While normally not caring would + * be best, some header-only libraries and builds can't afford to + * dictate this to the user. A quick check shows that fopen_s this + * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET, + * possibly even before that so we don't need to do any version + * number checks, since this has been there since forever. */ + + /* TO USER: if you want the behavior of typical fopen_s/fopen, + * which does lock the file on VC++, define the macro used below to 0 */ +#if COMPAT53_FOPEN_NO_LOCK + lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */ + if (lf.f == NULL) + return compat53_errfile(L, "open", fnameindex); +#else /* use default locking version */ + if (fopen_s(&lf.f, filename, "r") != 0) + return compat53_errfile(L, "open", fnameindex); +#endif /* Locking vs. No-locking fopen variants */ +#else + lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */ + if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); +#endif + } + if (compat53_skipcomment(&lf, &c)) /* read initial portion */ + lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ + if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ +#if defined(_MSC_VER) + if (freopen_s(&lf.f, filename, "rb", lf.f) != 0) + return compat53_errfile(L, "reopen", fnameindex); +#else + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex); +#endif + compat53_skipcomment(&lf, &c); /* re-read initial portion */ + } + if (c != EOF) + lf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */ + status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode); + readstatus = ferror(lf.f); + if (filename) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus) { + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ + return compat53_errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; +} + + +COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) { + int status = LUA_OK; + if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { + status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); + } + else { + status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); + } + if (status != LUA_OK) + return status; + return luaL_loadbuffer(L, buff, sz, name); +} + + +#if !defined(l_inspectstat) && \ + (defined(unix) || defined(__unix) || defined(__unix__) || \ + defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ + (defined(__APPLE__) && defined(__MACH__))) +/* some form of unix; check feature macros in unistd.h for details */ +# include +/* check posix version; the relevant include files and macros probably + * were available before 2001, but I'm not sure */ +# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L +# include +# define l_inspectstat(stat,what) \ + if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ + else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } +# endif +#endif + +/* provide default (no-op) version */ +#if !defined(l_inspectstat) +# define l_inspectstat(stat,what) ((void)0) +#endif + + +COMPAT53_API int luaL_execresult (lua_State *L, int stat) { + const char *what = "exit"; + if (stat == -1) + return luaL_fileresult(L, 0, NULL); + else { + l_inspectstat(stat, what); + if (*what == 'e' && stat == 0) + lua_pushboolean(L, 1); + else + lua_pushnil(L); + lua_pushstring(L, what); + lua_pushinteger(L, stat); + return 3; + } +} + + +COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) { + /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ + B->b.p = NULL; + B->b.L = NULL; + B->b.lvl = 0; + /* reuse the buffer from the 5.1-style luaL_Buffer though! */ + B->ptr = B->b.buffer; + B->capacity = LUAL_BUFFERSIZE; + B->nelems = 0; + B->L2 = L; +} + + +COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s) { + if (B->capacity - B->nelems < s) { /* needs to grow */ + char* newptr = NULL; + size_t newcap = B->capacity * 2; + if (newcap - B->nelems < s) + newcap = B->nelems + s; + if (newcap < B->capacity) /* overflow */ + luaL_error(B->L2, "buffer too large"); + newptr = (char*)lua_newuserdata(B->L2, newcap); + memcpy(newptr, B->ptr, B->nelems); + if (B->ptr != B->b.buffer) + lua_replace(B->L2, -2); /* remove old buffer */ + B->ptr = newptr; + B->capacity = newcap; + } + return B->ptr+B->nelems; +} + + +COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l) { + memcpy(luaL_prepbuffsize(B, l), s, l); + luaL_addsize(B, l); +} + + +COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B) { + size_t len = 0; + const char *s = lua_tolstring(B->L2, -1, &len); + if (!s) + luaL_error(B->L2, "cannot convert value to string"); + if (B->ptr != B->b.buffer) + lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ + luaL_addlstring(B, s, len); + lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); +} + + +void luaL_pushresult (luaL_Buffer_53 *B) { + lua_pushlstring(B->L2, B->ptr, B->nelems); + if (B->ptr != B->b.buffer) + lua_replace(B->L2, -2); /* remove userdata buffer */ +} + + +#endif /* Lua 5.1 */ + + + +/* definitions for Lua 5.1 and Lua 5.2 */ +#if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502 + + +COMPAT53_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { +#undef lua_pushlstring + lua_pushlstring(L, len > 0 ? s : "", len); +#define lua_pushlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _pushlstring_53) + return lua_tostring(L, -1); +} + + +COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i) { + index = lua_absindex(L, index); + lua_pushinteger(L, i); + lua_gettable(L, index); + return lua_type(L, -1); +} + + +#ifndef LUA_EXTRASPACE +#define LUA_EXTRASPACE (sizeof(void*)) +#endif + +COMPAT53_API void *lua_getextraspace (lua_State *L) { + int is_main = 0; + void *ptr = NULL; + luaL_checkstack(L, 4, "not enough stack slots available"); + lua_pushliteral(L, "__compat53_extraspace"); + lua_pushvalue(L, -1); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 2); + lua_createtable(L, 0, 1); + lua_pushliteral(L, "k"); + lua_setfield(L, -2, "__mode"); + lua_setmetatable(L, -2); + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } + lua_replace(L, -2); + is_main = lua_pushthread(L); + lua_rawget(L, -2); + ptr = lua_touserdata(L, -1); + if (!ptr) { + lua_pop(L, 1); + ptr = lua_newuserdata(L, LUA_EXTRASPACE); + if (is_main) { + memset(ptr, '\0', LUA_EXTRASPACE); + lua_pushthread(L); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + lua_pushboolean(L, 1); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } else { + void* mptr = NULL; + lua_pushboolean(L, 1); + lua_rawget(L, -3); + mptr = lua_touserdata(L, -1); + if (mptr) + memcpy(ptr, mptr, LUA_EXTRASPACE); + else + memset(ptr, '\0', LUA_EXTRASPACE); + lua_pop(L, 1); + lua_pushthread(L); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } + } + lua_pop(L, 2); + return ptr; +} + + +COMPAT53_API int lua_isinteger (lua_State *L, int index) { + if (lua_type(L, index) == LUA_TNUMBER) { + lua_Number n = lua_tonumber(L, index); + lua_Integer i = lua_tointeger(L, index); + if (i == n) + return 1; + } + return 0; +} + + +COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) { + int ok = 0; + lua_Number n = lua_tonumberx(L, i, &ok); + if (ok) { + if (n == (lua_Integer)n) { + if (isnum) + *isnum = 1; + return (lua_Integer)n; + } + } + if (isnum) + *isnum = 0; + return 0; +} + + +static void compat53_reverse (lua_State *L, int a, int b) { + for (; a < b; ++a, --b) { + lua_pushvalue(L, a); + lua_pushvalue(L, b); + lua_replace(L, a); + lua_replace(L, b); + } +} + + +COMPAT53_API void lua_rotate (lua_State *L, int idx, int n) { + int n_elems = 0; + idx = lua_absindex(L, idx); + n_elems = lua_gettop(L)-idx+1; + if (n < 0) + n += n_elems; + if ( n > 0 && n < n_elems) { + luaL_checkstack(L, 2, "not enough stack slots available"); + n = n_elems - n; + compat53_reverse(L, idx, idx+n-1); + compat53_reverse(L, idx+n, idx+n_elems-1); + compat53_reverse(L, idx, idx+n_elems-1); + } +} + + +COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i) { + luaL_checkstack(L, 1, "not enough stack slots available"); + index = lua_absindex(L, index); + lua_pushinteger(L, i); + lua_insert(L, -2); + lua_settable(L, index); +} + + +#if !defined(lua_str2number) +# define lua_str2number(s, p) strtod((s), (p)) +#endif + +COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) { + char* endptr; + lua_Number n = lua_str2number(s, &endptr); + if (endptr != s) { + while (*endptr != '\0' && isspace((unsigned char)*endptr)) + ++endptr; + if (*endptr == '\0') { + lua_pushnumber(L, n); + return endptr - s + 1; + } + } + return 0; +} + + +COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { + if (!luaL_callmeta(L, idx, "__tostring")) { + int t = lua_type(L, idx), tt = 0; + char const* name = NULL; + switch (t) { + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + case LUA_TSTRING: + case LUA_TNUMBER: + lua_pushvalue(L, idx); + break; + case LUA_TBOOLEAN: + if (lua_toboolean(L, idx)) + lua_pushliteral(L, "true"); + else + lua_pushliteral(L, "false"); + break; + default: + tt = luaL_getmetafield(L, idx, "__name"); + name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); + lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); + if (tt != LUA_TNIL) + lua_replace(L, -2); + break; + } + } else { + if (!lua_isstring(L, -1)) + luaL_error(L, "'__tostring' must return a string"); + } + return lua_tolstring(L, -1, len); +} + + +COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + luaL_checkstack(L, 3, "not enough stack slots available"); + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); + if (lua_getfield(L, -1, modname) == LUA_TNIL) { + lua_pop(L, 1); + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); + lua_call(L, 1, 1); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); + } + if (glb) { + lua_pushvalue(L, -1); + lua_setglobal(L, modname); + } + lua_replace(L, -2); +} + + +#endif /* Lua 5.1 and 5.2 */ + + +#endif /* COMPAT53_C_ */ + + +/********************************************************************* +* This file contains parts of Lua 5.2's and Lua 5.3's source code: +* +* Copyright (C) 1994-2014 Lua.org, PUC-Rio. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*********************************************************************/ + diff --git a/lib/compat53/c-api/compat-5.3.h b/lib/compat53/c-api/compat-5.3.h new file mode 100644 index 0000000..6f66dad --- /dev/null +++ b/lib/compat53/c-api/compat-5.3.h @@ -0,0 +1,421 @@ +#ifndef COMPAT53_H_ +#define COMPAT53_H_ + +#include +#include +#include +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) +extern "C" { +#endif +#include +#include +#include +#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) +} +#endif + + +#undef COMPAT53_INCLUDE_SOURCE +#if defined(COMPAT53_PREFIX) +/* - change the symbol names of functions to avoid linker conflicts + * - compat-5.3.c needs to be compiled (and linked) separately + */ +# if !defined(COMPAT53_API) +# define COMPAT53_API extern +# endif +#else /* COMPAT53_PREFIX */ +/* - make all functions static and include the source. + * - compat-5.3.c doesn't need to be compiled (and linked) separately + */ +# define COMPAT53_PREFIX compat53 +# undef COMPAT53_API +# if defined(__GNUC__) || defined(__clang__) +# define COMPAT53_API __attribute__((__unused__)) static +# else +# define COMPAT53_API static +# endif +# define COMPAT53_INCLUDE_SOURCE +#endif /* COMPAT53_PREFIX */ + +#define COMPAT53_CONCAT_HELPER(a, b) a##b +#define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) + + + +/* declarations for Lua 5.1 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 + +/* XXX not implemented: + * lua_arith (new operators) + * lua_upvalueid + * lua_upvaluejoin + * lua_version + * lua_yieldk + */ + +#ifndef LUA_OK +# define LUA_OK 0 +#endif +#ifndef LUA_OPADD +# define LUA_OPADD 0 +#endif +#ifndef LUA_OPSUB +# define LUA_OPSUB 1 +#endif +#ifndef LUA_OPMUL +# define LUA_OPMUL 2 +#endif +#ifndef LUA_OPDIV +# define LUA_OPDIV 3 +#endif +#ifndef LUA_OPMOD +# define LUA_OPMOD 4 +#endif +#ifndef LUA_OPPOW +# define LUA_OPPOW 5 +#endif +#ifndef LUA_OPUNM +# define LUA_OPUNM 6 +#endif +#ifndef LUA_OPEQ +# define LUA_OPEQ 0 +#endif +#ifndef LUA_OPLT +# define LUA_OPLT 1 +#endif +#ifndef LUA_OPLE +# define LUA_OPLE 2 +#endif + +/* LuaJIT/Lua 5.1 does not have the updated + * error codes for thread status/function returns (but some patched versions do) + * define it only if it's not found + */ +#if !defined(LUA_ERRGCMM) +/* Use + 2 because in some versions of Lua (Lua 5.1) + * LUA_ERRFILE is defined as (LUA_ERRERR+1) + * so we need to avoid it (LuaJIT might have something at this + * integer value too) + */ +# define LUA_ERRGCMM (LUA_ERRERR + 2) +#endif /* LUA_ERRGCMM define */ + +typedef size_t lua_Unsigned; + +typedef struct luaL_Buffer_53 { + luaL_Buffer b; /* make incorrect code crash! */ + char *ptr; + size_t nelems; + size_t capacity; + lua_State *L2; +} luaL_Buffer_53; +#define luaL_Buffer luaL_Buffer_53 + +/* In PUC-Rio 5.1, userdata is a simple FILE* + * In LuaJIT, it's a struct where the first member is a FILE* + * We can't support the `closef` member + */ +typedef struct luaL_Stream { + FILE *f; +} luaL_Stream; + +#define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) +COMPAT53_API int lua_absindex (lua_State *L, int i); + +#define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) +COMPAT53_API void lua_arith (lua_State *L, int op); + +#define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) +COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op); + +#define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) +COMPAT53_API void lua_copy (lua_State *L, int from, int to); + +#define lua_getuservalue(L, i) \ + (lua_getfenv((L), (i)), lua_type((L), -1)) +#define lua_setuservalue(L, i) \ + (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) + +#define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) +COMPAT53_API void lua_len (lua_State *L, int i); + +#define lua_pushstring(L, s) \ + (lua_pushstring((L), (s)), lua_tostring((L), -1)) + +#ifndef luaL_newlibtable +# define luaL_newlibtable(L, l) \ + (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) +#endif +#ifndef luaL_newlib +# define luaL_newlib(L, l) \ + (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) +#endif + +#define lua_pushglobaltable(L) \ + lua_pushvalue((L), LUA_GLOBALSINDEX) + +#define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) +COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p); + +#define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) +COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); + +#define lua_rawlen(L, i) lua_objlen((L), (i)) + +#define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL) + +#define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) +COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); + +#define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) +COMPAT53_API void luaL_checkversion (lua_State *L); + +#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) +COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode); + +#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) +COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode); + +#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) +COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); + +#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) +COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); + +#define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) +COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name); + +#define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) +COMPAT53_API lua_Integer luaL_len (lua_State *L, int i); + +#define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) +COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); + +#define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) +COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname); + +#define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) +COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname); + +#define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) +COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); + +#define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) +COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname); + +#define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) +COMPAT53_API int luaL_execresult (lua_State *L, int stat); + +#define lua_callk(L, na, nr, ctx, cont) \ + ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) +#define lua_pcallk(L, na, nr, err, ctx, cont) \ + ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) + +#define lua_resume(L, from, nargs) \ + ((void)(from), lua_resume((L), (nargs))) + +#define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) +COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B); + +#define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) +COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s); + +#define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) +COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l); + +#define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) +COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B); + +#define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) +COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B); + +#undef luaL_buffinitsize +#define luaL_buffinitsize(L, B, s) \ + (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) + +#undef luaL_prepbuffer +#define luaL_prepbuffer(B) \ + luaL_prepbuffsize((B), LUAL_BUFFERSIZE) + +#undef luaL_addchar +#define luaL_addchar(B, c) \ + ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ + ((B)->ptr[(B)->nelems++] = (c))) + +#undef luaL_addsize +#define luaL_addsize(B, s) \ + ((B)->nelems += (s)) + +#undef luaL_addstring +#define luaL_addstring(B, s) \ + luaL_addlstring((B), (s), strlen((s))) + +#undef luaL_pushresultsize +#define luaL_pushresultsize(B, s) \ + (luaL_addsize((B), (s)), luaL_pushresult((B))) + +#if defined(LUA_COMPAT_APIINTCASTS) +#define lua_pushunsigned(L, n) \ + lua_pushinteger((L), (lua_Integer)(n)) +#define lua_tounsignedx(L, i, is) \ + ((lua_Unsigned)lua_tointegerx((L), (i), (is))) +#define lua_tounsigned(L, i) \ + lua_tounsignedx((L), (i), NULL) +#define luaL_checkunsigned(L, a) \ + ((lua_Unsigned)luaL_checkinteger((L), (a))) +#define luaL_optunsigned(L, a, d) \ + ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) +#endif + +#endif /* Lua 5.1 only */ + + + +/* declarations for Lua 5.1 and 5.2 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 + +typedef int lua_KContext; + +typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); + +#define lua_dump(L, w, d, s) \ + ((void)(s), lua_dump((L), (w), (d))) + +#define lua_getfield(L, i, k) \ + (lua_getfield((L), (i), (k)), lua_type((L), -1)) + +#define lua_gettable(L, i) \ + (lua_gettable((L), (i)), lua_type((L), -1)) + +#define lua_pushlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _pushlstring_53) +COMPAT53_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len); + +#define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) +COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i); + +#define lua_getextraspace COMPAT53_CONCAT(COMPAT53_PREFIX, _getextraspace) +COMPAT53_API void *lua_getextraspace (lua_State *L); + +#define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) +COMPAT53_API int lua_isinteger (lua_State *L, int index); + +#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53) +COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum); + +#define lua_numbertointeger(n, p) \ + ((*(p) = (lua_Integer)(n)), 1) + +#define lua_rawget(L, i) \ + (lua_rawget((L), (i)), lua_type((L), -1)) + +#define lua_rawgeti(L, i, n) \ + (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) + +#define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) +COMPAT53_API void lua_rotate (lua_State *L, int idx, int n); + +#define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) +COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i); + +#define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) +COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s); + +#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) +COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); + +#define luaL_getmetafield(L, o, e) \ + (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) + +#define luaL_newmetatable(L, tn) \ + (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) + +#define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) +COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, + lua_CFunction openf, int glb ); + +#endif /* Lua 5.1 and Lua 5.2 */ + + + +/* declarations for Lua 5.2 */ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 + +/* XXX not implemented: + * lua_isyieldable + * lua_arith (new operators) + * lua_pushfstring (new formats) + */ + +#define lua_getglobal(L, n) \ + (lua_getglobal((L), (n)), lua_type((L), -1)) + +#define lua_getuservalue(L, i) \ + (lua_getuservalue((L), (i)), lua_type((L), -1)) + +#define lua_rawgetp(L, i, p) \ + (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) + +#define LUA_KFUNCTION(_name) \ + static int (_name)(lua_State *L, int status, lua_KContext ctx); \ + static int (_name ## _52)(lua_State *L) { \ + lua_KContext ctx; \ + int status = lua_getctx(L, &ctx); \ + return (_name)(L, status, ctx); \ + } \ + static int (_name)(lua_State *L, int status, lua_KContext ctx) + +#define lua_pcallk(L, na, nr, err, ctx, cont) \ + lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) + +#define lua_callk(L, na, nr, ctx, cont) \ + lua_callk((L), (na), (nr), (ctx), cont ## _52) + +#define lua_yieldk(L, nr, ctx, cont) \ + lua_yieldk((L), (nr), (ctx), cont ## _52) + +#ifdef lua_call +# undef lua_call +# define lua_call(L, na, nr) \ + (lua_callk)((L), (na), (nr), 0, NULL) +#endif + +#ifdef lua_pcall +# undef lua_pcall +# define lua_pcall(L, na, nr, err) \ + (lua_pcallk)((L), (na), (nr), (err), 0, NULL) +#endif + +#ifdef lua_yield +# undef lua_yield +# define lua_yield(L, nr) \ + (lua_yieldk)((L), (nr), 0, NULL) +#endif + +#endif /* Lua 5.2 only */ + + + +/* other Lua versions */ +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 504 + +# error "unsupported Lua version (i.e. not Lua 5.1, 5.2, 5.3, or 5.4)" + +#endif /* other Lua versions except 5.1, 5.2, 5.3, and 5.4 */ + + + +/* helper macro for defining continuation functions (for every version + * *except* Lua 5.2) */ +#ifndef LUA_KFUNCTION +#define LUA_KFUNCTION(_name) \ + static int (_name)(lua_State *L, int status, lua_KContext ctx) +#endif + + +#if defined(COMPAT53_INCLUDE_SOURCE) +# include "compat-5.3.c" +#endif + + +#endif /* COMPAT53_H_ */ + diff --git a/lib/compat53/compat53/file_mt.lua b/lib/compat53/compat53/file_mt.lua new file mode 100644 index 0000000..6433619 --- /dev/null +++ b/lib/compat53/compat53/file_mt.lua @@ -0,0 +1,71 @@ +local lua_version = _VERSION:sub(-3) + +local M = {} + +local unpack = lua_version == "5.1" and unpack or table.unpack + +local function addasterisk(fmt) + if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then + return "*"..fmt + else + return fmt + end +end + +function M.update_file_meta(file_meta, is_luajit52) + + -- make '*' optional for file:read and file:lines + + local file_lines = file_meta.__index.lines + file_meta.__index.lines = function(self, ...) + local n = select('#', ...) + for i = 1, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return file_lines(self, unpack(args, 1, n)) + end + end + return file_lines(self, ...) + end + + local file_read = file_meta.__index.read + file_meta.__index.read = function(self, ...) + local n = select('#', ...) + for i = 1, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return file_read(self, unpack(args, 1, n)) + end + end + return file_read(self, ...) + end + + if not is_luajit52 then + local file_write = file_meta.__index.write + file_meta.__index.write = function(self, ...) + local ret, err = file_write(self, ...) + if ret then + return self + end + return ret, err + end + end +end + +return M diff --git a/lib/compat53/compat53/init.lua b/lib/compat53/compat53/init.lua new file mode 100644 index 0000000..b507571 --- /dev/null +++ b/lib/compat53/compat53/init.lua @@ -0,0 +1,325 @@ +local lua_version = _VERSION:sub(-3) + + +if lua_version < "5.3" then + + local _G, pairs, require, select, type = + _G, pairs, require, select, type + local debug, io = debug, io + local unpack = lua_version == "5.1" and unpack or table.unpack + + local M = require("compat53.module") + + -- select the most powerful getmetatable function available + local gmt = type(debug) == "table" and debug.getmetatable or + getmetatable or function() return false end + -- metatable for file objects from Lua's standard io library + local file_meta = gmt(io.stdout) + + + -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) + local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" + local is_luajit52 = is_luajit and + #setmetatable({}, { __len = function() return 1 end }) == 1 + + + if type(file_meta) == "table" and type(file_meta.__index) == "table" then + local file_mt = require("compat53.file_mt") + file_mt.update_file_meta(file_meta, is_luajit52) + end -- got a valid metatable for file objects + + + -- changes for Lua 5.1 only + if lua_version == "5.1" then + + -- cache globals + local error, pcall, rawset, setmetatable, tostring, xpcall = + error, pcall, rawset, setmetatable, tostring, xpcall + local coroutine, package, string = coroutine, package, string + local coroutine_resume = coroutine.resume + local coroutine_running = coroutine.running + local coroutine_status = coroutine.status + local coroutine_yield = coroutine.yield + local io_type = io.type + + + -- make package.searchers available as an alias for package.loaders + local p_index = { searchers = package.loaders } + setmetatable(package, { + __index = p_index, + __newindex = function(p, k, v) + if k == "searchers" then + rawset(p, "loaders", v) + p_index.searchers = v + else + rawset(p, k, v) + end + end + }) + + + if type(file_meta) == "table" and type(file_meta.__index) == "table" then + if not is_luajit then + local function helper(_, var_1, ...) + if var_1 == nil then + if (...) ~= nil then + error((...), 2) + end + end + return var_1, ... + end + + local function lines_iterator(st) + return helper(st, st.f:read(unpack(st, 1, st.n))) + end + + local file_write = file_meta.__index.write + file_meta.__index.write = function(self, ...) + local res, msg, errno = file_write(self, ...) + if res then + return self + else + return nil, msg, errno + end + end + + file_meta.__index.lines = function(self, ...) + if io_type(self) == "closed file" then + error("attempt to use a closed file", 2) + end + local st = { f=self, n=select('#', ...), ... } + for i = 1, st.n do + local t = type(st[i]) + if t == "string" then + local fmt = st[i]:match("^*?([aln])") + if not fmt then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + st[i] = "*"..fmt + elseif t ~= "number" then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + end + return lines_iterator, st + end + end -- not luajit + end -- file_meta valid + + + -- the (x)pcall implementations start a new coroutine internally + -- to allow yielding even in Lua 5.1. to allow for accurate + -- stack traces we keep track of the nested coroutine activations + -- in the weak tables below: + local weak_meta = { __mode = "kv" } + -- maps the internal pcall coroutines to the user coroutine that + -- *should* be running if pcall didn't use coroutines internally + local pcall_mainOf = setmetatable({}, weak_meta) + -- table that maps each running coroutine started by pcall to + -- the coroutine that resumed it (user coroutine *or* pcall + -- coroutine!) + local pcall_previous = setmetatable({}, weak_meta) + -- reverse of `pcall_mainOf`. maps a user coroutine to the + -- currently active pcall coroutine started within it + local pcall_callOf = setmetatable({}, weak_meta) + -- similar to `pcall_mainOf` but is used only while executing + -- the error handler of xpcall (thus no nesting is necessary!) + local xpcall_running = setmetatable({}, weak_meta) + + -- handle debug functions + if type(debug) == "table" then + local debug_getinfo = debug.getinfo + local debug_traceback = debug.traceback + + if not is_luajit then + local function calculate_trace_level(co, level) + if level ~= nil then + for out = 1, 1/0 do + local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") + if info == nil then + local max = out-1 + if level <= max then + return level + end + return nil, level-max + end + end + end + return 1 + end + + local stack_pattern = "\nstack traceback:" + local stack_replace = "" + function debug.traceback(co, msg, level) + local lvl + local nilmsg + if type(co) ~= "thread" then + co, msg, level = coroutine_running(), co, msg + end + if msg == nil then + msg = "" + nilmsg = true + elseif type(msg) ~= "string" then + return msg + end + if co == nil then + msg = debug_traceback(msg, level or 1) + else + local xpco = xpcall_running[co] + if xpco ~= nil then + lvl, level = calculate_trace_level(xpco, level) + if lvl then + msg = debug_traceback(xpco, msg, lvl) + else + msg = msg..stack_pattern + end + lvl, level = calculate_trace_level(co, level) + if lvl then + local trace = debug_traceback(co, "", lvl) + msg = msg..trace:gsub(stack_pattern, stack_replace) + end + else + co = pcall_callOf[co] or co + lvl, level = calculate_trace_level(co, level) + if lvl then + msg = debug_traceback(co, msg, lvl) + else + msg = msg..stack_pattern + end + end + co = pcall_previous[co] + while co ~= nil do + lvl, level = calculate_trace_level(co, level) + if lvl then + local trace = debug_traceback(co, "", lvl) + msg = msg..trace:gsub(stack_pattern, stack_replace) + end + co = pcall_previous[co] + end + end + if nilmsg then + msg = msg:gsub("^\n", "") + end + msg = msg:gsub("\n\t%(tail call%): %?", "\000") + msg = msg:gsub("\n\t%.%.%.\n", "\001\n") + msg = msg:gsub("\n\t%.%.%.$", "\001") + msg = msg:gsub("(%z+)\001(%z+)", function(some, other) + return "\n\t(..."..#some+#other.."+ tail call(s)...)" + end) + msg = msg:gsub("\001(%z+)", function(zeros) + return "\n\t(..."..#zeros.."+ tail call(s)...)" + end) + msg = msg:gsub("(%z+)\001", function(zeros) + return "\n\t(..."..#zeros.."+ tail call(s)...)" + end) + msg = msg:gsub("%z+", function(zeros) + return "\n\t(..."..#zeros.." tail call(s)...)" + end) + msg = msg:gsub("\001", function() + return "\n\t..." + end) + return msg + end + end -- is not luajit + end -- debug table available + + + if not is_luajit52 then + local coroutine_running52 = M.coroutine.running + function M.coroutine.running() + local co, ismain = coroutine_running52() + if ismain then + return co, true + else + return pcall_mainOf[co] or co, false + end + end + end + + if not is_luajit then + local function pcall_results(current, call, success, ...) + if coroutine_status(call) == "suspended" then + return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) + end + if pcall_previous then + pcall_previous[call] = nil + local main = pcall_mainOf[call] + if main == current then current = nil end + pcall_callOf[main] = current + end + pcall_mainOf[call] = nil + return success, ... + end + + local function pcall_exec(current, call, ...) + local main = pcall_mainOf[current] or current + pcall_mainOf[call] = main + if pcall_previous then + pcall_previous[call] = current + pcall_callOf[main] = call + end + return pcall_results(current, call, coroutine_resume(call, ...)) + end + + local coroutine_create52 = M.coroutine.create + + local function pcall_coroutine(func) + if type(func) ~= "function" then + local callable = func + func = function (...) return callable(...) end + end + return coroutine_create52(func) + end + + function M.pcall(func, ...) + local current = coroutine_running() + if not current then return pcall(func, ...) end + return pcall_exec(current, pcall_coroutine(func), ...) + end + + local function xpcall_catch(current, call, msgh, success, ...) + if not success then + xpcall_running[current] = call + local ok, result = pcall(msgh, ...) + xpcall_running[current] = nil + if not ok then + return false, "error in error handling ("..tostring(result)..")" + end + return false, result + end + return true, ... + end + + function M.xpcall(f, msgh, ...) + local current = coroutine_running() + if not current then + local args, n = { ... }, select('#', ...) + return xpcall(function() return f(unpack(args, 1, n)) end, msgh) + end + local call = pcall_coroutine(f) + return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) + end + end -- not luajit + + end -- lua 5.1 + + + -- handle exporting to global scope + local function extend_table(from, to) + if from ~= to then + for k,v in pairs(from) do + if type(v) == "table" and + type(to[k]) == "table" and + v ~= to[k] then + extend_table(v, to[k]) + else + to[k] = v + end + end + end + end + + extend_table(M, _G) + +end -- lua < 5.3 + +-- vi: set expandtab softtabstop=3 shiftwidth=3 : diff --git a/lib/compat53/compat53/module.lua b/lib/compat53/compat53/module.lua new file mode 100644 index 0000000..52b1dd6 --- /dev/null +++ b/lib/compat53/compat53/module.lua @@ -0,0 +1,894 @@ +local _G, _VERSION = _G, _VERSION +local lua_version = _VERSION:sub(-3) + + +local M = _G + +if lua_version < "5.3" then + + -- cache globals in upvalues + local error, ipairs, pairs, pcall, require, select, setmetatable, type = + error, ipairs, pairs, pcall, require, select, setmetatable, type + local debug, io, math, package, string, table = + debug, io, math, package, string, table + local io_lines = io.lines + local io_read = io.read + local io_open = io.open + local io_popen = io.popen + local io_tmpfile = io.tmpfile + local unpack = lua_version == "5.1" and unpack or table.unpack + local debug_setmetatable = type(debug) == "table" and debug.setmetatable + + -- create module table + M = {} + local M_meta = { + __index = _G, + -- __newindex is set at the end + } + setmetatable(M, M_meta) + + -- create subtables + M.io = setmetatable({}, { __index = io }) + M.math = setmetatable({}, { __index = math }) + M.string = setmetatable({}, { __index = string }) + M.table = setmetatable({}, { __index = table }) + M.utf8 = {} + + + -- select the most powerful getmetatable function available + local gmt = type(debug) == "table" and debug.getmetatable or + getmetatable or function() return false end + + -- type checking functions + local checkinteger -- forward declararation + + local function argcheck(cond, i, f, extra) + if not cond then + error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0) + end + end + + + -- load utf8 library + local utf8_ok, utf8lib = pcall(require, "compat53.utf8") + if utf8_ok then + if lua_version == "5.1" then + utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" + end + for k,v in pairs(utf8lib) do + M.utf8[k] = v + end + package.loaded["utf8"] = M.utf8 + end + + + -- load table library + local table_ok, tablib = pcall(require, "compat53.table") + if table_ok then + for k,v in pairs(tablib) do + M.table[k] = v + end + end + + + -- load io functions + local io_ok, iolib = pcall(require, "compat53.io") + if io_ok then + for k,v in pairs(iolib) do + M.io[k] = v + end + end + + + -- load string packing functions + local str_ok, strlib = pcall(require, "compat53.string") + if str_ok then + for k,v in pairs(strlib) do + M.string[k] = v + end + end + + + -- try Roberto's struct module for string packing/unpacking if + -- compat53.string is unavailable + if not str_ok then + local struct_ok, struct = pcall(require, "struct") + if struct_ok then + M.string.pack = struct.pack + M.string.packsize = struct.size + M.string.unpack = struct.unpack + end + end + + + -- update math library + do + local maxint, minint = 1 + + while maxint+1 > maxint and 2*maxint > maxint do + maxint = maxint * 2 + end + if 2*maxint <= maxint then + maxint = 2*maxint-1 + minint = -maxint-1 + else + maxint = maxint + minint = -maxint + end + M.math.maxinteger = maxint + M.math.mininteger = minint + + function M.math.tointeger(n) + n = tonumber(n) + if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then + return n + end + return nil + end + + function M.math.type(n) + if type(n) == "number" then + if n <= maxint and n >= minint and n % 1 == 0 then + return "integer" + else + return "float" + end + else + return nil + end + end + + function checkinteger(x, i, f) + local t = type(x) + if t ~= "number" then + error("bad argument #"..i.." to '"..f.. + "' (number expected, got "..t..")", 0) + elseif x > maxint or x < minint or x % 1 ~= 0 then + error("bad argument #"..i.." to '"..f.. + "' (number has no integer representation)", 0) + else + return x + end + end + + function M.math.ult(m, n) + m = checkinteger(m, "1", "math.ult") + n = checkinteger(n, "2", "math.ult") + if m >= 0 and n < 0 then + return true + elseif m < 0 and n >= 0 then + return false + else + return m < n + end + end + end + + + -- assert should allow non-string error objects + function M.assert(cond, ...) + if cond then + return cond, ... + elseif select('#', ...) > 0 then + error((...), 0) + else + error("assertion failed!", 0) + end + end + + + -- ipairs should respect __index metamethod + do + local function ipairs_iterator(st, var) + var = var + 1 + local val = st[var] + if val ~= nil then + return var, st[var] + end + end + function M.ipairs(t) + if gmt(t) ~= nil then -- t has metatable + return ipairs_iterator, t, 0 + else + return ipairs(t) + end + end + end + + + -- make '*' optional for io.read and io.lines + do + local function addasterisk(fmt) + if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then + return "*"..fmt + else + return fmt + end + end + + function M.io.read(...) + local n = select('#', ...) + for i = 1, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere. + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return io_read(unpack(args, 1, n)) + end + end + return io_read(...) + end + + -- PUC-Rio Lua 5.1 uses a different implementation for io.lines! + function M.io.lines(...) + local n = select('#', ...) + for i = 2, n do + local a = select(i, ...) + local b = addasterisk(a) + -- as an optimization we only allocate a table for the + -- modified format arguments when we have a '*' somewhere. + if a ~= b then + local args = { ... } + args[i] = b + for j = i+1, n do + args[j] = addasterisk(args[j]) + end + return io_lines(unpack(args, 1, n)) + end + end + return io_lines(...) + end + end + + + -- update table library (if C module not available) + if not table_ok then + local table_concat = table.concat + local table_insert = table.insert + local table_remove = table.remove + local table_sort = table.sort + + function M.table.concat(list, sep, i, j) + local mt = gmt(list) + if type(mt) == "table" and type(mt.__len) == "function" then + local src = list + list, i, j = {}, i or 1, j or mt.__len(src) + for k = i, j do + list[k] = src[k] + end + end + return table_concat(list, sep, i, j) + end + + function M.table.insert(list, ...) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_mt and (has_len or mt.__index or mt.__newindex) then + local e = (has_len and mt.__len(list) or #list)+1 + local nargs, pos, value = select('#', ...), ... + if nargs == 1 then + pos, value = e, pos + elseif nargs == 2 then + pos = checkinteger(pos, "2", "table.insert") + argcheck(1 <= pos and pos <= e, "2", "table.insert", + "position out of bounds" ) + else + error("wrong number of arguments to 'insert'", 0) + end + for i = e-1, pos, -1 do + list[i+1] = list[i] + end + list[pos] = value + else + return table_insert(list, ...) + end + end + + function M.table.move(a1, f, e, t, a2) + a2 = a2 or a1 + f = checkinteger(f, "2", "table.move") + argcheck(f > 0, "2", "table.move", + "initial position must be positive") + e = checkinteger(e, "3", "table.move") + t = checkinteger(t, "4", "table.move") + if e >= f then + local m, n, d = 0, e-f, 1 + if t > f then m, n, d = n, m, -1 end + for i = m, n, d do + a2[t+i] = a1[f+i] + end + end + return a2 + end + + function M.table.remove(list, pos) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_mt and (has_len or mt.__index or mt.__newindex) then + local e = (has_len and mt.__len(list) or #list) + pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e + if pos ~= e then + argcheck(1 <= pos and pos <= e+1, "2", "table.remove", + "position out of bounds" ) + end + local result = list[pos] + while pos < e do + list[pos] = list[pos+1] + pos = pos + 1 + end + list[pos] = nil + return result + else + return table_remove(list, pos) + end + end + + do + local function pivot(list, cmp, a, b) + local m = b - a + if m > 2 then + local c = a + (m-m%2)/2 + local x, y, z = list[a], list[b], list[c] + if not cmp(x, y) then + x, y, a, b = y, x, b, a + end + if not cmp(y, z) then + y, b = z, c + end + if not cmp(x, y) then + y, b = x, a + end + return b, y + else + return b, list[b] + end + end + + local function lt_cmp(a, b) + return a < b + end + + local function qsort(list, cmp, b, e) + if b < e then + local i, j, k, val = b, e, pivot(list, cmp, b, e) + while i < j do + while i < j and cmp(list[i], val) do + i = i + 1 + end + while i < j and not cmp(list[j], val) do + j = j - 1 + end + if i < j then + list[i], list[j] = list[j], list[i] + if i == k then k = j end -- update pivot position + i, j = i+1, j-1 + end + end + if i ~= k and not cmp(list[i], val) then + list[i], list[k] = val, list[i] + k = i -- update pivot position + end + qsort(list, cmp, b, i == k and i-1 or i) + return qsort(list, cmp, i+1, e) + end + end + + function M.table.sort(list, cmp) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_len then + cmp = cmp or lt_cmp + local len = mt.__len(list) + return qsort(list, cmp, 1, len) + else + return table_sort(list, cmp) + end + end + end + + local function unpack_helper(list, i, j, ...) + if j < i then + return ... + else + return unpack_helper(list, i, j-1, list[j], ...) + end + end + function M.table.unpack(list, i, j) + local mt = gmt(list) + local has_mt = type(mt) == "table" + local has_len = has_mt and type(mt.__len) == "function" + if has_mt and (has_len or mt.__index) then + i, j = i or 1, j or (has_len and mt.__len(list)) or #list + return unpack_helper(list, i, j) + else + return unpack(list, i, j) + end + end + end -- update table library + + + -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 + if lua_version == "5.1" then + -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) + local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" + local is_luajit52 = is_luajit and + #setmetatable({}, { __len = function() return 1 end }) == 1 + + -- cache globals in upvalues + local load, loadfile, loadstring, setfenv, xpcall = + load, loadfile, loadstring, setfenv, xpcall + local coroutine, os = coroutine, os + local coroutine_create = coroutine.create + local coroutine_resume = coroutine.resume + local coroutine_running = coroutine.running + local coroutine_status = coroutine.status + local coroutine_yield = coroutine.yield + local io_input = io.input + local io_open = io.open + local io_output = io.output + local io_write = io.write + local math_log = math.log + local os_execute = os.execute + local string_find = string.find + local string_format = string.format + local string_gmatch = string.gmatch + local string_gsub = string.gsub + local string_match = string.match + local string_rep = string.rep + local table_concat = table.concat + + -- create subtables + M.coroutine = setmetatable({}, { __index = coroutine }) + M.os = setmetatable({}, { __index = os }) + M.package = setmetatable({}, { __index = package }) + + -- handle debug functions + if type(debug) == "table" then + local debug_setfenv = debug.setfenv + local debug_getfenv = debug.getfenv + + M.debug = setmetatable({}, { __index = debug }) + + if not is_luajit52 then + function M.debug.setuservalue(obj, value) + if type(obj) ~= "userdata" then + error("bad argument #1 to 'setuservalue' (userdata expected, got ".. + type(obj)..")", 2) + end + if value == nil then value = _G end + if type(value) ~= "table" then + error("bad argument #2 to 'setuservalue' (table expected, got ".. + type(value)..")", 2) + end + return debug_setfenv(obj, value) + end + + function M.debug.getuservalue(obj) + if type(obj) ~= "userdata" then + return nil + else + local v = debug_getfenv(obj) + if v == _G or v == package then + return nil + end + return v + end + end + + function M.debug.setmetatable(value, tab) + debug_setmetatable(value, tab) + return value + end + end -- not luajit with compat52 enabled + end -- debug table available + + + if not is_luajit52 then + function M.pairs(t) + local mt = gmt(t) + if type(mt) == "table" and type(mt.__pairs) == "function" then + return mt.__pairs(t) + else + return pairs(t) + end + end + end + + + if not is_luajit then + local function check_mode(mode, prefix) + local has = { text = false, binary = false } + for i = 1,#mode do + local c = mode:sub(i, i) + if c == "t" then has.text = true end + if c == "b" then has.binary = true end + end + local t = prefix:sub(1, 1) == "\27" and "binary" or "text" + if not has[t] then + return "attempt to load a "..t.." chunk (mode is '"..mode.."')" + end + end + + function M.load(ld, source, mode, env) + mode = mode or "bt" + local chunk, msg + if type( ld ) == "string" then + if mode ~= "bt" then + local merr = check_mode(mode, ld) + if merr then return nil, merr end + end + chunk, msg = loadstring(ld, source) + else + local ld_type = type(ld) + if ld_type ~= "function" then + error("bad argument #1 to 'load' (function expected, got ".. + ld_type..")", 2) + end + if mode ~= "bt" then + local checked, merr = false, nil + local function checked_ld() + if checked then + return ld() + else + checked = true + local v = ld() + merr = check_mode(mode, v or "") + if merr then return nil end + return v + end + end + chunk, msg = load(checked_ld, source) + if merr then return nil, merr end + else + chunk, msg = load(ld, source) + end + end + if not chunk then + return chunk, msg + end + if env ~= nil then + setfenv(chunk, env) + end + return chunk + end + + M.loadstring = M.load + + function M.loadfile(file, mode, env) + mode = mode or "bt" + if mode ~= "bt" then + local f = io_open(file, "rb") + if f then + local prefix = f:read(1) + f:close() + if prefix then + local merr = check_mode(mode, prefix) + if merr then return nil, merr end + end + end + end + local chunk, msg = loadfile(file) + if not chunk then + return chunk, msg + end + if env ~= nil then + setfenv(chunk, env) + end + return chunk + end + end -- not luajit + + + if not is_luajit52 then + function M.rawlen(v) + local t = type(v) + if t ~= "string" and t ~= "table" then + error("bad argument #1 to 'rawlen' (table or string expected)", 2) + end + return #v + end + end + + + if not is_luajit then + function M.xpcall(f, msgh, ...) + local args, n = { ... }, select('#', ...) + return xpcall(function() return f(unpack(args, 1, n)) end, msgh) + end + end + + + if not is_luajit52 then + function M.os.execute(cmd) + local code = os_execute(cmd) + -- Lua 5.1 does not report exit by signal. + if code == 0 then + return true, "exit", code + else + if package.config:sub(1, 1) == '/' then + code = code/256 -- only correct on Linux! + end + return nil, "exit", code + end + end + end + + + if not table_ok and not is_luajit52 then + M.table.pack = function(...) + return { n = select('#', ...), ... } + end + end + + + local main_coroutine = coroutine_create(function() end) + + function M.coroutine.create(func) + local success, result = pcall(coroutine_create, func) + if not success then + if type(func) ~= "function" then + error("bad argument #1 (function expected)", 0) + end + result = coroutine_create(function(...) return func(...) end) + end + return result + end + + if not is_luajit52 then + function M.coroutine.running() + local co = coroutine_running() + if co then + return co, false + else + return main_coroutine, true + end + end + end + + function M.coroutine.yield(...) + local co, flag = coroutine_running() + if co and not flag then + return coroutine_yield(...) + else + error("attempt to yield from outside a coroutine", 0) + end + end + + if not is_luajit then + function M.coroutine.resume(co, ...) + if co == main_coroutine then + return false, "cannot resume non-suspended coroutine" + else + return coroutine_resume(co, ...) + end + end + + function M.coroutine.status(co) + local notmain = coroutine_running() + if co == main_coroutine then + return notmain and "normal" or "running" + else + return coroutine_status(co) + end + end + end -- not luajit + + + if not is_luajit then + M.math.log = function(x, base) + if base ~= nil then + return math_log(x)/math_log(base) + else + return math_log(x) + end + end + end + + + if not is_luajit then + function M.package.searchpath(name, path, sep, rep) + sep = (sep or "."):gsub("(%p)", "%%%1") + rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") + local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") + local msg = {} + for subpath in path:gmatch("[^;]+") do + local fpath = subpath:gsub("%?", pname) + local f = io_open(fpath, "r") + if f then + f:close() + return fpath + end + msg[#msg+1] = "\n\tno file '" .. fpath .. "'" + end + return nil, table_concat(msg) + end + end + + + local function fix_pattern(pattern) + return (string_gsub(pattern, "%z", "%%z")) + end + + function M.string.find(s, pattern, ...) + return string_find(s, fix_pattern(pattern), ...) + end + + function M.string.gmatch(s, pattern) + return string_gmatch(s, fix_pattern(pattern)) + end + + function M.string.gsub(s, pattern, ...) + return string_gsub(s, fix_pattern(pattern), ...) + end + + function M.string.match(s, pattern, ...) + return string_match(s, fix_pattern(pattern), ...) + end + + if not is_luajit then + function M.string.rep(s, n, sep) + if sep ~= nil and sep ~= "" and n >= 2 then + return s .. string_rep(sep..s, n-1) + else + return string_rep(s, n) + end + end + end + + if not is_luajit then + do + local addqt = { + ["\n"] = "\\\n", + ["\\"] = "\\\\", + ["\""] = "\\\"" + } + + local function addquoted(c, d) + return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d + end + + function M.string.format(fmt, ...) + local args, n = { ... }, select('#', ...) + local i = 0 + local function adjust_fmt(lead, mods, kind) + if #lead % 2 == 0 then + i = i + 1 + if kind == "s" then + args[i] = _G.tostring(args[i]) + elseif kind == "q" then + args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"' + return lead.."%"..mods.."s" + end + end + end + fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) + return string_format(fmt, unpack(args, 1, n)) + end + end + end + + + function M.io.write(...) + local res, msg, errno = io_write(...) + if res then + return io_output() + else + return nil, msg, errno + end + end + + if not is_luajit then + local function helper(st, var_1, ...) + if var_1 == nil then + if st.doclose then st.f:close() end + if (...) ~= nil then + error((...), 2) + end + end + return var_1, ... + end + + local function lines_iterator(st) + return helper(st, st.f:read(unpack(st, 1, st.n))) + end + + function M.io.lines(fname, ...) + local doclose, file, msg + if fname ~= nil then + doclose, file, msg = true, io_open(fname, "r") + if not file then error(msg, 2) end + else + doclose, file = false, io_input() + end + local st = { f=file, doclose=doclose, n=select('#', ...), ... } + for i = 1, st.n do + local t = type(st[i]) + if t == "string" then + local fmt = st[i]:match("^%*?([aln])") + if not fmt then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + st[i] = "*"..fmt + elseif t ~= "number" then + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) + end + end + return lines_iterator, st + end + end -- not luajit + + if is_luajit then + local compat_file_meta = {} + local compat_file_meta_loaded = 0 + + local function load_compat_file_meta(file_meta) + -- fill compat_file_meta with original entries + for k, v in pairs(file_meta) do + compat_file_meta[k] = v + end + compat_file_meta.__index = {} + for k, v in pairs(file_meta.__index) do + compat_file_meta.__index[k] = v + end + + compat_file_meta_loaded = 1 + + -- update it with compatibility functions + local file_mt_ok, file_mt = pcall(require, "compat53.file_mt") + if file_mt_ok then + file_mt.update_file_meta(compat_file_meta, is_luajit52) + + compat_file_meta_loaded = 2 + end + end + + local function return_fd(fd, err, code) + if not fd then + return fd, err, code + end + if fd and debug_setmetatable then + if compat_file_meta_loaded == 0 then + local file_meta = gmt(fd) + load_compat_file_meta(file_meta) + end + if compat_file_meta_loaded == 2 then + debug_setmetatable(fd, compat_file_meta) + end + end + return fd + end + + function M.io.open(...) + return return_fd(io_open(...)) + end + + function M.io.popen(...) + return return_fd(io_popen(...)) + end + + function M.io.tmpfile(...) + return return_fd(io_tmpfile(...)) + end + end + + end -- lua 5.1 + + -- further write should be forwarded to _G + M_meta.__newindex = _G + +end -- lua < 5.3 + + +-- return module table +return M + +-- vi: set expandtab softtabstop=3 shiftwidth=3 : diff --git a/lib/compat53/lbitlib.c b/lib/compat53/lbitlib.c new file mode 100644 index 0000000..db2652a --- /dev/null +++ b/lib/compat53/lbitlib.c @@ -0,0 +1,243 @@ +/* +** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ +** Standard library for bitwise operations +** See Copyright Notice in lua.h +*/ + +#define lbitlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +#if defined(LUA_COMPAT_BITLIB) /* { */ + + +#define pushunsigned(L,n) (sizeof(lua_Integer) > 4 ? lua_pushinteger(L, (lua_Integer)(n)) : lua_pushnumber(L, (lua_Number)(n))) +static lua_Unsigned checkunsigned(lua_State *L, int i) { + if (sizeof(lua_Integer) > 4) + return (lua_Unsigned)luaL_checkinteger(L, i); + else { + lua_Number d = luaL_checknumber(L, i); + if (d < 0) + d = (d + 1) + (~(lua_Unsigned)0); + luaL_argcheck(L, d >= 0 && d <= (~(lua_Unsigned)0), i, "value out of range"); + return (lua_Unsigned)d; + } +} + + +/* number of bits to consider in a number */ +#if !defined(LUA_NBITS) +#define LUA_NBITS 32 +#endif + + +/* +** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must +** be made in two parts to avoid problems when LUA_NBITS is equal to the +** number of bits in a lua_Unsigned.) +*/ +#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + + +/* macro to trim extra bits */ +#define trim(x) ((x) & ALLONES) + + +/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ +#define mask(n) (~((ALLONES << 1) << ((n) - 1))) + + + +static lua_Unsigned andaux (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = ~(lua_Unsigned)0; + for (i = 1; i <= n; i++) + r &= checkunsigned(L, i); + return trim(r); +} + + +static int b_and (lua_State *L) { + lua_Unsigned r = andaux(L); + pushunsigned(L, r); + return 1; +} + + +static int b_test (lua_State *L) { + lua_Unsigned r = andaux(L); + lua_pushboolean(L, r != 0); + return 1; +} + + +static int b_or (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = 0; + for (i = 1; i <= n; i++) + r |= checkunsigned(L, i); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_xor (lua_State *L) { + int i, n = lua_gettop(L); + lua_Unsigned r = 0; + for (i = 1; i <= n; i++) + r ^= checkunsigned(L, i); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_not (lua_State *L) { + lua_Unsigned r = ~checkunsigned(L, 1); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { + if (i < 0) { /* shift right? */ + i = -i; + r = trim(r); + if (i >= LUA_NBITS) r = 0; + else r >>= i; + } + else { /* shift left */ + if (i >= LUA_NBITS) r = 0; + else r <<= i; + r = trim(r); + } + pushunsigned(L, r); + return 1; +} + + +static int b_lshift (lua_State *L) { + return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); +} + + +static int b_rshift (lua_State *L) { + return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); +} + + +static int b_arshift (lua_State *L) { + lua_Unsigned r = checkunsigned(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) + return b_shift(L, r, -i); + else { /* arithmetic shift for 'negative' number */ + if (i >= LUA_NBITS) r = ALLONES; + else + r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ + pushunsigned(L, r); + return 1; + } +} + + +static int b_rot (lua_State *L, lua_Integer d) { + lua_Unsigned r = checkunsigned(L, 1); + int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ + r = trim(r); + if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ + r = (r << i) | (r >> (LUA_NBITS - i)); + pushunsigned(L, trim(r)); + return 1; +} + + +static int b_lrot (lua_State *L) { + return b_rot(L, luaL_checkinteger(L, 2)); +} + + +static int b_rrot (lua_State *L) { + return b_rot(L, -luaL_checkinteger(L, 2)); +} + + +/* +** get field and width arguments for field-manipulation functions, +** checking whether they are valid. +** ('luaL_error' called without 'return' to avoid later warnings about +** 'width' being used uninitialized.) +*/ +static int fieldargs (lua_State *L, int farg, int *width) { + lua_Integer f = luaL_checkinteger(L, farg); + lua_Integer w = luaL_optinteger(L, farg + 1, 1); + luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); + luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); + if (f + w > LUA_NBITS) + luaL_error(L, "trying to access non-existent bits"); + *width = (int)w; + return (int)f; +} + + +static int b_extract (lua_State *L) { + int w; + lua_Unsigned r = trim(checkunsigned(L, 1)); + int f = fieldargs(L, 2, &w); + r = (r >> f) & mask(w); + pushunsigned(L, r); + return 1; +} + + +static int b_replace (lua_State *L) { + int w; + lua_Unsigned r = trim(checkunsigned(L, 1)); + lua_Unsigned v = trim(checkunsigned(L, 2)); + int f = fieldargs(L, 3, &w); + lua_Unsigned m = mask(w); + r = (r & ~(m << f)) | ((v & m) << f); + pushunsigned(L, r); + return 1; +} + + +static const luaL_Reg bitlib[] = { + {"arshift", b_arshift}, + {"band", b_and}, + {"bnot", b_not}, + {"bor", b_or}, + {"bxor", b_xor}, + {"btest", b_test}, + {"extract", b_extract}, + {"lrotate", b_lrot}, + {"lshift", b_lshift}, + {"replace", b_replace}, + {"rrotate", b_rrot}, + {"rshift", b_rshift}, + {NULL, NULL} +}; + + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + luaL_newlib(L, bitlib); + return 1; +} + + +#else /* }{ */ + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + return luaL_error(L, "library 'bit32' has been deprecated"); +} + +#endif /* } */ diff --git a/lib/compat53/liolib.c b/lib/compat53/liolib.c new file mode 100644 index 0000000..8a9e75c --- /dev/null +++ b/lib/compat53/liolib.c @@ -0,0 +1,776 @@ +/* +** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + +#define liolib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + + +/* +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +static int l_checkmode (const char *mode) { + return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && + (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ + (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ +} + +#endif + +/* +** {====================================================== +** l_popen spawns a new process connected to the current +** one through the file streams. +** ======================================================= +*/ + +#if !defined(l_popen) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) + +#else /* }{ */ + +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)((void)c, m), \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + +/* +** {====================================================== +** l_fseek: configuration for longer offsets +** ======================================================= +*/ + +#if !defined(l_fseek) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define l_fseek(f,o,w) fseeko(f,o,w) +#define l_ftell(f) ftello(f) +#define l_seeknum off_t + +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ + && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ + +/* Windows (but not DDK) and Visual C++ 2005 or higher */ +#define l_fseek(f,o,w) _fseeki64(f,o,w) +#define l_ftell(f) _ftelli64(f) +#define l_seeknum __int64 + +#else /* }{ */ + +/* ISO C definitions */ +#define l_fseek(f,o,w) fseek(f,o,w) +#define l_ftell(f) ftell(f) +#define l_seeknum long + +#endif /* } */ + +#endif /* } */ + +/* }====================================================== */ + + +#define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) +#define IO_INPUT (IO_PREFIX "input") +#define IO_OUTPUT (IO_PREFIX "output") + + +typedef luaL_Stream LStream; + + +#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +#define isclosed(p) ((p)->closef == NULL) + + +static int io_type (lua_State *L) { + LStream *p; + luaL_checkany(L, 1); + p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); + if (p == NULL) + lua_pushnil(L); /* not a file */ + else if (isclosed(p)) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; +} + + +static int f_tostring (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", p->f); + return 1; +} + + +static FILE *tofile (lua_State *L) { + LStream *p = tolstream(L); + if (isclosed(p)) + luaL_error(L, "attempt to use a closed file"); + lua_assert(p->f); + return p->f; +} + + +/* +** When creating file handles, always creates a 'closed' file handle +** before opening the actual file; so, if there is a memory error, the +** handle is in a consistent state. +*/ +static LStream *newprefile (lua_State *L) { + LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); + p->closef = NULL; /* mark file handle as 'closed' */ + luaL_setmetatable(L, LUA_FILEHANDLE); + return p; +} + + +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ +static int aux_close (lua_State *L) { + LStream *p = tolstream(L); + volatile lua_CFunction cf = p->closef; + p->closef = NULL; /* mark stream as closed */ + return (*cf)(L); /* close it */ +} + + +static int f_close (lua_State *L) { + tofile(L); /* make sure argument is an open stream */ + return aux_close(L); +} + + +static int io_close (lua_State *L) { + if (lua_isnone(L, 1)) /* no argument? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ + return f_close(L); +} + + +static int f_gc (lua_State *L) { + LStream *p = tolstream(L); + if (!isclosed(p) && p->f != NULL) + aux_close(L); /* ignore closed and incompletely open files */ + return 0; +} + + +/* +** function to close regular files +*/ +static int io_fclose (lua_State *L) { + LStream *p = tolstream(L); + int res = fclose(p->f); + return luaL_fileresult(L, (res == 0), NULL); +} + + +static LStream *newfile (lua_State *L) { + LStream *p = newprefile(L); + p->f = NULL; + p->closef = &io_fclose; + return p; +} + + +static void opencheck (lua_State *L, const char *fname, const char *mode) { + LStream *p = newfile(L); + p->f = fopen(fname, mode); + if (p->f == NULL) + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newfile(L); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + p->f = fopen(filename, mode); + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +/* +** function to close 'popen' files +*/ +static int io_pclose (lua_State *L) { + LStream *p = tolstream(L); + return luaL_execresult(L, l_pclose(L, p->f)); +} + + +static int io_popen (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "r"); + LStream *p = newprefile(L); + p->f = l_popen(L, filename, mode); + p->closef = &io_pclose; + return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; +} + + +static int io_tmpfile (lua_State *L) { + LStream *p = newfile(L); + p->f = tmpfile(); + return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; +} + + +static FILE *getiofile (lua_State *L, const char *findex) { + LStream *p; + lua_getfield(L, LUA_REGISTRYINDEX, findex); + p = (LStream *)lua_touserdata(L, -1); + if (isclosed(p)) + luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); + return p->f; +} + + +static int g_iofile (lua_State *L, const char *f, const char *mode) { + if (!lua_isnoneornil(L, 1)) { + const char *filename = lua_tostring(L, 1); + if (filename) + opencheck(L, filename, mode); + else { + tofile(L); /* check that it's a valid file handle */ + lua_pushvalue(L, 1); + } + lua_setfield(L, LUA_REGISTRYINDEX, f); + } + /* return current value */ + lua_getfield(L, LUA_REGISTRYINDEX, f); + return 1; +} + + +static int io_input (lua_State *L) { + return g_iofile(L, IO_INPUT, "r"); +} + + +static int io_output (lua_State *L) { + return g_iofile(L, IO_OUTPUT, "w"); +} + + +static int io_readline (lua_State *L); + + +/* +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit +** in the limit for upvalues of a closure) +*/ +#define MAXARGLINE 250 + +static void aux_lines (lua_State *L, int toclose) { + int n = lua_gettop(L) - 1; /* number of arguments to read */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); + lua_pushinteger(L, n); /* number of arguments to read */ + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ + lua_pushcclosure(L, io_readline, 3 + n); +} + + +static int f_lines (lua_State *L) { + tofile(L); /* check that it's a valid file handle */ + aux_lines(L, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + int toclose; + if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ + if (lua_isnil(L, 1)) { /* no file name? */ + lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ + lua_replace(L, 1); /* put it at index 1 */ + tofile(L); /* check that it's a valid file handle */ + toclose = 0; /* do not close it after iteration */ + } + else { /* open a new file */ + const char *filename = luaL_checkstring(L, 1); + opencheck(L, filename, "r"); + lua_replace(L, 1); /* put file at index 1 */ + toclose = 1; /* close it after iteration */ + } + aux_lines(L, toclose); + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ + } + else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_stringtonumber' to check whether the format is +** correct and to convert it to a Lua number +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "00")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else { /* invalid format */ + lua_pushnil(L); /* "result" to be removed */ + return 0; /* read fails */ + } +} + + +static int test_eof (lua_State *L, FILE *f) { + int c = getc(f); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); + return (c != EOF); +} + + +static int read_line (lua_State *L, FILE *f, int chop) { + luaL_Buffer b; + int c = '\0'; + luaL_buffinit(L, &b); + while (c != EOF && c != '\n') { /* repeat until end of line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; + l_unlockfile(f); + luaL_addsize(&b, i); + } + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); +} + + +static void read_all (lua_State *L, FILE *f) { + size_t nr; + luaL_Buffer b; + luaL_buffinit(L, &b); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); + luaL_addsize(&b, nr); + } while (nr == LUAL_BUFFERSIZE); + luaL_pushresult(&b); /* close buffer */ +} + + +static int read_chars (lua_State *L, FILE *f, size_t n) { + size_t nr; /* number of chars actually read */ + char *p; + luaL_Buffer b; + luaL_buffinit(L, &b); + p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ + nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ + luaL_addsize(&b, nr); + luaL_pushresult(&b); /* close buffer */ + return (nr > 0); /* true iff read something */ +} + + +static int g_read (lua_State *L, FILE *f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f, 1); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)luaL_checkinteger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f, 1); + break; + case 'L': /* line with end-of-line */ + success = read_line(L, f, 0); + break; + case 'a': /* file */ + read_all(L, f); /* read entire file */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)) + return luaL_fileresult(L, 0, NULL); + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int io_read (lua_State *L) { + return g_read(L, getiofile(L, IO_INPUT), 1); +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L), 2); +} + + +static int io_readline (lua_State *L) { + LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); + int i; + int n = (int)lua_tointeger(L, lua_upvalueindex(2)); + if (isclosed(p)) /* file is already closed? */ + return luaL_error(L, "file is already closed"); + lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); + for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ + lua_pushvalue(L, lua_upvalueindex(3 + i)); + n = g_read(L, p->f, 2); /* 'n' is number of results */ + lua_assert(n > 0); /* should return at least a nil */ + if (lua_toboolean(L, -n)) /* read at least one value? */ + return n; /* return them */ + else { /* first result is nil: EOF or error */ + if (n > 1) { /* is there error information? */ + /* 2nd result is error message */ + return luaL_error(L, "%s", lua_tostring(L, -n + 1)); + } + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, FILE *f, int arg) { + int nargs = lua_gettop(L) - arg; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, + (LUAI_UACINT)lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, + (LUAI_UACNUMBER)lua_tonumber(L, arg)); + status = status && (len > 0); + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (fwrite(s, sizeof(char), l, f) == l); + } + } + if (status) return 1; /* file handle already on stack top */ + else return luaL_fileresult(L, status, NULL); +} + + +static int io_write (lua_State *L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); +} + + +static int f_write (lua_State *L) { + FILE *f = tofile(L); + lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ + return g_write(L, f, 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; + static const char *const modenames[] = {"set", "cur", "end", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + lua_Integer p3 = luaL_optinteger(L, 3, 0); + l_seeknum offset = (l_seeknum)p3; + luaL_argcheck(L, (lua_Integer)offset == p3, 3, + "not an integer in proper range"); + op = l_fseek(f, offset, mode[op]); + if (op) + return luaL_fileresult(L, 0, NULL); /* error */ + else { + lua_pushinteger(L, (lua_Integer)l_ftell(f)); + return 1; + } +} + + +static int f_setvbuf (lua_State *L) { + static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; + static const char *const modenames[] = {"no", "full", "line", NULL}; + FILE *f = tofile(L); + int op = luaL_checkoption(L, 2, NULL, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); + return luaL_fileresult(L, res == 0, NULL); +} + + + +static int io_flush (lua_State *L) { + return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); +} + + +static int f_flush (lua_State *L) { + return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); +} + + +/* +** functions for 'io' library +*/ +static const luaL_Reg iolib[] = { + {"close", io_close}, + {"flush", io_flush}, + {"input", io_input}, + {"lines", io_lines}, + {"open", io_open}, + {"output", io_output}, + {"popen", io_popen}, + {"read", io_read}, + {"tmpfile", io_tmpfile}, + {"type", io_type}, + {"write", io_write}, + {NULL, NULL} +}; + + +/* +** methods for file handles +*/ +static const luaL_Reg flib[] = { + {"close", f_close}, + {"flush", f_flush}, + {"lines", f_lines}, + {"read", f_read}, + {"seek", f_seek}, + {"setvbuf", f_setvbuf}, + {"write", f_write}, + {"__gc", f_gc}, + {"__tostring", f_tostring}, + {NULL, NULL} +}; + + +static void createmeta (lua_State *L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ + lua_pop(L, 1); /* pop new metatable */ +} + + +/* +** function to (not) close the standard files stdin, stdout, and stderr +*/ +static int io_noclose (lua_State *L) { + LStream *p = tolstream(L); + p->closef = &io_noclose; /* keep file opened */ + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; +} + + +static void createstdfile (lua_State *L, FILE *f, const char *k, + const char *fname) { + LStream *p = newprefile(L); + p->f = f; + p->closef = &io_noclose; + if (k != NULL) { + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ + } + lua_setfield(L, -2, fname); /* add file to module */ +} + + +LUAMOD_API int luaopen_io (lua_State *L) { + luaL_newlib(L, iolib); /* new module */ + createmeta(L); + /* create (and set) default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, NULL, "stderr"); + return 1; +} + diff --git a/lib/compat53/lprefix.h b/lib/compat53/lprefix.h new file mode 100644 index 0000000..0f83906 --- /dev/null +++ b/lib/compat53/lprefix.h @@ -0,0 +1,282 @@ +/* +** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + + +/* COMPAT53 adaptation */ +#include "c-api/compat-5.3.h" + +#undef LUAMOD_API +#define LUAMOD_API extern + + +#ifdef lutf8lib_c +# define luaopen_utf8 luaopen_compat53_utf8 +/* we don't support the %U format string of lua_pushfstring! + * code below adapted from the Lua 5.3 sources: + */ +static const char *compat53_utf8_escape (lua_State* L, long x) { + if (x < 0x80) { /* ASCII */ + char c = (char)x; + lua_pushlstring(L, &c, 1); + } else { + char buff[8] = { 0 }; + unsigned int mfb = 0x3f; + int n = 1; + do { + buff[8 - (n++)] = (char)(0x80|(x & 0x3f)); + x >>= 6; + mfb >>= 1; + } while (x > mfb); + buff[8-n] = (char)((~mfb << 1) | x); + lua_pushlstring(L, buff+8-n, n); + } + return lua_tostring(L, -1); +} +# define lua_pushfstring(L, fmt, l) \ + compat53_utf8_escape(L, l) +#endif + + +#ifdef ltablib_c +# define luaopen_table luaopen_compat53_table +# ifndef LUA_MAXINTEGER +/* conservative estimate: */ +# define LUA_MAXINTEGER INT_MAX +# endif +#endif /* ltablib_c */ + + +#ifdef lstrlib_c +#include +#include +/* move the string library open function out of the way (we only take + * the string packing functions)! + */ +# define luaopen_string luaopen_string_XXX +/* used in string.format implementation, which we don't use: */ +# ifndef LUA_INTEGER_FRMLEN +# define LUA_INTEGER_FRMLEN "" +# define LUA_NUMBER_FRMLEN "" +# endif +# ifndef LUA_MININTEGER +# define LUA_MININTEGER 0 +# endif +# ifndef LUA_INTEGER_FMT +# define LUA_INTEGER_FMT "%d" +# endif +# ifndef LUAI_UACINT +# define LUAI_UACINT lua_Integer +# endif +/* different Lua 5.3 versions have conflicting variants of this macro + * in luaconf.h, there's a fallback implementation in lstrlib.c, and + * the macro isn't used for string (un)packing anyway! + * */ +# undef lua_number2strx +# if LUA_VERSION_NUM < 503 +/* lstrlib assumes that lua_Integer and lua_Unsigned have the same + * size, so we use the unsigned equivalent of ptrdiff_t! */ +# define lua_Unsigned size_t +# endif +# ifndef l_mathlim +# ifdef LUA_NUMBER_DOUBLE +# define l_mathlim(n) (DBL_##n) +# else +# define l_mathlim(n) (FLT_##n) +# endif +# endif +# ifndef l_mathop +# ifdef LUA_NUMBER_DOUBLE +# define l_mathop(op) op +# else +# define l_mathop(op) op##f +# endif +# endif +# ifndef lua_getlocaledecpoint +# define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +# endif +# ifndef l_sprintf +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define l_sprintf(s,sz,f,i) (snprintf(s, sz, f, i)) +# else +# define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s, f, i)) +# endif +# endif + +static int str_pack (lua_State *L); +static int str_packsize (lua_State *L); +static int str_unpack (lua_State *L); +LUAMOD_API int luaopen_compat53_string (lua_State *L) { + luaL_Reg const funcs[] = { + { "pack", str_pack }, + { "packsize", str_packsize }, + { "unpack", str_unpack }, + { NULL, NULL } + }; + luaL_newlib(L, funcs); + return 1; +} +/* fake CLANG feature detection on other compilers */ +# ifndef __has_attribute +# define __has_attribute(x) 0 +# endif +/* make luaopen_string(_XXX) static, so it (and all other referenced + * string functions) won't be included in the resulting dll + * (hopefully). + */ +# undef LUAMOD_API +# if defined(__GNUC__) || __has_attribute(__unused__) +# define LUAMOD_API __attribute__((__unused__)) static +# else +# define LUAMOD_API static +# endif +#endif /* lstrlib.c */ + +#endif + + +#ifdef liolib_c +/* move the io library open function out of the way (we only take + * the popen and type functions)! + */ +# define luaopen_io luaopen_io_XXX + +#include +#include + +# if !defined(lua_getlocaledecpoint) +# define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +# endif + +# ifndef LUA_INTEGER_FMT +# define LUA_INTEGER_FMT "%ld" +# endif +# ifndef LUAI_UACINT +# define LUAI_UACINT lua_Integer +# endif + +/* choose which popen implementation to pick */ +# if (defined(_WIN32) && !defined(__CYGWIN__)) +# define LUA_USE_WINDOWS 1 +# endif +# if (!defined(LUA_USE_WINDOWS) && !defined(LUA_USE_POSIX)) && \ + ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || \ + defined(__APPLE__)) +# define LUA_USE_POSIX 1 +# endif + +typedef struct COMPAT53_luaL_Stream { + FILE *f; /* stream (NULL for incompletely created streams) */ + lua_CFunction closef; /* to close stream (NULL for closed streams) */ +} COMPAT53_luaL_Stream; + +#define luaL_Stream COMPAT53_luaL_Stream + +#define COMPAT53_LUA_PFILEHANDLE "PFILE*" + +static int io_ptype (lua_State *L) { + luaL_Stream *p; + luaL_checkany(L, 1); + p = (luaL_Stream *)luaL_testudata(L, 1, COMPAT53_LUA_PFILEHANDLE); + if (p) { + /* Lua 5.3 implementation, for popen files */ + if (p->closef == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; + } else { + /* Lua 5.1 implementation, for plain files */ + void *ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) + lua_pushnil(L); /* not a file */ + else if (*((FILE **)ud) == NULL) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; + } +} + +static int io_popen (lua_State *L); +static void createmeta (lua_State *L); + +# undef LUA_FILEHANDLE +# define LUA_FILEHANDLE COMPAT53_LUA_PFILEHANDLE + +LUAMOD_API int luaopen_compat53_io (lua_State *L) { + luaL_Reg const funcs[] = { + +/* for PUC-Rio Lua 5.1 only */ +# if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 && !defined(LUA_JITLIBNAME) + + { "popen", io_popen }, + { "type", io_ptype }, + +# endif /* for PUC-Rio Lua 5.1 only */ + + { NULL, NULL } + }; + luaL_newlib(L, funcs); + createmeta(L); + return 1; +} + + +/* fake CLANG feature detection on other compilers */ +# ifndef __has_attribute +# define __has_attribute(x) 0 +# endif +/* make luaopen_io(_XXX) static, so it (and all other referenced + * io functions) won't be included in the resulting dll + * (hopefully). + */ +# undef LUAMOD_API +# if defined(__GNUC__) || __has_attribute(__unused__) +# define LUAMOD_API __attribute__((__unused__)) static +# else +# define LUAMOD_API static +# endif + +#endif /* iolib.c */ diff --git a/lib/compat53/lstrlib.c b/lib/compat53/lstrlib.c new file mode 100644 index 0000000..b4bed7e --- /dev/null +++ b/lib/compat53/lstrlib.c @@ -0,0 +1,1584 @@ +/* +** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** maximum number of captures that a pattern can do during +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. +*/ +#if !defined(LUA_MAXCAPTURES) +#define LUA_MAXCAPTURES 32 +#endif + + +/* macro to 'unsign' a character */ +#define uchar(c) ((unsigned char)(c)) + + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + + +static int str_len (lua_State *L) { + size_t l; + luaL_checklstring(L, 1, &l); + lua_pushinteger(L, (lua_Integer)l); + return 1; +} + + +/* translate a relative string position: negative means back from end */ +static lua_Integer posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +static int str_sub (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); + lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (lua_Integer)l) end = l; + if (start <= end) + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); + else lua_pushliteral(L, ""); + return 1; +} + + +static int str_reverse (lua_State *L) { + size_t l, i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); + return 1; +} + + +static int str_lower (lua_State *L) { + size_t l; + size_t i; + luaL_Buffer b; + const char *s = luaL_checklstring(L, 1, &l); + char *p = luaL_buffinitsize(L, &b, l); + for (i=0; i MAXSIZE / n) /* may overflow? */ + return luaL_error(L, "resulting string too large"); + else { + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, totallen); + while (n-- > 1) { /* first n-1 copies (followed by separator) */ + memcpy(p, s, l * sizeof(char)); p += l; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; + } + } + memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ + luaL_pushresultsize(&b, totallen); + } + return 1; +} + + +static int str_byte (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); + lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi < 1) posi = 1; + if (pose > (lua_Integer)l) pose = l; + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* arithmetic overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) + return luaL_error(ms->L, "invalid capture index %%%d", l + 1); + return l; +} + + +static int capture_to_close (MatchState *ms) { + int level = ms->level; + for (level--; level>=0; level--) + if (ms->capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms->L, "invalid pattern capture"); +} + + +static const char *classend (MatchState *ms, const char *p) { + switch (*p++) { + case L_ESC: { + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (ends with '%%')"); + return p+1; + } + case '[': { + if (*p == '^') p++; + do { /* look for a ']' */ + if (p == ms->p_end) + luaL_error(ms->L, "malformed pattern (missing ']')"); + if (*(p++) == L_ESC && p < ms->p_end) + p++; /* skip escapes (e.g. '%]') */ + } while (*p != ']'); + return p+1; + } + default: { + return p; + } + } +} + + +static int match_class (int c, int cl) { + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'g' : res = isgraph(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit(c); break; + case 'z' : res = (c == 0); break; /* deprecated option */ + default: return (cl == c); + } + return (islower(cl) ? res : !res); +} + + +static int matchbracketclass (int c, const char *p, const char *ec) { + int sig = 1; + if (*(p+1) == '^') { + sig = 0; + p++; /* skip the '^' */ + } + while (++p < ec) { + if (*p == L_ESC) { + p++; + if (match_class(c, uchar(*p))) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < ec)) { + p+=2; + if (uchar(*(p-2)) <= c && c <= uchar(*p)) + return sig; + } + else if (uchar(*p) == c) return sig; + } + return !sig; +} + + +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } + } +} + + +static const char *matchbalance (MatchState *ms, const char *s, + const char *p) { + if (p >= ms->p_end - 1) + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); + if (*s != *p) return NULL; + else { + int b = *p; + int e = *(p+1); + int cont = 1; + while (++s < ms->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static const char *max_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while (singlematch(ms, s + i, p, ep)) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + const char *res = match(ms, (s+i), ep+1); + if (res) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return NULL; +} + + +static const char *min_expand (MatchState *ms, const char *s, + const char *p, const char *ep) { + for (;;) { + const char *res = match(ms, s, ep+1); + if (res != NULL) + return res; + else if (singlematch(ms, s, p, ep)) + s++; /* try with one more repetition */ + else return NULL; + } +} + + +static const char *start_capture (MatchState *ms, const char *s, + const char *p, int what) { + const char *res; + int level = ms->level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); + ms->capture[level].init = s; + ms->capture[level].len = what; + ms->level = level+1; + if ((res=match(ms, s, p)) == NULL) /* match failed? */ + ms->level--; /* undo capture */ + return res; +} + + +static const char *end_capture (MatchState *ms, const char *s, + const char *p) { + int l = capture_to_close(ms); + const char *res; + ms->capture[l].len = s - ms->capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == NULL) /* match failed? */ + ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; +} + + +static const char *match_capture (MatchState *ms, const char *s, int l) { + size_t len; + l = check_capture(ms, l); + len = ms->capture[l].len; + if ((size_t)(ms->src_end-s) >= len && + memcmp(ms->capture[l].init, s, len) == 0) + return s+len; + else return NULL; +} + + +static const char *match (MatchState *ms, const char *s, const char *p) { + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); + init: /* using goto's to optimize tail recursion */ + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; + } + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; + } + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ + } + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* FALLTHROUGH */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } + } + break; + } + } + } + ms->matchdepth++; + return s; +} + + + +static const char *lmemfind (const char *s1, size_t l1, + const char *s2, size_t l2) { + if (l2 == 0) return s1; /* empty strings are everywhere */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ + else { + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ + while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { + init++; /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct 'l1' and 's1' to try again */ + l1 -= init-s1; + s1 = init; + } + } + return NULL; /* not found */ + } +} + + +static void push_onecapture (MatchState *ms, int i, const char *s, + const char *e) { + if (i >= ms->level) { + if (i == 0) /* ms->level == 0, too */ + lua_pushlstring(ms->L, s, e - s); /* add whole match */ + else + luaL_error(ms->L, "invalid capture index %%%d", i + 1); + } + else { + ptrdiff_t l = ms->capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); + else + lua_pushlstring(ms->L, ms->capture[i].init, l); + } +} + + +static int push_captures (MatchState *ms, const char *s, const char *e) { + int i; + int nlevels = (ms->level == 0 && s) ? 1 : ms->level; + luaL_checkstack(ms->L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ +} + + +/* check whether pattern has no special characters */ +static int nospecials (const char *p, size_t l) { + size_t upto = 0; + do { + if (strpbrk(p + upto, SPECIALS)) + return 0; /* pattern has a special character */ + upto += strlen(p + upto) + 1; /* may have more after \0 */ + } while (upto <= l); + return 1; /* no special chars found */ +} + + +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + +static int str_find_aux (lua_State *L, int find) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); + if (init < 1) init = 1; + else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ + lua_pushnil(L); /* cannot find anything */ + return 1; + } + /* explicit request or no special characters? */ + if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { + /* do a plain search */ + const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); + if (s2) { + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); + return 2; + } + } + else { + MatchState ms; + const char *s1 = s + init - 1; + int anchor = (*p == '^'); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, s, ls, p, lp); + do { + const char *res; + reprepstate(&ms); + if ((res=match(&ms, s1, p)) != NULL) { + if (find) { + lua_pushinteger(L, (s1 - s) + 1); /* start */ + lua_pushinteger(L, res - s); /* end */ + return push_captures(&ms, NULL, 0) + 2; + } + else + return push_captures(&ms, s1, res); + } + } while (s1++ < ms.src_end && !anchor); + } + lua_pushnil(L); /* not found */ + return 1; +} + + +static int str_find (lua_State *L) { + return str_find_aux(L, 1); +} + + +static int str_match (lua_State *L) { + return str_find_aux(L, 0); +} + + +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ + MatchState ms; /* match state */ +} GMatchState; + + +static int gmatch_aux (lua_State *L) { + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); + const char *src; + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { + const char *e; + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); + } + } + return 0; /* not found */ +} + + +static int gmatch (lua_State *L) { + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + GMatchState *gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; gm->p = p; gm->lastmatch = NULL; + lua_pushcclosure(L, gmatch_aux, 3); + return 1; +} + + +static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e) { + size_t l, i; + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit(uchar(news[i]))) { + if (news[i] != L_ESC) + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); + luaL_addchar(b, news[i]); + } + else if (news[i] == '0') + luaL_addlstring(b, s, e - s); + else { + push_onecapture(ms, news[i] - '1', s, e); + luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ + lua_remove(L, -2); /* remove original value */ + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } +} + + +static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, + const char *e, int tr) { + lua_State *L = ms->L; + switch (tr) { + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + default: { /* LUA_TNUMBER or LUA_TSTRING */ + add_s(ms, b, s, e); + return; + } + } + if (!lua_toboolean(L, -1)) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, e - s); /* keep original text */ + } + else if (!lua_isstring(L, -1)) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ +} + + +static int str_gsub (lua_State *L) { + size_t srcl, lp; + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ + int anchor = (*p == '^'); + lua_Integer n = 0; /* replacement count */ + MatchState ms; + luaL_Buffer b; + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, + "string/function/table expected"); + luaL_buffinit(L, &b); + if (anchor) { + p++; lp--; /* skip anchor character */ + } + prepstate(&ms, L, src, srcl, p, lp); + while (n < max_s) { + const char *e; + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ + n++; + add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ + src = lastmatch = e; + } + else if (src < ms.src_end) /* otherwise, skip one character */ + luaL_addchar(&b, *src++); + else break; /* end of subject */ + if (anchor) break; + } + luaL_addlstring(&b, src, ms.src_end-src); + luaL_pushresult(&b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** STRING FORMAT +** ======================================================= +*/ + +#if !defined(lua_number2strx) /* { */ + +/* +** Hexadecimal floating-point formatter +*/ + +#include + +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) + + +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) + + +/* +** Add integer part of 'x' to buffer and return new 'x' +*/ +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} + + +static int num2straux (char *buff, int sz, lua_Number x) { + /* if 'inf' or 'NaN', format it like '%g' */ + if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) + return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size of each formatted item. This maximum size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra +** expenses", such as locale-dependent stuff) +*/ +#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) + + +/* valid flags in a format specification */ +#define FLAGS "-+ #0" + +/* +** maximum size of each format specification (such as "%-099.99d") +*/ +#define MAX_FORMAT 32 + + +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { + luaL_addchar(b, '"'); + while (len--) { + if (*s == '"' || *s == '\\' || *s == '\n') { + luaL_addchar(b, '\\'); + luaL_addchar(b, *s); + } + else if (iscntrl(uchar(*s))) { + char buff[10]; + if (!isdigit(uchar(*(s+1)))) + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); + else + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); + luaL_addstring(b, buff); + } + else + luaL_addchar(b, *s); + s++; + } + luaL_addchar(b, '"'); +} + + +/* +** Ensures the 'buff' string uses a dot as the radix character. +*/ +static void checkdp (char *buff, int nb) { + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = (char *)memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } +} + + +static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { + switch (lua_type(L, arg)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: { + char *buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) { /* float? */ + lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); + checkdp(buff, nb); /* ensure it uses a dot */ + } + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: { + luaL_argerror(L, arg, "value has no literal form"); + } + } +} + + +static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { + const char *p = strfrmt; + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ + if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit(uchar(*p))) p++; /* skip width */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + if (*p == '.') { + p++; + if (isdigit(uchar(*p))) p++; /* skip precision */ + if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ + } + if (isdigit(uchar(*p))) + luaL_error(L, "invalid format (width or precision too long)"); + *(form++) = '%'; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; + *form = '\0'; + return p; +} + + +/* +** add length modifier into formats +*/ +static void addlenmod (char *form, const char *lenmod) { + size_t l = strlen(form); + size_t lm = strlen(lenmod); + char spec = form[l - 1]; + strcpy(form + l - 1, lenmod); + form[l + lm - 1] = spec; + form[l + lm] = '\0'; +} + + +static int str_format (lua_State *L) { + int top = lua_gettop(L); + int arg = 1; + size_t sfl; + const char *strfrmt = luaL_checklstring(L, arg, &sfl); + const char *strfrmt_end = strfrmt+sfl; + luaL_Buffer b; + luaL_buffinit(L, &b); + while (strfrmt < strfrmt_end) { + if (*strfrmt != L_ESC) + luaL_addchar(&b, *strfrmt++); + else if (*++strfrmt == L_ESC) + luaL_addchar(&b, *strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ + if (++arg > top) + luaL_argerror(L, arg, "no value"); + strfrmt = scanformat(L, strfrmt, form); + switch (*strfrmt++) { + case 'c': { + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); + break; + } + case 'd': case 'i': + case 'o': case 'u': case 'x': case 'X': { + lua_Integer n = luaL_checkinteger(L, arg); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); + break; + } + case 'a': case 'A': + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; + case 'e': case 'E': case 'f': + case 'g': case 'G': { + lua_Number n = luaL_checknumber(L, arg); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); + break; + } + case 'q': { + addliteral(L, &b, arg); + break; + } + case 's': { + size_t l; + const char *s = luaL_tolstring(L, arg, &l); + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ + else { + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } + } + break; + } + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid option '%%%c' to 'format'", + *(strfrmt - 1)); + } + } + lua_assert(nb < MAX_ITEM); + luaL_addsize(&b, nb); + } + } + luaL_pushresult(&b); + return 1; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* dummy structure to get native alignment requirements */ +struct cD { + char c; + union { double d; void *p; lua_Integer i; lua_Number n; } u; +}; + +#define MAXALIGN (offsetof(struct cD, u)) + + +/* +** Union for serializing floats +*/ +typedef union Ftypes { + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +} Ftypes; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'd': *size = sizeof(double); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (volatile char *dest, volatile const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) { + while (size-- != 0) + *(dest++) = *(src++); + } + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* floating-point options */ + volatile Ftypes u; + char *buff = luaL_prepbuffsize(&b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + +static const luaL_Reg strlib[] = { + {"byte", str_byte}, + {"char", str_char}, + {"dump", str_dump}, + {"find", str_find}, + {"format", str_format}, + {"gmatch", gmatch}, + {"gsub", str_gsub}, + {"len", str_len}, + {"lower", str_lower}, + {"match", str_match}, + {"rep", str_rep}, + {"reverse", str_reverse}, + {"sub", str_sub}, + {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, + {NULL, NULL} +}; + + +static void createmetatable (lua_State *L) { + lua_createtable(L, 0, 1); /* table to be metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); /* copy table */ + lua_setmetatable(L, -2); /* set table as metatable for strings */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* get string library */ + lua_setfield(L, -2, "__index"); /* metatable.__index = string */ + lua_pop(L, 1); /* pop metatable */ +} + + +/* +** Open string library +*/ +LUAMOD_API int luaopen_string (lua_State *L) { + luaL_newlib(L, strlib); + createmetatable(L); + return 1; +} + diff --git a/lib/compat53/ltablib.c b/lib/compat53/ltablib.c new file mode 100644 index 0000000..c534957 --- /dev/null +++ b/lib/compat53/ltablib.c @@ -0,0 +1,450 @@ +/* +** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ +** Library for Table Manipulation +** See Copyright Notice in lua.h +*/ + +#define ltablib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } +} + + +#if defined(LUA_COMPAT_MAXN) +static int maxn (lua_State *L) { + lua_Number max = 0; + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushnil(L); /* first key */ + while (lua_next(L, 1)) { + lua_pop(L, 1); /* remove value */ + if (lua_type(L, -1) == LUA_TNUMBER) { + lua_Number v = lua_tonumber(L, -1); + if (v > max) max = v; + } + } + lua_pushnumber(L, max); + return 1; +} +#endif + + +static int tinsert (lua_State *L) { + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ + lua_Integer pos; /* where to insert new element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); + for (i = e; i > pos; i--) { /* move up elements */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to 'insert'"); + } + } + lua_seti(L, 1, pos); /* t[pos] = v */ + return 0; +} + + +static int tremove (lua_State *L) { + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); + lua_geti(L, 1, pos); /* result = t[pos] */ + for ( ; pos < size; pos++) { + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ + } + lua_pushnil(L); + lua_seti(L, 1, pos); /* t[pos] = nil */ + return 1; +} + + +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +static int tmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); + if (!lua_isstring(L, -1)) + luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", + luaL_typename(L, -1), i); + luaL_addvalue(b); +} + + +static int tconcat (lua_State *L) { + luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); + size_t lsep; + const char *sep = luaL_optlstring(L, 2, "", &lsep); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); + luaL_buffinit(L, &b); + for (; i < last; i++) { + addfield(L, &b, i); + luaL_addlstring(&b, sep, lsep); + } + if (i == last) /* add last value (if interval was not empty) */ + addfield(L, &b, i); + luaL_pushresult(&b); + return 1; +} + + +/* +** {====================================================== +** Pack/unpack +** ======================================================= +*/ + +static int pack (lua_State *L) { + int i; + int n = lua_gettop(L); /* number of elements to pack */ + lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); + lua_pushinteger(L, n); + lua_setfield(L, 1, "n"); /* t.n = number of elements */ + return 1; /* return table */ +} + + +static int unpack (lua_State *L) { + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); + if (i > e) return 0; /* empty range */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) + return luaL_error(L, "too many results to unpack"); + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Quicksort +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; +** Addison-Wesley, 1993.) +** ======================================================= +*/ + + +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; +} + +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ +static int sort_comp (lua_State *L, int a, int b) { + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ + int res; + lua_pushvalue(L, 2); /* push function */ + lua_pushvalue(L, a-1); /* -1 to compensate function */ + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ + return res; + } +} + + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** QuickSort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ + else + lua_pop(L, 2); /* remove both values */ + if (up - lo == 1) /* only 2 elements? */ + return; /* already sorted */ + if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ + p = (lo + up)/2; /* middle element is a good pivot */ + else /* for larger intervals, it is worth a random pivot */ + p = choosePivot(lo, up, rnd); + lua_geti(L, 1, p); + lua_geti(L, 1, lo); + if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ + set2(L, p, lo); /* swap a[p] - a[lo] */ + else { + lua_pop(L, 1); /* remove a[lo] */ + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ + set2(L, p, up); /* swap a[up] - a[p] */ + else + lua_pop(L, 2); + } + if (up - lo == 2) /* only 3 elements? */ + return; /* already sorted */ + lua_geti(L, 1, p); /* get middle element (Pivot) */ + lua_pushvalue(L, -1); /* push Pivot */ + lua_geti(L, 1, up - 1); /* push a[up - 1] */ + set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ + p = partition(L, lo, up); + /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ + if (p - lo < up - p) { /* lower interval is smaller? */ + auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ + n = p - lo; /* size of smaller interval */ + lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ + } + else { + auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ + n = up - p; /* size of smaller interval */ + up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ + } + if ((up - lo) / 128 > n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ +} + + +static int sort (lua_State *L) { + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } + return 0; +} + +/* }====================================================== */ + + +static const luaL_Reg tab_funcs[] = { + {"concat", tconcat}, +#if defined(LUA_COMPAT_MAXN) + {"maxn", maxn}, +#endif + {"insert", tinsert}, + {"pack", pack}, + {"unpack", unpack}, + {"remove", tremove}, + {"move", tmove}, + {"sort", sort}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_table (lua_State *L) { + luaL_newlib(L, tab_funcs); +#if defined(LUA_COMPAT_UNPACK) + /* _G.unpack = table.unpack */ + lua_getfield(L, -1, "unpack"); + lua_setglobal(L, "unpack"); +#endif + return 1; +} + diff --git a/lib/compat53/lutf8lib.c b/lib/compat53/lutf8lib.c new file mode 100644 index 0000000..10bd238 --- /dev/null +++ b/lib/compat53/lutf8lib.c @@ -0,0 +1,256 @@ +/* +** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +#define MAXUNICODE 0x10FFFF + +#define iscont(p) ((*(p) & 0xC0) == 0x80) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. +*/ +static const char *utf8_decode (const char *o, int *val) { + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + const unsigned char *s = (const unsigned char *)o; + unsigned int c = s[0]; + unsigned int res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + while (c & 0x40) { /* still have continuation bytes? */ + int cc = s[++count]; /* read next byte */ + if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + c <<= 1; /* to test next bit */ + } + res |= ((c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 3 || res > MAXUNICODE || res <= limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (val) *val = res; + return (const char *)s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j]]) --> number of characters that start in the +** range [i,j], or nil + current position if 's' is not well formed in +** that interval +*/ +static int utflen (lua_State *L) { + int n = 0; + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of string"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of string"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL); + if (s1 == NULL) { /* conversion error? */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j]]) -> returns codepoints for all characters +** that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of range"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + n = 0; + se = s + pose; + for (s += posi - 1; s < se;) { + int code; + s = utf8_decode(s, &code); + if (s == NULL) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Integer code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of range"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscont(s + posi)) posi--; + } + else { + if (iscont(s + posi)) + return luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscont(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscont(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + lua_pushnil(L); + return 1; +} + + +static int iter_aux (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = lua_tointeger(L, 2) - 1; + if (n < 0) /* first iteration? */ + n = 0; /* start from here */ + else if (n < (lua_Integer)len) { + n++; /* skip current byte */ + while (iscont(s + n)) n++; /* and its continuations */ + } + if (n >= (lua_Integer)len) + return 0; /* no more codepoints */ + else { + int code; + const char *next = utf8_decode(s + n, &code); + if (next == NULL || iscont(next)) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_codes (lua_State *L) { + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/lib/compat53/rockspecs/bit32-5.3.5-1.rockspec b/lib/compat53/rockspecs/bit32-5.3.5-1.rockspec new file mode 100644 index 0000000..353e19c --- /dev/null +++ b/lib/compat53/rockspecs/bit32-5.3.5-1.rockspec @@ -0,0 +1,28 @@ +package = "bit32" +version = "5.3.5-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.9.zip", + dir = "lua-compat-5.3-0.9", +} +description = { + summary = "Lua 5.2 bit manipulation library", + detailed = [[ + bit32 is the native Lua 5.2 bit manipulation library, in the version + from Lua 5.3; it is compatible with Lua 5.1, 5.2 and 5.3. + ]], + homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" +} +build = { + type = "builtin", + modules = { + bit32 = { + sources = { "lbitlib.c" }, + defines = { "LUA_COMPAT_BITLIB" }, + incdirs = { "c-api" }, + } + } +} diff --git a/lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec b/lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec new file mode 100644 index 0000000..371f1ae --- /dev/null +++ b/lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec @@ -0,0 +1,28 @@ +package = "bit32" +version = "5.3.5.1-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.10.zip", + dir = "lua-compat-5.3-0.10", +} +description = { + summary = "Lua 5.2 bit manipulation library", + detailed = [[ + bit32 is the native Lua 5.2 bit manipulation library, in the version + from Lua 5.3; it is compatible with Lua 5.1, 5.2, 5.3 and 5.4. + ]], + homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" +} +build = { + type = "builtin", + modules = { + bit32 = { + sources = { "lbitlib.c" }, + defines = { "LUA_COMPAT_BITLIB" }, + incdirs = { "c-api" }, + } + } +} diff --git a/lib/compat53/rockspecs/bit32-scm-1.rockspec b/lib/compat53/rockspecs/bit32-scm-1.rockspec new file mode 100644 index 0000000..78f9736 --- /dev/null +++ b/lib/compat53/rockspecs/bit32-scm-1.rockspec @@ -0,0 +1,28 @@ +package = "bit32" +version = "scm-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/master.zip", + dir = "lua-compat-5.3-master", +} +description = { + summary = "Lua 5.2 bit manipulation library", + detailed = [[ + bit32 is the native Lua 5.2 bit manipulation library, in the version + from Lua 5.3; it is compatible with Lua 5.1, 5.2 and 5.3. + ]], + homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" +} +build = { + type = "builtin", + modules = { + bit32 = { + sources = { "lbitlib.c" }, + defines = { "LUA_COMPAT_BITLIB" }, + incdirs = { "c-api" }, + } + } +} diff --git a/lib/compat53/rockspecs/compat53-0.1-1.rockspec b/lib/compat53/rockspecs/compat53-0.1-1.rockspec new file mode 100644 index 0000000..b9012fe --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.1-1.rockspec @@ -0,0 +1,31 @@ +package = "compat53" +version = "0.1-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.1.zip", + dir = "lua-compat-5.3-0.1", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53"] = "compat53.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.11-1.rockspec b/lib/compat53/rockspecs/compat53-0.11-1.rockspec new file mode 100644 index 0000000..9608f0a --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.11-1.rockspec @@ -0,0 +1,33 @@ +package = "compat53" +version = "0.11-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.11.zip", + dir = "lua-compat-5.3-0.11", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + ["compat53.io"] = "liolib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.12-1.rockspec b/lib/compat53/rockspecs/compat53-0.12-1.rockspec new file mode 100644 index 0000000..1b120ca --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.12-1.rockspec @@ -0,0 +1,33 @@ +package = "compat53" +version = "0.12-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.12.zip", + dir = "lua-compat-5.3-0.12", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + ["compat53.io"] = "liolib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.13-1.rockspec b/lib/compat53/rockspecs/compat53-0.13-1.rockspec new file mode 100644 index 0000000..f08dc66 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.13-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.13-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13.zip", + dir = "lua-compat-5.3-0.13" +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.io"] = "liolib.c", + ["compat53.module"] = "compat53/module.lua", + ["compat53.string"] = "lstrlib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.utf8"] = "lutf8lib.c" + } +} diff --git a/lib/compat53/rockspecs/compat53-0.14-1.rockspec b/lib/compat53/rockspecs/compat53-0.14-1.rockspec new file mode 100644 index 0000000..54ad4a9 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.14-1.rockspec @@ -0,0 +1,33 @@ +package = "compat53" +version = "0.14-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.zip", + dir = "lua-compat-5.3-0.14" +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.file_mt"] = "compat53/file_mt.lua", + ["compat53.init"] = "compat53/init.lua", + ["compat53.io"] = "liolib.c", + ["compat53.module"] = "compat53/module.lua", + ["compat53.string"] = "lstrlib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.utf8"] = "lutf8lib.c" + } +} diff --git a/lib/compat53/rockspecs/compat53-0.14.1-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.1-1.rockspec new file mode 100644 index 0000000..ea35bb2 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.14.1-1.rockspec @@ -0,0 +1,33 @@ +package = "compat53" +version = "0.14.1-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.1.zip", + dir = "lua-compat-5.3-0.14.1" +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.file_mt"] = "compat53/file_mt.lua", + ["compat53.init"] = "compat53/init.lua", + ["compat53.io"] = "liolib.c", + ["compat53.module"] = "compat53/module.lua", + ["compat53.string"] = "lstrlib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.utf8"] = "lutf8lib.c" + } +} diff --git a/lib/compat53/rockspecs/compat53-0.14.2-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.2-1.rockspec new file mode 100644 index 0000000..99236fe --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.14.2-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.14.2-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.2.zip", + dir = "lua-compat-5.3-0.14.2" +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" +} +build = { + type = "builtin", + modules = { + ["compat53.file_mt"] = "compat53/file_mt.lua", + ["compat53.init"] = "compat53/init.lua", + ["compat53.io"] = "liolib.c", + ["compat53.module"] = "compat53/module.lua", + ["compat53.string"] = "lstrlib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.utf8"] = "lutf8lib.c" + } +} diff --git a/lib/compat53/rockspecs/compat53-0.14.3-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.3-1.rockspec new file mode 100644 index 0000000..d6327d7 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.14.3-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.14.3-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.3.zip", + dir = "lua-compat-5.3-0.14.3" +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" +} +build = { + type = "builtin", + modules = { + ["compat53.file_mt"] = "compat53/file_mt.lua", + ["compat53.init"] = "compat53/init.lua", + ["compat53.io"] = "liolib.c", + ["compat53.module"] = "compat53/module.lua", + ["compat53.string"] = "lstrlib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.utf8"] = "lutf8lib.c" + } +} diff --git a/lib/compat53/rockspecs/compat53-0.14.4-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.4-1.rockspec new file mode 100644 index 0000000..804220f --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.14.4-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.14.4-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.4.zip", + dir = "lua-compat-5.3-0.14.4" +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5" +} +build = { + type = "builtin", + modules = { + ["compat53.file_mt"] = "compat53/file_mt.lua", + ["compat53.init"] = "compat53/init.lua", + ["compat53.io"] = "liolib.c", + ["compat53.module"] = "compat53/module.lua", + ["compat53.string"] = "lstrlib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.utf8"] = "lutf8lib.c" + } +} diff --git a/lib/compat53/rockspecs/compat53-0.2-1.rockspec b/lib/compat53/rockspecs/compat53-0.2-1.rockspec new file mode 100644 index 0000000..47ddaf2 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.2-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.2-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.2.zip", + dir = "lua-compat-5.3-0.2", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.3-1.rockspec b/lib/compat53/rockspecs/compat53-0.3-1.rockspec new file mode 100644 index 0000000..d99099f --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.3-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.3-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.3.zip", + dir = "lua-compat-5.3-0.3", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.4-1.rockspec b/lib/compat53/rockspecs/compat53-0.4-1.rockspec new file mode 100644 index 0000000..bc33826 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.4-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.4-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.4.zip", + dir = "lua-compat-5.3-0.4", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.5-1.rockspec b/lib/compat53/rockspecs/compat53-0.5-1.rockspec new file mode 100644 index 0000000..8d18b51 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.5-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.5-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.5.zip", + dir = "lua-compat-5.3-0.5", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.7-1.rockspec b/lib/compat53/rockspecs/compat53-0.7-1.rockspec new file mode 100644 index 0000000..fc5a0c8 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.7-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.7-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.7.zip", + dir = "lua-compat-5.3-0.7", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.4", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-0.8-1.rockspec b/lib/compat53/rockspecs/compat53-0.8-1.rockspec new file mode 100644 index 0000000..2fe47b9 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-0.8-1.rockspec @@ -0,0 +1,32 @@ +package = "compat53" +version = "0.8-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.8.zip", + dir = "lua-compat-5.3-0.8", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + } +} + diff --git a/lib/compat53/rockspecs/compat53-scm-1.rockspec b/lib/compat53/rockspecs/compat53-scm-1.rockspec new file mode 100644 index 0000000..b0581f9 --- /dev/null +++ b/lib/compat53/rockspecs/compat53-scm-1.rockspec @@ -0,0 +1,34 @@ +package = "compat53" +version = "scm-1" +source = { + url = "https://github.com/lunarmodules/lua-compat-5.3/archive/master.zip", + dir = "lua-compat-5.3-master", +} +description = { + summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", + detailed = [[ + This is a small module that aims to make it easier to write Lua + code in a Lua-5.3-style that runs on Lua 5.1+. + It does *not* make Lua 5.2 (or even 5.1) entirely compatible + with Lua 5.3, but it brings the API closer to that of Lua 5.3. + ]], + homepage = "https://github.com/lunarmodules/lua-compat-5.3", + license = "MIT" +} +dependencies = { + "lua >= 5.1, < 5.5", + --"struct" -- make Roberto's struct module optional +} +build = { + type = "builtin", + modules = { + ["compat53.init"] = "compat53/init.lua", + ["compat53.module"] = "compat53/module.lua", + ["compat53.file_mt"] = "compat53/file_mt.lua", + ["compat53.utf8"] = "lutf8lib.c", + ["compat53.table"] = "ltablib.c", + ["compat53.string"] = "lstrlib.c", + ["compat53.io"] = "liolib.c", + } +} + diff --git a/lib/compat53/tests/test-bit32.lua b/lib/compat53/tests/test-bit32.lua new file mode 100755 index 0000000..a408b7d --- /dev/null +++ b/lib/compat53/tests/test-bit32.lua @@ -0,0 +1,10 @@ +#!/usr/bin/env lua + +local bit32 = require("bit32") + + +assert(bit32.bnot(0) == 2^32-1) +assert(bit32.bnot(-1) == 0) +assert(bit32.band(1, 3, 5) == 1) +assert(bit32.bor(1, 3, 5) == 7) + diff --git a/lib/compat53/tests/test.lua b/lib/compat53/tests/test.lua new file mode 100755 index 0000000..503e3f4 --- /dev/null +++ b/lib/compat53/tests/test.lua @@ -0,0 +1,866 @@ +#!/usr/bin/env lua + +local F, tproxy, writefile, noprint, ___ +do + local type, unpack = type, table.unpack or unpack + local assert, io = assert, io + function F(...) + local args, n = { ... }, select('#', ...) + for i = 1, n do + local t = type(args[i]) + if t ~= "string" and t ~= "number" and t ~= "boolean" then + args[i] = t + end + end + return unpack(args, 1, n) + end + function tproxy(t) + return setmetatable({}, { + __index = t, + __newindex = t, + __len = function() return #t end, + }), t + end + function writefile(name, contents, bin) + local f = assert(io.open(name, bin and "wb" or "w")) + f:write(contents) + f:close() + end + function noprint() end + local sep = ("="):rep(70) + function ___() + print(sep) + end +end + +local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") +if jit then V = "jit" end + +local is_puclua51 = (_VERSION == "Lua 5.1" and not jit) + +local mode = "global" +if arg[1] == "module" then + mode = "module" +end +local self = arg[0] + +package.path = "../?.lua;../?/init.lua" +package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" +if mode == "module" then + print("testing Lua API using `compat53.module` ...") + _ENV = require("compat53.module") + if setfenv then setfenv(1, _ENV) end +else + print("testing Lua API using `compat53` ...") + require("compat53") +end + + +___'' +do + print("assert", F(pcall(assert, false))) + print("assert", F(pcall(assert, false, nil))) + print("assert", F(pcall(assert, false, "error msg"))) + print("assert", F(pcall(assert, nil, {}))) + print("assert", F(pcall(assert, 1, 2, 3))) +end + + +___'' +do + local t = setmetatable({}, { __index = { 1, false, "three" } }) + for i,v in ipairs(t) do + print("ipairs", i, v) + end +end + + +___'' +do + local p, t = tproxy{ "a", "b", "c" } + print("table.concat", table.concat(p)) + print("table.concat", table.concat(p, ",", 2)) + print("table.concat", table.concat(p, ".", 1, 2)) + print("table.concat", table.concat(t)) + print("table.concat", table.concat(t, ",", 2)) + print("table.concat", table.concat(t, ".", 1, 2)) +end + + +___'' +do + local p, t = tproxy{ "a", "b", "c" } + table.insert(p, "d") + print("table.insert", next(p), t[4]) + table.insert(p, 1, "z") + print("table.insert", next(p), t[1], t[2]) + table.insert(p, 2, "y") + print("table.insert", next(p), t[1], t[2], p[3]) + t = { "a", "b", "c" } + table.insert(t, "d") + print("table.insert", t[1], t[2], t[3], t[4]) + table.insert(t, 1, "z") + print("table.insert", t[1], t[2], t[3], t[4], t[5]) + table.insert(t, 2, "y") + print("table.insert", t[1], t[2], t[3], t[4], t[5]) +end + + +___'' +do + local ps, s = tproxy{ "a", "b", "c", "d" } + local pd, d = tproxy{ "A", "B", "C", "D" } + table.move(ps, 1, 4, 1, pd) + print("table.move", next(pd), d[1], d[2], d[3], d[4]) + pd, d = tproxy{ "A", "B", "C", "D" } + table.move(ps, 2, 4, 1, pd) + print("table.move", next(pd), d[1], d[2], d[3], d[4]) + pd, d = tproxy{ "A", "B", "C", "D" } + table.move(ps, 2, 3, 4, pd) + print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5]) + table.move(ps, 2, 4, 1) + print("table.move", next(ps), s[1], s[2], s[3], s[4]) + ps, s = tproxy{ "a", "b", "c", "d" } + table.move(ps, 2, 3, 4) + print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5]) + s = { "a", "b", "c", "d" } + d = { "A", "B", "C", "D" } + table.move(s, 1, 4, 1, d) + print("table.move", d[1], d[2], d[3], d[4]) + d = { "A", "B", "C", "D" } + table.move(s, 2, 4, 1, d) + print("table.move", d[1], d[2], d[3], d[4]) + d = { "A", "B", "C", "D" } + table.move(s, 2, 3, 4, d) + print("table.move", d[1], d[2], d[3], d[4], d[5]) + table.move(s, 2, 4, 1) + print("table.move", s[1], s[2], s[3], s[4]) + s = { "a", "b", "c", "d" } + table.move(s, 2, 3, 4) + print("table.move", s[1], s[2], s[3], s[4], s[5]) +end + + +___'' +do + local p, t = tproxy{ "a", "b", "c", "d", "e" } + print("table.remove", table.remove(p)) + print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5]) + print("table.remove", table.remove(p, 1)) + print("table.remove", next(p), t[1], t[2], t[3], t[4]) + print("table.remove", table.remove(p, 2)) + print("table.remove", next(p), t[1], t[2], t[3]) + print("table.remove", table.remove(p, 3)) + print("table.remove", next(p), t[1], t[2], t[3]) + p, t = tproxy{} + print("table.remove", table.remove(p)) + print("table.remove", next(p), next(t)) + t = { "a", "b", "c", "d", "e" } + print("table.remove", table.remove(t)) + print("table.remove", t[1], t[2], t[3], t[4], t[5]) + print("table.remove", table.remove(t, 1)) + print("table.remove", t[1], t[2], t[3], t[4]) + print("table.remove", table.remove(t, 2)) + print("table.remove", t[1], t[2], t[3]) + print("table.remove", table.remove(t, 3)) + print("table.remove", t[1], t[2], t[3]) + t = {} + print("table.remove", table.remove(t)) + print("table.remove", next(t)) +end + +___'' +do + local p, t = tproxy{ 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } + table.sort(p) + print("table.sort", next(p)) + for i,v in ipairs(t) do + print("table.sort", i, v) + end + table.sort(p) + print("table.sort", next(p)) + for i,v in ipairs(t) do + print("table.sort", i, v) + end + p, t = tproxy{ 9, 8, 7, 6, 5, 4, 3, 2, 1 } + table.sort(p) + print("table.sort", next(p)) + for i,v in ipairs(t) do + print("table.sort", i, v) + end + table.sort(p, function(a, b) return a > b end) + print("table.sort", next(p)) + for i,v in ipairs(t) do + print("table.sort", i, v) + end + p, t = tproxy{ 1, 1, 1, 1, 1 } + print("table.sort", next(p)) + for i,v in ipairs(t) do + print("table.sort", i, v) + end + t = { 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } + table.sort(t) + for i,v in ipairs(t) do + print("table.sort", i, v) + end + table.sort(t, function(a, b) return a > b end) + for i,v in ipairs(t) do + print("table.sort", i, v) + end +end + + +___'' +do + local p, t = tproxy{ "a", "b", "c" } + print("table.unpack", table.unpack(p)) + print("table.unpack", table.unpack(p, 2)) + print("table.unpack", table.unpack(p, 1, 2)) + print("table.unpack", table.unpack(t)) + print("table.unpack", table.unpack(t, 2)) + print("table.unpack", table.unpack(t, 1, 2)) +end + + +___'' +print("math.maxinteger", math.maxinteger+1 > math.maxinteger) +print("math.mininteger", math.mininteger-1 < math.mininteger) + + +___'' +print("math.tointeger", math.tointeger(0)) +print("math.tointeger", math.tointeger(math.pi)) +print("math.tointeger", math.tointeger("123")) +print("math.tointeger", math.tointeger("hello")) +print("math.tointeger", math.tointeger(math.maxinteger+2.0)) +print("math.tointeger", math.tointeger(math.mininteger*2.0)) + + +___'' +print("math.type", math.type(0)) +print("math.type", math.type(math.pi)) +print("math.type", math.type("hello")) + + +___'' +print("math.ult", math.ult(1, 2), math.ult(2, 1)) +print("math.ult", math.ult(-1, 2), math.ult(2, -1)) +print("math.ult", math.ult(-1, -2), math.ult(-2, -1)) +print("math.ult", pcall(math.ult, "x", 2)) +print("math.ult", pcall(math.ult, 1, 2.1)) +___'' + + +if utf8.len then + local unpack = table.unpack or unpack + local function utf8rt(s) + local t = { utf8.codepoint(s, 1, #s) } + local ps, cs = {}, {} + for p,c in utf8.codes(s) do + ps[#ps+1], cs[#cs+1] = p, c + end + print("utf8.codes", unpack(ps)) + print("utf8.codes", unpack(cs)) + print("utf8.codepoint", unpack(t)) + print("utf8.len", utf8.len(s), #t, #s) + print("utf8.char", utf8.char(unpack(t))) + end + utf8rt("äöüßÄÖÜ") + utf8rt("abcdefg") + ___'' + local s = "äöüßÄÖÜ" + print("utf8.offset", utf8.offset(s, 1, 1)) + print("utf8.offset", utf8.offset(s, 2, 1)) + print("utf8.offset", utf8.offset(s, 3, 1)) + print("utf8.offset", pcall(utf8.offset, s, 3, 2)) + print("utf8.offset", utf8.offset(s, 3, 3)) + print("utf8.offset", utf8.offset(s, -1, 7)) + print("utf8.offset", utf8.offset(s, -2, 7)) + print("utf8.offset", utf8.offset(s, -3, 7)) + print("utf8.offset", utf8.offset(s, -1)) + ___'' +else + print("XXX: utf8 module not available") +end + + +if string.pack then + local format = "bBhHlLjJdc3z" + local s = string.pack(format, -128, 255, -32768, 65535, -2147483648, 4294967295, -32768, 65536, 1.25, "abc", "defgh") + print("string.unpack", string.unpack(format, s)) + ___'' +else + print("XXX: string packing not available") +end + + +print("testing Lua API for Lua 5.1 ...") + +___'' +print("debug.getuservalue()", F(debug.getuservalue(false))) +print("debug.setuservalue()", pcall(function() + debug.setuservalue(false, {}) +end)) +print("debug.setmetatable()", F(debug.setmetatable({}, {}))) + + +___'' +do + local t = setmetatable({}, { + __pairs = function() return pairs({ a = "a" }) end, + }) + for k,v in pairs(t) do + print("pairs()", k, v) + end +end + + +___'' +do + local code = "print('hello world')\n" + local badcode = "print('blub\n" + print("load()", pcall(function() load(true) end)) + print("load()", F(load(badcode))) + print("load()", F(load(code))) + print("load()", F(load(code, "[L]"))) + print("load()", F(load(code, "[L]", "b"))) + print("load()", F(load(code, "[L]", "t"))) + print("load()", F(load(code, "[L]", "bt"))) + local f = load(code, "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(code, "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + local bytecode = string.dump(f) + print("load()", F(load(bytecode))) + print("load()", F(load(bytecode, "[L]"))) + print("load()", F(load(bytecode, "[L]", "b"))) + print("load()", F(load(bytecode, "[L]", "t"))) + print("load()", F(load(bytecode, "[L]", "bt"))) + f = load(bytecode, "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(bytecode, "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + local function make_loader(code) + local mid = math.floor( #code/2 ) + local array = { code:sub(1, mid), code:sub(mid+1) } + local i = 0 + return function() + i = i + 1 + return array[i] + end + end + print("load()", F(load(make_loader(badcode)))) + print("load()", F(load(make_loader(code)))) + print("load()", F(load(make_loader(code), "[L]"))) + print("load()", F(load(make_loader(code), "[L]", "b"))) + print("load()", F(load(make_loader(code), "[L]", "t"))) + print("load()", F(load(make_loader(code), "[L]", "bt"))) + f = load(make_loader(code), "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(make_loader(code), "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + print("load()", F(load(make_loader(bytecode)))) + print("load()", F(load(make_loader(bytecode), "[L]"))) + print("load()", F(load(make_loader(bytecode), "[L]", "b"))) + print("load()", F(load(make_loader(bytecode), "[L]", "t"))) + print("load()", F(load(make_loader(bytecode), "[L]", "bt"))) + f = load(make_loader(bytecode), "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(make_loader(bytecode), "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + writefile("good.lua", code) + writefile("bad.lua", badcode) + writefile("good.luac", bytecode, true) + print("loadfile()", F(loadfile("bad.lua"))) + print("loadfile()", F(loadfile("good.lua"))) + print("loadfile()", F(loadfile("good.lua", "b"))) + print("loadfile()", F(loadfile("good.lua", "t"))) + print("loadfile()", F(loadfile("good.lua", "bt"))) + f = loadfile("good.lua", "bt", {}) + print("loadfile()", pcall(f)) + f = loadfile("good.lua", "bt", { print = noprint }) + print("loadfile()", pcall(f)) + print("loadfile()", F(loadfile("good.luac"))) + print("loadfile()", F(loadfile("good.luac", "b"))) + print("loadfile()", F(loadfile("good.luac", "t"))) + print("loadfile()", F(loadfile("good.luac", "bt"))) + f = loadfile("good.luac", "bt", {}) + print("loadfile()", pcall(f)) + f = loadfile("good.luac", "bt", { print = noprint }) + print("loadfile()", pcall(f)) + os.remove("good.lua") + os.remove("bad.lua") + os.remove("good.luac") +end + + +___'' +do + local function func(throw) + if throw then + error("argh") + else + return 1, 2, 3 + end + end + local function tb(err) return "|"..err.."|" end + print("xpcall()", xpcall(func, debug.traceback, false)) + print("xpcall()", xpcall(func, debug.traceback, true)) + print("xpcall()", xpcall(func, tb, true)) + if mode ~= "module" then + local function func2(cb) + print("xpcall()", xpcall(cb, debug.traceback, "str")) + end + local function func3(cb) + print("pcall()", pcall(cb, "str")) + end + local function cb(arg) + coroutine.yield(2) + return arg + end + local c = coroutine.wrap(func2) + print("xpcall()", c(cb)) + print("xpcall()", c()) + local c = coroutine.wrap(func3) + print("pcall()", c(cb)) + print("pcall()", c()) + end +end + + +___'' +do + local t = setmetatable({ 1 }, { __len = function() return 5 end }) + print("rawlen()", rawlen(t), rawlen("123")) +end + + +___'' +print("os.execute()", os.execute("exit 1")) +io.flush() +print("os.execute()", os.execute("echo 'hello world!'")) +io.flush() +print("os.execute()", os.execute("no_such_file")) + + +___'' +do + local t = table.pack("a", nil, "b", nil) + print("table.(un)pack()", t.n, table.unpack(t, 1, t.n)) +end + + +___'' +do + print("coroutine.running()", F(coroutine.wrap(function() + return coroutine.running() + end)())) + print("coroutine.running()", F(coroutine.running())) + local main_co, co1, co2 = coroutine.running() + -- coroutine.yield + if mode ~= "module" then + print("coroutine.yield()", pcall(function() + coroutine.yield(1, 2, 3) + end)) + end + print("coroutine.yield()", coroutine.wrap(function() + coroutine.yield(1, 2, 3) + end)()) + print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3)) + co1 = coroutine.create(function(a, b, c) + print("coroutine.resume()", a, b, c) + return a, b, c + end) + print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3)) + co1 = coroutine.create(function() + print("coroutine.status()", "[co1] main is", coroutine.status(main_co)) + print("coroutine.status()", "[co1] co2 is", coroutine.status(co2)) + end) + co2 = coroutine.create(function() + print("coroutine.status()", "[co2] main is", coroutine.status(main_co)) + print("coroutine.status()", "[co2] co2 is", coroutine.status(co2)) + coroutine.yield() + coroutine.resume(co1) + end) + print("coroutine.status()", coroutine.status(main_co)) + print("coroutine.status()", coroutine.status(co2)) + coroutine.resume(co2) + print("coroutine.status()", F(coroutine.status(co2))) + coroutine.resume(co2) + print("coroutine.status()", F(coroutine.status(co2))) +end + + +___'' +print("math.log()", math.log(1000)) +print("math.log()", math.log(1000, 10)) + + +___'' +do + local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" + print(prefix, package.searchpath("no.such.module", path)) + print(prefix, package.searchpath("no.such.module", "")) + print(prefix, package.searchpath("compat53", path)) + print(prefix, package.searchpath("no:such:module", path, ":", "|")) +end + + +___'' +if mode ~= "module" then + local function mod_func() return {} end + local function my_searcher(name) + if name == "my.module" then + print("package.searchers", "my.module found") + return mod_func + end + end + local function my_searcher2(name) + if name == "my.module" then + print("package.searchers", "my.module found 2") + return mod_func + end + end + table.insert(package.searchers, my_searcher) + require("my.module") + package.loaded["my.module"] = nil + local new_s = { my_searcher2 } + for i,f in ipairs(package.searchers) do + new_s[i+1] = f + end + package.searchers = new_s + require("my.module") +end + + +___'' +do + print("string.find()", string.find("abc\0abc\0abc", "[^a\0]+")) + print("string.find()", string.find("abc\0abc\0abc", "%w+\0", 5)) + for x in string.gmatch("abc\0def\0ghi", "[^\0]+") do + print("string.gmatch()", x) + end + for x in string.gmatch("abc\0def\0ghi", "%w*\0") do + print("string.gmatch()", #x) + end + print("string.gsub()", string.gsub("abc\0def\0ghi", "[\0]", "X")) + print("string.gsub()", string.gsub("abc\0def\0ghi", "%w*\0", "X")) + print("string.gsub()", string.gsub("abc\0def\0ghi", "%A", "X")) + print("string.match()", string.match("abc\0abc\0abc", "([^\0a]+)")) + print("string.match()", #string.match("abc\0abc\0abc", ".*\0")) + print("string.rep()", string.rep("a", 0)) + print("string.rep()", string.rep("b", 1)) + print("string.rep()", string.rep("c", 4)) + print("string.rep()", string.rep("a", 0, "|")) + print("string.rep()", string.rep("b", 1, "|")) + print("string.rep()", string.rep("c", 4, "|")) + local _tostring = tostring + function tostring(v) + if type(v) == "number" then + return "(".._tostring(v)..")" + else + return _tostring(v) + end + end + print("string.format()", string.format("%q", "\"\\\0000\0010\002\r\n0\t0\"")) + print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {})) + print("string.format()", string.format("%-3f %%%s %%s", 3.1, true)) + print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil)) + print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout)) + print("string.format()", pcall(function() + print("string.format()", string.format("%d %%s", {})) + end)) + tostring = _tostring +end + + +___'' +do + print("io.write()", io.type(io.write("hello world\n"))) + local f = assert(io.tmpfile()) + print("io.tmpfile => file:write()", io.type(f:write("hello world\n"))) + f:close() +end + + +___'' +do + writefile("data.txt", "123 18.8 hello world\ni'm here\n") + io.input("data.txt") + print("io.read()", io.read("*n", "*number", "*l", "*a")) + io.input("data.txt") + print("io.read()", io.read("n", "number", "l", "a")) + io.input(io.stdin) + if not is_puclua51 then + local f = assert(io.open("data.txt", "r")) + print("file:read()", f:read("*n", "*number", "*l", "*a")) + f:close() + f = assert(io.open("data.txt", "r")) + print("file:read()", f:read("n", "number", "l", "a")) + f:close() + os.remove("data.txt") + + local g = assert(io.open("data.txt", "w")) + print("io.open => file:write()", type(g:write("hello"))) + g:close() + end + os.remove("data.txt") +end + + +___'' +do + writefile("data.txt", "123 18.8 hello world\ni'm here\n") + for a,b in io.lines(self, 2, "*l") do + print("io.lines()", a, b) + break + end + for l in io.lines(self) do + print("io.lines()", l) + break + end + for n1,n2,rest in io.lines("data.txt", "*n", "n", "*a") do + print("io.lines()", n1, n2, rest) + end + for l in io.lines("data.txt") do + print("io.lines()", l) + end + print("io.lines()", pcall(function() + for l in io.lines("data.txt", "*x") do print(l) end + end)) + print("io.lines()", pcall(function() + for l in io.lines("no_such_file.txt") do print(l) end + end)) + if mode ~= "module" then + local f = assert(io.open(self, "r")) + print("io.type()", io.type(f)) + for a,b in f:lines(2, "*l") do + print("file:lines()", a, b) + break + end + f:close() + print("io.type()", io.type(f)) + f = assert(io.open("data.txt", "r")) + for n1,n2,rest in f:lines("*n", "n", "*a") do + print("file:lines()", n1, n2, rest) + end + f:close() + f = assert(io.open("data.txt", "r")) + for l in f:lines() do + print("file:lines()", l) + end + f:close() + print("file:lines()", pcall(function() + for l in f:lines() do print(l) end + end)) + print("file:lines()", pcall(function() + local f = assert(io.open("data.txt", "r")) + for l in f:lines("*l", "*x") do print(l) end + f:close() + end)) + end + os.remove("data.txt") + print("io.popen()", pcall(function() + local f = assert(io.popen("echo 'hello' && exit 0", "r")) + print("io.popen()", f:read("*a")) + print("io.popen()", f:close()) + end)) + print("io.popen()", pcall(function() + local f = assert(io.popen("echo 'hello' && exit 5", "r")) + print("io.type()", io.type(f)) + print("io.popen()", f:read("*a")) + print("io.popen()", f:close()) + print("io.type()", io.type(f)) + end)) +end +___'' + + +print("testing C API ...") +local mod = require("testmod") +___'' +print("isinteger", mod.isinteger(1)) +print("isinteger", mod.isinteger(0)) +print("isinteger", mod.isinteger(1234567)) +print("isinteger", mod.isinteger(12.3)) +print("isinteger", mod.isinteger(math.huge)) +print("isinteger", mod.isinteger(math.sqrt(-1))) + +___'' +print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6)) +print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6)) + +___'' +print("strtonum", mod.strtonum("+123")) +print("strtonum", mod.strtonum(" 123 ")) +print("strtonum", mod.strtonum("-1.23")) +print("strtonum", mod.strtonum(" 123 abc")) +print("strtonum", mod.strtonum("jkl")) + +___'' +local a, b, c = mod.requiref() +print("requiref", type(a), type(b), type(c), + a.boolean, b.boolean, c.boolean, + type(requiref1), type(requiref2), type(requiref3)) + +___'' +local c = coroutine.wrap(function() + mod.extraspace("uvw") + print("getextraspace", mod.extraspace()) + coroutine.yield() + print("getextraspace", mod.extraspace()) + coroutine.yield() + print("getextraspace", mod.extraspace()) +end) +c() +mod.extraspace("abc") +print("getextraspace", mod.extraspace()) +c() +local d = coroutine.wrap(function() + print("getextraspace", mod.extraspace()) + mod.extraspace("xyz") + print("getextraspace", mod.extraspace()) + coroutine.yield() + print("getextraspace", mod.extraspace()) + coroutine.yield() + print("getextraspace", mod.extraspace()) +end) +d() +print("getextraspace", mod.extraspace()) +mod.extraspace("123") +c() +d() + +___'' +local proxy, backend = {}, {} +setmetatable(proxy, { __index = backend, __newindex = backend }) +print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) +print("geti/seti", mod.getseti(proxy, 1)) +print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) +print("geti/seti", mod.getseti(proxy, 1)) +print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) + +-- tests for Lua 5.1 +___'' +print("tonumber", mod.tonumber(12)) +print("tonumber", mod.tonumber("12")) +print("tonumber", mod.tonumber("0")) +print("tonumber", mod.tonumber(false)) +print("tonumber", mod.tonumber("error")) + +___'' +print("tointeger", mod.tointeger(12)) +print("tointeger", mod.tointeger(12)) +print("tointeger", mod.tointeger(12.1)) +print("tointeger", mod.tointeger(12.9)) +print("tointeger", mod.tointeger(-12.1)) +print("tointeger", mod.tointeger(-12.9)) +print("tointeger", mod.tointeger("12")) +print("tointeger", mod.tointeger("0")) +print("tointeger", mod.tointeger(math.pi)) +print("tointeger", mod.tointeger(false)) +print("tointeger", mod.tointeger("error")) + +___'' +print("len", mod.len("123")) +print("len", mod.len({ 1, 2, 3})) +print("len", pcall(mod.len, true)) +local ud, meta = mod.newproxy() +meta.__len = function() return 5 end +print("len", mod.len(ud)) +meta.__len = function() return true end +print("len", pcall(mod.len, ud)) + +___'' +print("copy", mod.copy(true, "string", {}, 1)) + +___'' +print("rawgetp/rawsetp", mod.rawxetp()) +print("rawgetp/rawsetp", mod.rawxetp("I'm back")) + +___'' +print("globals", F(mod.globals()), mod.globals() == _G) + +___'' +local t = {} +print("getsubtable", F(mod.subtable(t))) +local x, msg = mod.subtable(t) +print("getsubtable", F(x, msg, x == t.xxx)) + +___'' +print("udata", F(mod.udata())) +print("udata", mod.udata("nosuchtype")) + +___'' +print("uservalue", F(mod.uservalue())) + +___'' +print("upvalues", mod.getupvalues()) + +___'' +print("absindex", mod.absindex("hi", true)) + +___'' +print("arith", mod.arith(2, 1)) +print("arith", mod.arith(3, 5)) + +___'' +print("compare", mod.compare(1, 1)) +print("compare", mod.compare(2, 1)) +print("compare", mod.compare(1, 2)) + +___'' +print("tolstring", mod.tolstring("string")) +local t = setmetatable({}, { + __tostring = function(v) return "mytable" end +}) +print("tolstring", mod.tolstring(t)) +local t = setmetatable({}, { + __tostring = function(v) return nil end +}) +print("tolstring", pcall(mod.tolstring, t)) +local ud, meta = mod.newproxy() +meta.__name = "XXX" +print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy")) + +___'' +print("pushstring", mod.pushstring()) + +___'' +print("Buffer", mod.buffer()) + +___'' +print("execresult", mod.exec("exit 0")) +print("execresult", mod.exec("exit 1")) +print("execresult", mod.exec("exit 25")) + +___'' +do + local bin = string.dump(function() end) + local modes = { "t", "b", "bt" } + local codes = { + "", "return true", bin, "invalidsource", "\27invalidbinary" + } + for _,m in ipairs(modes) do + for i,c in ipairs(codes) do + print("loadbufferx", m, i, F(mod.loadstring(c, m))) + end + end + + ___'' + local bom = "\239\187\191" + local shebang = "#!/usr/bin/env lua\n" + codes[#codes+1] = bom .. shebang .. "return true" + codes[#codes+1] = bom .. shebang .. bin + codes[#codes+1] = bom .. shebang .. "invalidsource" + codes[#codes+1] = bom .. shebang .. "\027invalidbinary" + for _,m in ipairs(modes) do + for i,c in ipairs(codes) do + print("loadfilex", m, i, F(mod.loadfile(c, m))) + end + end +end +___'' + diff --git a/lib/compat53/tests/testmod.c b/lib/compat53/tests/testmod.c new file mode 100644 index 0000000..0d73ed4 --- /dev/null +++ b/lib/compat53/tests/testmod.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include "compat-5.3.h" + + +static int test_isinteger (lua_State *L) { + lua_pushboolean(L, lua_isinteger(L, 1)); + return 1; +} + + +static int test_rotate (lua_State *L) { + int r = (int)luaL_checkinteger(L, 1); + int n = lua_gettop(L)-1; + luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments"); + lua_rotate(L, 2, r); + return n; +} + + +static int test_str2num (lua_State *L) { + const char *s = luaL_checkstring(L, 1); + size_t len = lua_stringtonumber(L, s); + if (len == 0) + lua_pushnumber(L, 0); + lua_pushinteger(L, (lua_Integer)len); + return 2; +} + + +static int my_mod (lua_State *L ) { + lua_newtable(L); + lua_pushboolean(L, 1); + lua_setfield(L, -2, "boolean"); + return 1; +} + +static int test_requiref (lua_State *L) { + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_newtable(L); + lua_pushboolean(L, 0); + lua_setfield(L, -2, "boolean"); + lua_setfield(L, -2, "requiref3"); + lua_pop(L, 1); + luaL_requiref(L, "requiref1", my_mod, 0); + luaL_requiref(L, "requiref2", my_mod, 1); + luaL_requiref(L, "requiref3", my_mod, 1); + return 3; +} + +static int test_getseti (lua_State *L) { + lua_Integer k = luaL_checkinteger(L, 2); + lua_Integer n = 0; + if (lua_geti(L, 1, k) == LUA_TNUMBER) { + n = lua_tointeger(L, -1); + } else { + lua_pop(L, 1); + lua_pushinteger(L, n); + } + lua_pushinteger(L, n+1); + lua_seti(L, 1, k); + return 1; +} + + +#ifndef LUA_EXTRASPACE +#define LUA_EXTRASPACE (sizeof(void*)) +#endif + +static int test_getextraspace (lua_State *L) { + size_t len = 0; + char const* s = luaL_optlstring(L, 1, NULL, &len); + char* p = (char*)lua_getextraspace(L); + lua_pushstring(L, p); + if (s) + memcpy(p, s, len > LUA_EXTRASPACE-1 ? LUA_EXTRASPACE-1 : len+1); + return 1; +} + + +/* additional tests for Lua5.1 */ +#define NUP 3 + +static int test_newproxy (lua_State *L) { + lua_settop(L, 0); + lua_newuserdata(L, 0); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_pushboolean(L, 1); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -3); + return 2; +} + +static int test_absindex (lua_State *L) { + int i = 1; + for (i = 1; i <= NUP; ++i) + lua_pushvalue(L, lua_absindex(L, lua_upvalueindex(i))); + lua_pushvalue(L, lua_absindex(L, LUA_REGISTRYINDEX)); + lua_pushstring(L, lua_typename(L, lua_type(L, lua_absindex(L, -1)))); + lua_replace(L, lua_absindex(L, -2)); + lua_pushvalue(L, lua_absindex(L, -2)); + lua_pushvalue(L, lua_absindex(L, -4)); + lua_pushvalue(L, lua_absindex(L, -6)); + i += 3; + lua_pushvalue(L, lua_absindex(L, 1)); + lua_pushvalue(L, lua_absindex(L, 2)); + lua_pushvalue(L, lua_absindex(L, 3)); + i += 3; + return i; +} + +static int test_arith (lua_State *L) { + lua_settop(L, 2); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + lua_arith(L, LUA_OPADD); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + lua_arith(L, LUA_OPSUB); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + lua_arith(L, LUA_OPMUL); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + lua_arith(L, LUA_OPDIV); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + lua_arith(L, LUA_OPMOD); + lua_pushvalue(L, 1); + lua_pushvalue(L, 2); + lua_arith(L, LUA_OPPOW); + lua_pushvalue(L, 1); + lua_arith(L, LUA_OPUNM); + return lua_gettop(L)-2; +} + +static int test_compare (lua_State *L) { + luaL_checknumber(L, 1); + luaL_checknumber(L, 2); + lua_settop(L, 2); + lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPEQ)); + lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLT)); + lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLE)); + return 3; +} + +static int test_globals (lua_State *L) { + lua_pushglobaltable(L); + return 1; +} + +static int test_tonumber (lua_State *L) { + int isnum = 0; + lua_Number n = lua_tonumberx(L, 1, &isnum); + if (!isnum) + lua_pushnil(L); + else + lua_pushnumber(L, n); + return 1; +} + +static int test_tointeger (lua_State *L) { + int isnum = 0; + lua_Integer n = lua_tointegerx(L, 1, &isnum); + if (!isnum) + lua_pushnil(L); + else + lua_pushinteger(L, n); + lua_pushinteger(L, lua_tointeger(L, 1)); + return 2; +} + +static int test_len (lua_State *L) { + luaL_checkany(L, 1); + lua_len(L, 1); + lua_pushinteger(L, luaL_len(L, 1)); + return 2; +} + +static int test_copy (lua_State *L) { + int args = lua_gettop(L); + if (args >= 2) { + int i = 0; + for (i = args-1; i > 0; --i) + lua_copy(L, args, i); + } + return args; +} + +/* need an address */ +static char const dummy = 0; + +static int test_rawxetp (lua_State *L) { + if (lua_gettop(L) > 0) + lua_pushvalue(L, 1); + else + lua_pushliteral(L, "hello again"); + lua_rawsetp(L, LUA_REGISTRYINDEX, &dummy); + lua_settop(L, 0); + lua_rawgetp(L, LUA_REGISTRYINDEX, &dummy); + return 1; +} + +static int test_udata (lua_State *L) { + const char *tname = luaL_optstring(L, 1, "utype1"); + void *u1 = lua_newuserdata(L, 1); + int u1pos = lua_gettop(L); + void *u2 = lua_newuserdata(L, 1); + int u2pos = lua_gettop(L); + luaL_newmetatable(L, "utype1"); + luaL_newmetatable(L, "utype2"); + lua_pop(L, 2); + luaL_setmetatable(L, "utype2"); + lua_pushvalue(L, u1pos); + luaL_setmetatable(L, "utype1"); + lua_pop(L, 1); + (void)u1; + (void)u2; + lua_pushlightuserdata(L, luaL_testudata(L, u1pos, tname)); + lua_pushlightuserdata(L, luaL_testudata(L, u2pos, tname)); + luaL_getmetatable(L, "utype1"); + lua_getfield(L, -1, "__name"); + lua_replace(L, -2); + return 3; +} + +static int test_subtable (lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); + if (luaL_getsubtable(L, 1, "xxx")) { + lua_pushliteral(L, "oldtable"); + } else { + lua_pushliteral(L, "newtable"); + } + return 2; +} + +static int test_uservalue (lua_State *L) { + void *udata = lua_newuserdata(L, 1); + int ui = lua_gettop(L); + lua_newtable(L); + lua_setuservalue(L, ui); + lua_pushinteger(L, lua_getuservalue(L, ui)); + (void)udata; + return 2; +} + +static int test_upvalues (lua_State *L) { + int i = 1; + for (i = 1; i <= NUP; ++i) + lua_pushvalue(L, lua_upvalueindex(i)); + return NUP; +} + +static int test_tolstring (lua_State *L) { + size_t len = 0; + luaL_tolstring(L, 1, &len); + lua_pushinteger(L, (int)len); + return 2; +} + +static int test_pushstring (lua_State *L) { + lua_pushstring(L, lua_pushliteral(L, "abc")); + lua_pushstring(L, lua_pushlstring(L, "abc", 2)); + lua_pushstring(L, lua_pushlstring(L, NULL, 0)); + lua_pushstring(L, lua_pushstring(L, "abc")); + lua_pushboolean(L, NULL == lua_pushstring(L, NULL)); + return 10; +} + +static int test_buffer (lua_State *L) { + luaL_Buffer b; + char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1); + p[0] = 'a'; + p[1] = 'b'; + luaL_addsize(&b, 2); + luaL_addstring(&b, "c"); + lua_pushliteral(L, "d"); + luaL_addvalue(&b); + luaL_addchar(&b, 'e'); + luaL_pushresult(&b); + return 1; +} + +static int test_exec (lua_State *L) { + const char *cmd = luaL_checkstring(L, 1); + errno = 0; + return luaL_execresult(L, system(cmd)); +} + +static int test_loadstring (lua_State *L) { + size_t len = 0; + char const* s = luaL_checklstring(L, 1, &len); + char const* mode = luaL_optstring(L, 2, "bt"); + lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode)); + return 2; +} + +static int test_loadfile (lua_State *L) { + char filename[L_tmpnam+1] = { 0 }; + size_t len = 0; + char const* s = luaL_checklstring(L, 1, &len); + char const* mode = luaL_optstring(L, 2, "bt"); + if (tmpnam(filename)) { + FILE* f = fopen(filename, "wb"); + if (f) { + fwrite(s, 1, len, f); + fclose(f); + lua_pushinteger(L, luaL_loadfilex(L, filename, mode)); + remove(filename); + return 2; + } else + remove(filename); + } + return 0; +} + + +static const luaL_Reg funcs[] = { + { "isinteger", test_isinteger }, + { "rotate", test_rotate }, + { "strtonum", test_str2num }, + { "requiref", test_requiref }, + { "getseti", test_getseti }, + { "extraspace", test_getextraspace }, + { "newproxy", test_newproxy }, + { "arith", test_arith }, + { "compare", test_compare }, + { "tonumber", test_tonumber }, + { "tointeger", test_tointeger }, + { "len", test_len }, + { "copy", test_copy }, + { "rawxetp", test_rawxetp }, + { "subtable", test_subtable }, + { "udata", test_udata }, + { "uservalue", test_uservalue }, + { "globals", test_globals }, + { "tolstring", test_tolstring }, + { "pushstring", test_pushstring }, + { "buffer", test_buffer }, + { "exec", test_exec }, + { "loadstring", test_loadstring }, + { "loadfile", test_loadfile }, + { NULL, NULL } +}; + +static const luaL_Reg more_funcs[] = { + { "getupvalues", test_upvalues }, + { "absindex", test_absindex }, + { NULL, NULL } +}; + + +#ifdef __cplusplus +extern "C" { +#endif +int luaopen_testmod (lua_State *L) { + int i = 1; + luaL_newlib(L, funcs); + for (i = 1; i <= NUP; ++i) + lua_pushnumber(L, i); + luaL_setfuncs(L, more_funcs, NUP); + return 1; +} +#ifdef __cplusplus +} +#endif + diff --git a/premake5.lua b/premake5.lua index 037cfca..127e86e 100644 --- a/premake5.lua +++ b/premake5.lua @@ -18,7 +18,11 @@ else links({ "lua" }) end -includedirs({ lua_inc_path, "lib/hashmap" }) +includedirs({ + lua_inc_path, + "lib/hashmap", + "lib/compat53/c-api" +}) libdirs({ lua_lib_path }) files({ @@ -26,8 +30,10 @@ files({ "src/**.c", "lib/hashmap/**.h", "lib/hashmap/**.c", + "lib/compat53/c-api/compat-5.3.h", + "lib/compat53/c-api/compat-5.3.c" }) -defines({ 'LUSH_VERSION="0.3.2"' }) +defines({ 'LUSH_VERSION="0.3.2"', 'COMPAT53_PREFIX=""' }) filter("configurations:Debug") defines({ "DEBUG" }) diff --git a/src/lush.c b/src/lush.c index 1c42139..cadc1bc 100644 --- a/src/lush.c +++ b/src/lush.c @@ -21,6 +21,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "lua.h" #include "lua_api.h" #include "lualib.h" +#include "../lib/compat53/c-api/compat-5.3.h" #include #include #include @@ -1485,13 +1486,14 @@ int main(int argc, char *argv[]) { return 0; } + // init lua state + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + lua_register_api(L); + lua_run_init(L); + // check if being run in command string mode if (argc > 2 && strcmp(argv[1], "-c") == 0) { - // init Lua state - lua_State *L = luaL_newstate(); - luaL_openlibs(L); - lua_register_api(L); - lua_run_init(L); // execute the command provided char *command = argv[2]; @@ -1521,36 +1523,26 @@ int main(int argc, char *argv[]) { return 0; } - // init lua state - lua_State *L = luaL_newstate(); - luaL_openlibs(L); - lua_register_api(L); - lua_run_init(L); + // This is the corrected logic for running a script file non-interactively. + if (argc > 1) { + char *ext = strrchr(argv[1], '.'); + if (ext && strcmp(ext, ".lua") == 0) { + const char *script_name = argv[1]; + // The arguments for the script start at argv[2]. + // We create a pointer to that part of the array. + char **script_args = (argc > 2) ? &argv[2] : NULL; - // if a lua function is passed on load run non-interactively - if (argc > 1) { - char *ext = strrchr(argv[1], '.'); - if (ext) { - ext++; - if (strcmp(ext, "lua") == 0) { - int status = 0; - argv++; - char ***args = lush_split_args(argv, &status); - - if (status == -1) { - fprintf(stderr, "lush: Expected end of quoted string\n"); - } else if (lush_run(L, args, status) != 0) { - exit(1); - } + // Call the script loader directly with the script and its arguments. + if (lua_load_script(L, script_name, script_args) != 0) { + exit(1); // Exit if the script had an error + } - for (int i = 0; args[i]; i++) { - free(args[i]); - } - free(args); - return 0; - } - } - } + lua_close(L); // Clean up and exit + return 0; + } + } + + // --- Interactive Shell Mode --- // eat ^C in main struct sigaction sa_int; @@ -1617,4 +1609,4 @@ int main(int argc, char *argv[]) { if (alt_shell != NULL) free(alt_shell); return 0; -} +} \ No newline at end of file diff --git a/test/compat_test.lua b/test/compat_test.lua new file mode 100644 index 0000000..bd7ef90 --- /dev/null +++ b/test/compat_test.lua @@ -0,0 +1,60 @@ +-- test/compat_test.lua +-- A small test suite for the lua-compat-5.3 layer. +-- Can be run in two ways: +-- 1. ./lush test/compat_test.lua (runs all tests) +-- 2. ./lush test/compat_test.lua test_table_unpack (runs a single test) + +local tests = {} + +function tests.test_table_unpack() + print("--- Running test: table.unpack ---") + local my_table = { "a", "b", "c" } + -- The compat layer provides table.unpack for Lua 5.1. + local x, y, z = table.unpack(my_table) + assert(x == "a", "unpack failed for first element") + assert(y == "b", "unpack failed for second element") + assert(z == "c", "unpack failed for third element") + print("...SUCCESS!") +end + +function tests.test_math_log_base() + print("--- Running test: math.log with base ---") + -- Lua 5.1's math.log only takes one argument. The compat layer adds the base. + local result = math.log(100, 10) + -- Use a small epsilon for floating point comparison + assert(math.abs(result - 2) < 1e-9, "math.log(100, 10) should be 2") + print("...SUCCESS!") +end + +function tests.test_string_rep_separator() + print("--- Running test: string.rep with separator ---") + -- Lua 5.1's string.rep doesn't have the separator argument. + local result = string.rep("a", 3, "-") + assert(result == "a-a-a", "string.rep with separator failed, got: " .. tostring(result)) + print("...SUCCESS!") +end + + +-- NOTE: The lush C host provides arguments in a global table named 'args', not 'arg'. +local test_to_run = args and args[1] + +if test_to_run and tests[test_to_run] then + -- If a valid test name is provided, run only that test. + local success, err = pcall(tests[test_to_run]) + if not success then + print("...FAILURE: " .. err) + end +elseif test_to_run then + -- If an invalid name is provided, show an error. + print("ERROR: Test function '" .. test_to_run .. "' not found.") +else + -- If no specific test is requested, run all of them. + print("--- Running all compatibility tests ---") + for name, func in pairs(tests) do + local success, err = pcall(func) + if not success then + print("...FAILURE on test '" .. name .. "': " .. err) + end + end + print("--- All tests complete ---") +end From a604743427f1f42d7e65cb4cdbc69866eb044603 Mon Sep 17 00:00:00 2001 From: "io.shift" Date: Mon, 14 Jul 2025 18:05:24 -0500 Subject: [PATCH 02/33] Delete et --- et | 132 ------------------------------------------------------------- 1 file changed, 132 deletions(-) delete mode 100644 et diff --git a/et b/et deleted file mode 100644 index 1a9eb09..0000000 --- a/et +++ /dev/null @@ -1,132 +0,0 @@ -* 1982f1c (fork/main, fork/HEAD) Smarter tracer: backup -* 5e49f57 Re-init submodules: backup -* bd4cfd2 Arch dis Backup: lisp logs included -* 9bf7f1f Backup: moving from Ubun to Arch -* 2b1f666 (HEAD -> my-feature-branch, tag: v0.3.2, origin/main, origin/HEAD, fork/my-feature-branch, main) v0.3.2 -* 17aadc3 added ability to configure alternate shell -* 9b85e55 (tag: v0.3.1) v0.3.1 -* a1cdb80 add api method to enable/disable inline suggestions -* ce3f1d2 (tag: v0.3.0) v0.3.0 -* 640221c add globbing to command mode -* 6f2e940 added wildcard globbing -* 823a5a4 fixed --version bug -* a87df81 made constant for lush_lua builtin index -* e373f9a added trap builtin -* 3904d58 added command string mode -* 5638f1b Update README.md -* c3afa71 removed history test out of convenience -* 6295ae2 updated help messages -* 6936fee (tag: v0.2.3) v0.2.3 -* a0d5695 added redirect/append for stdout, stderr, or both -* 68ce253 added exit api function -* b29a99b fixed chaining execution attempting to execute operator -* 4028df2 (tag: v0.2.2) v0.2.2 -* 80588be updated history tests -* cd55487 fixed crash in redirect operator -* 4cf1cba (tag: v0.2.1) v0.2.1 -* eda09a9 fixed semicolon chaining functionality -* e61e70d (tag: v0.2.0) v0.2.0 -* 4730d17 fixed crash from incorrect pointer indexing -* e13e23b added append chaining operator -* f7922ea added output redirection with -* e067ca5 added ; chaining operator -* ccf4047 added || chaining operator -* 0539674 Update README.md -* c6e9097 fixed lua api exit status issue -* 69592d5 fixed splitting within quoted string -* 1c41c12 made and operator actually conditional -* 6d0ff4d fixed operator chaining to handle commands terminating with an operator -* e85cb6b implemented background process operator -* b578aef Merge pull request #2 from BanceDev/chaining-operators -|\ -| * 863b097 implemented piping into new chaining method -| * ecfbc1f fixed && chaining for builtins -| * b7718ed added basic && chaining -| * b850121 changed tokenizer to handle all the chaining operators -|/ -* 8997142 Update README.md -* 5914d2e added better clarification to help menu -* c3eb4b2 improved installation instructions -* 6f4a6c4 (tag: v0.1.1) v0.1.1 -* b5857f5 fixed bug in input buffer handling due to misplaced print -* 0dc9a6a Update build.yml checkout v4 -* 58a4647 Update build.yml to artifact v4 -* 0b9c467 fixed exit status issue with non interative mode -* 2c7d28a added non interative mode for running lua scripts -* ee88d00 temporary github action fix until non-interactive mode is implemented -* d41d846 attempt to update build script to accept input into lush shell -* 2fdc7cc prevent lush workflow from getting stuck in tests -* f21f5a8 removed chsh in workflow -* 11b81de Create build.yml -* d25fc21 updated documentation -* 2870751 added e2e testing to cover basic shell functionality -* 9fffa2e updated buffer size for date to account for compiler warning -* 0381ae7 added glob function to lua APi -* daace6e (tag: v0.1.0) v0.1.0 -* 6b3be9c initialized OLDPWD properly -* d5874c5 added HOSTNAME envar -* 3165d96 added OLDPWD environment var and cd - to go to OLDPWD -* 68904ae added date format specifier for prompt -* 32ee824 spelling error in readme demo -* 10910fd updated readme with visuals -* 4361507 fixed off-by-one error with prompt wrapping -* e28bd74 added tab to accept inline autocomplete -* 3742e0b basic current directory suggestions -* 8389686 made it so that lua args properly reset between commands -* e21a4d0 removed demo image to cleanup -* 2c3e681 higher quality image for readme -* 23fb50c added better demo to readme -* 86cadef added handling for when prompt gets longer than terminal width -* 50d69ad added support for multiline prompts -* a0ff5b1 lua api functions for getting terminal width and height -* 5e403a6 added coloring to help command -* 521316d add aliasing to init.lua -* 49fe61d bugfix to inline backspace and delete on multiline buffer -* 0ec71db fixed line wrapping when deleting inline -* 4cdf16f updated gitignore -* d6c203a fixed wrapping bug due to not using updated prompt_length -* 73d9858 added stripping of escape sequences from prompt size to allow for coloring -* 0f4b5ff Merge pull request #1 from Makaze/patch-1 -|\ -| * b6e478c docs: update path -* | 49de8d3 added support for init.lua for configuring shell -|/ -* 6a2689d added getenv and putenv to Lua API -* bfa2768 added lua api functions for indexing history -* ea0eb66 added support for cli args for lua scripts -* c638ce8 added --version flag -* 0edfb38 fixed error in install.sh instructions -* 29c052c fixed bug with cursor alignment when adding text within the buffer -* 29f1b14 added API guide to readme -* 305b17a Update README.md -* ff06726 better readme -* 0b263c3 Create FUNDING.yml -* e6700fc Update README.md -* 9c301c1 fixed crash when no history exists yet and polls for history -* d864cde fixed inability to move cursor between lines -* d63e0e1 cleaned up syntax -* b020cf5 Update CONTRIBUTING.md -* 41f8b9a bugfix on arrowkey movement after browsing history -* 58cb10f updated readme -* 99b8bb5 upadted contribution guidelines -* 64c61c4 Create CONTRIBUTING.md -* bbcf154 fixed bugs with multi line history elements -* 65d523b added api functions for isFile, isDirectory, isReadable, and isWriteable -* e828e25 command history scrolling implemented -* 995e8da history saving implemented -* eea1194 added exists function to lua api -* 7dea3ee added missing lua registrations -* 8936264 updated the example.lua to use new cd command -* 86b8b0e added cd to lua api -* 72f5958 fixed a bug where multiline commands printed wrong -* 5568fba removed need for lush command to execute lua files -* 3577398 added debug mode for scripting -* d5d3f94 update lua api to table and added getcwd to api -* 4fee5ce fixed crash in cd when no path found -* 4375a8e searches .lush/scripts for lua files -* ebdd4e8 added basic lua scripting -* 8ddcd6b added arrow key movement -* 112a831 updated help and fixed SIGINT -* 5c2b255 lunar shell logo -* 58966d4 changed prompt -* f6d7b19 initial commit From 3961c372ea01f5b9a151bf3ff891602ae0d347d8 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 20:23:07 -0500 Subject: [PATCH 03/33] Added compat53 to init block: added .gitmodules init to install.sh --- install.sh | 3 +++ src/lush.c | 1 + 2 files changed, 4 insertions(+) diff --git a/install.sh b/install.sh index ebdbaeb..405cf6e 100755 --- a/install.sh +++ b/install.sh @@ -1,5 +1,8 @@ #!/bin/sh +echo "Initializing and updating submodules..." +git submodule update --init --recursive + # Function to install packages using apt (Debian/Ubuntu) install_with_apt() { sudo apt-get update diff --git a/src/lush.c b/src/lush.c index cadc1bc..49b205e 100644 --- a/src/lush.c +++ b/src/lush.c @@ -1489,6 +1489,7 @@ int main(int argc, char *argv[]) { // init lua state lua_State *L = luaL_newstate(); luaL_openlibs(L); + luaopen_compat53(L); lua_register_api(L); lua_run_init(L); From 7c4b465d8c773b2e6282e78553c7c49e85e091d5 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 20:49:31 -0500 Subject: [PATCH 04/33] Added Jenkins files for local CI testing --- Dockerfile.jenkins | 29 +++++++++++++++++++++ Jenkinsfile | 64 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 17 ++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 Dockerfile.jenkins create mode 100644 Jenkinsfile create mode 100644 docker-compose.yml diff --git a/Dockerfile.jenkins b/Dockerfile.jenkins new file mode 100644 index 0000000..874941a --- /dev/null +++ b/Dockerfile.jenkins @@ -0,0 +1,29 @@ +# Dockerfile.jenkins +# Use the official Jenkins image as a base +FROM jenkins/jenkins:lts-jdk17 + +# Pass the Docker group ID from the host as a build argument +ARG DOCKER_GID + +# Switch to root user to install dependencies +USER root + +# Install Docker CLI so Jenkins can interact with the host's Docker daemon +RUN apt-get update && apt-get install -y lsb-release sudo +RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \ + https://download.docker.com/linux/debian/gpg +RUN echo "deb [arch=$(dpkg --print-architecture) \ + signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \ + https://download.docker.com/linux/debian \ + $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list +RUN apt-get update && apt-get install -y docker-ce-cli + +# Create a 'docker' group with the host's GID to match permissions +# This is the key step to prevent the container from exiting +RUN if [ -n "$DOCKER_GID" ]; then groupadd -g $DOCKER_GID docker; else groupadd -g 999 docker; fi + +# Add the 'jenkins' user to the docker group +RUN usermod -aG docker jenkins + +# Switch back to the jenkins user +USER jenkins diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..e8d568d --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,64 @@ +pipeline { + agent any + + stages { + stage('Build Docker Image') { + steps { + script { + echo 'Building the Docker image...' + // Build the Docker image from the Dockerfile in the current directory + // and tag it as 'lush-arch-test' + sh 'docker build -t lush-arch-test .' + } + } + } + stage('Run Tests in Container') { + steps { + script { + echo 'Running tests inside the Docker container...' + // Run the container with the 'lush-arch-test' image. + // The CMD in the Dockerfile will be executed. + // --rm automatically removes the container when it exits. + sh 'docker run --rm lush-arch-test' + } + } + } + stage('Run Owner-Provided Test Script') { + steps { + script { + echo 'Running the Lua 5.2 compatibility test script...' + // First, create the test script file + sh ''' + cat <<'EOF' > test_52.lua + -- Lua 5.2-specific features + local _ENV = { print = print, x = 123 } -- lexical environments + function show_x() + print("x =", x) + end + show_x() + -- Bitwise ops (added in 5.2) + local a, b = 0x5, 0x3 + print("Bitwise AND:", a & b) + -- load() replaces loadstring() (binary and text) + local f = load("return 10 + 20") + print("Loaded result:", f()) + -- table.pack / table.unpack + local t = table.pack(1, 2, 3, nil, 5) + print("Packed length:", t.n) + print("Unpacked values:", table.unpack(t)) + EOF + ''' + // Run the container and execute the owner's test script + sh 'docker run --rm -v $(pwd)/test_52.lua:/app/test_52.lua lush-arch-test ./bin/Debug/lush/lush test_52.lua' + } + } + } + } + post { + always { + echo 'Pipeline finished.' + // Clean up the created docker image to save space + sh 'docker rmi lush-arch-test || true' + } + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..77dfb90 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +# docker-compose.yml +services: + jenkins: + build: + context: . + dockerfile: Dockerfile.jenkins + args: + # Pass the host's docker group ID to the build + DOCKER_GID: ${DOCKER_GID} + user: "${UID}:${GID}" # Run the container as the current host user + ports: + - "8080:8080" + - "50000:50000" + container_name: jenkins + volumes: + - ./jenkins_home:/var/jenkins_home + - /var/run/docker.sock:/var/run/docker.sock From bac1f1c73db9c55a18b41b76922572fd2620f3d5 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 21:00:10 -0500 Subject: [PATCH 05/33] Fixing Jenkins Setup: Attempt2 --- Dockerfile.jenkins | 27 +++++++++++++++++++-------- docker-compose.yml | 7 ++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Dockerfile.jenkins b/Dockerfile.jenkins index 874941a..23a95f1 100644 --- a/Dockerfile.jenkins +++ b/Dockerfile.jenkins @@ -2,10 +2,12 @@ # Use the official Jenkins image as a base FROM jenkins/jenkins:lts-jdk17 -# Pass the Docker group ID from the host as a build argument +# Pass Host User, Group, and Docker Group IDs as build arguments +ARG UID +ARG GID ARG DOCKER_GID -# Switch to root user to install dependencies +# Switch to root user to install dependencies and manage users USER root # Install Docker CLI so Jenkins can interact with the host's Docker daemon @@ -18,12 +20,21 @@ RUN echo "deb [arch=$(dpkg --print-architecture) \ $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list RUN apt-get update && apt-get install -y docker-ce-cli -# Create a 'docker' group with the host's GID to match permissions -# This is the key step to prevent the container from exiting -RUN if [ -n "$DOCKER_GID" ]; then groupadd -g $DOCKER_GID docker; else groupadd -g 999 docker; fi +# Create a docker group with the host's GID to match permissions +# and add the jenkins user to it. +RUN if [ -n "$DOCKER_GID" ]; then \ + groupadd -g $DOCKER_GID docker && \ + usermod -aG docker jenkins; \ + fi -# Add the 'jenkins' user to the docker group -RUN usermod -aG docker jenkins +# Change the jenkins user and group to match the host. +# This should ensure file permissions for the jenkins_home volume are correct. +RUN if [ -n "$GID" ] && [ "$(getent group jenkins | cut -d: -f3)" != "$GID" ]; then \ + groupmod -g $GID jenkins; \ + fi +RUN if [ -n "$UID" ] && [ "$(id -u jenkins)" != "$UID" ]; then \ + usermod -u $UID jenkins; \ + fi -# Switch back to the jenkins user +# Switch to the newly configured jenkins user USER jenkins diff --git a/docker-compose.yml b/docker-compose.yml index 77dfb90..0cccadc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,13 +5,14 @@ services: context: . dockerfile: Dockerfile.jenkins args: - # Pass the host's docker group ID to the build + # Pass all necessary host IDs to the build + UID: ${UID} + GID: ${GID} DOCKER_GID: ${DOCKER_GID} - user: "${UID}:${GID}" # Run the container as the current host user ports: - "8080:8080" - "50000:50000" container_name: jenkins volumes: - ./jenkins_home:/var/jenkins_home - - /var/run/docker.sock:/var/run/docker.sock + - /var/run/docker.sock:/var/run/docker.sock \ No newline at end of file From 4cae3c2244e14dd5c24c040ecff12a9d2c0cde4f Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 21:04:37 -0500 Subject: [PATCH 06/33] update the Jenkinsfile to explicitly tell the docker build command which file to use with the -f flag: Attempt3 --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e8d568d..83be0ac 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,9 +6,9 @@ pipeline { steps { script { echo 'Building the Docker image...' - // Build the Docker image from the Dockerfile in the current directory + // Build the Docker image from the Dockerfile.jenkins in the current directory // and tag it as 'lush-arch-test' - sh 'docker build -t lush-arch-test .' + sh 'docker build -f Dockerfile.jenkins -t lush-arch-test .' } } } @@ -61,4 +61,4 @@ pipeline { sh 'docker rmi lush-arch-test || true' } } -} \ No newline at end of file +} From 8e69247666fffb7db4b4b0a610a2461d635b0065 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 21:20:42 -0500 Subject: [PATCH 07/33] This file defines the environment for the lush application: Attempt4 --- Dockerfile | 26 ++++++++++++++++++++++++++ Jenkinsfile | 35 ++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d281f46 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Use a base image with build tools +FROM ubuntu:22.04 + +# Avoid interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install necessary build tools for your C project +RUN apt-get update && apt-get install -y \ + build-essential \ + wget \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +# Download and install Premake5 +RUN wget https://github.com/premake/premake-core/releases/download/v5.0.0-beta2/premake-5.0.0-beta2-linux.tar.gz -O premake.tar.gz && \ + tar -xvf premake.tar.gz && \ + mv premake5 /usr/local/bin/ + +# Set the working directory inside the container +WORKDIR /app + +# Copy your project's source code into the container +COPY . . + +# Generate the makefiles. This will be the default action if no other command is given. +CMD ["premake5", "gmake2"] diff --git a/Jenkinsfile b/Jenkinsfile index 83be0ac..f7f66c7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,35 +2,35 @@ pipeline { agent any stages { - stage('Build Docker Image') { + stage('Build Application Image') { steps { script { - echo 'Building the Docker image...' - // Build the Docker image from the Dockerfile.jenkins in the current directory - // and tag it as 'lush-arch-test' - sh 'docker build -f Dockerfile.jenkins -t lush-arch-test .' + echo 'Building the Lush application Docker image...' + // Build the image from the new Dockerfile and tag it + sh 'docker build -t lush-app:latest .' } } } - stage('Run Tests in Container') { + stage('Compile Project in Container') { steps { script { - echo 'Running tests inside the Docker container...' - // Run the container with the 'lush-arch-test' image. - // The CMD in the Dockerfile will be executed. - // --rm automatically removes the container when it exits. - sh 'docker run --rm lush-arch-test' + echo 'Compiling the Lush project inside the container...' + // Run the container to generate Makefiles and compile + // We mount the current directory to get the compiled artifacts back out + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest make' } } } - stage('Run Owner-Provided Test Script') { + stage('Run Lua 5.2 Compatibility Test') { steps { script { echo 'Running the Lua 5.2 compatibility test script...' - // First, create the test script file + // Create the test script file sh ''' cat <<'EOF' > test_52.lua -- Lua 5.2-specific features + print("--- Running Lua 5.2 Compatibility Test ---") local _ENV = { print = print, x = 123 } -- lexical environments function show_x() print("x =", x) @@ -45,11 +45,12 @@ pipeline { -- table.pack / table.unpack local t = table.pack(1, 2, 3, nil, 5) print("Packed length:", t.n) - print("Unpacked values:", table.unpack(t)) + print("Unpacked values:", table.unpack(t, 1, t.n)) + print("--- Test Complete ---") EOF ''' - // Run the container and execute the owner's test script - sh 'docker run --rm -v $(pwd)/test_52.lua:/app/test_52.lua lush-arch-test ./bin/Debug/lush/lush test_52.lua' + // Run the container and execute the test script with the compiled binary + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ./bin/Debug/lush/lush test_52.lua' } } } @@ -58,7 +59,7 @@ pipeline { always { echo 'Pipeline finished.' // Clean up the created docker image to save space - sh 'docker rmi lush-arch-test || true' + sh 'docker rmi lush-app:latest || true' } } } From 5666a237ef3f4f0ce7fb5505273f76806c5c7568 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 21:27:56 -0500 Subject: [PATCH 08/33] Jenkins checkout step with the SubmoduleOption enabled: Attempt5 --- Dockerfile | 1 - Jenkinsfile | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d281f46..6aa22ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,6 @@ RUN wget https://github.com/premake/premake-core/releases/download/v5.0.0-beta2/ # Set the working directory inside the container WORKDIR /app -# Copy your project's source code into the container COPY . . # Generate the makefiles. This will be the default action if no other command is given. diff --git a/Jenkinsfile b/Jenkinsfile index f7f66c7..27c5869 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,6 +2,20 @@ pipeline { agent any stages { + stage('Checkout Code') { + steps { + echo 'Checking out code from Git and initializing submodules...' + checkout([ + $class: 'GitSCM', + branches: scm.branches, + userRemoteConfigs: scm.userRemoteConfigs, + extensions: [ + [$class: 'SubmoduleOption', disableSubmodules: false, recursiveSubmodules: true, trackingSubmodules: true] + ] + ]) + } + } + stage('Build Application Image') { steps { script { From ad56a06a04366930599a39273e0d6b4e681f9e06 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 22:27:36 -0500 Subject: [PATCH 09/33] Add a simple shell command to manually initialize the submodules: attempt6 --- Jenkinsfile | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 27c5869..364cff3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,25 +2,15 @@ pipeline { agent any stages { - stage('Checkout Code') { - steps { - echo 'Checking out code from Git and initializing submodules...' - checkout([ - $class: 'GitSCM', - branches: scm.branches, - userRemoteConfigs: scm.userRemoteConfigs, - extensions: [ - [$class: 'SubmoduleOption', disableSubmodules: false, recursiveSubmodules: true, trackingSubmodules: true] - ] - ]) - } - } - stage('Build Application Image') { steps { script { + echo 'Initializing Git submodules...' + // Manually initialize and update the git submodules + sh 'git submodule update --init --recursive' + echo 'Building the Lush application Docker image...' - // Build the image from the new Dockerfile and tag it + // Build the image from the Dockerfile and tag it sh 'docker build -t lush-app:latest .' } } From 2215c76635853d92e79150576bd3d40db0725f76 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 22:41:22 -0500 Subject: [PATCH 10/33] Add diagnostics: attempt6a --- Jenkinsfile | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 364cff3..96fc734 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,12 +5,20 @@ pipeline { stage('Build Application Image') { steps { script { + echo 'Pre-build diagnostics...' + sh 'pwd' + sh 'ls -la' + sh 'find . -name "premake5.lua" -type f' + echo 'Initializing Git submodules...' - // Manually initialize and update the git submodules sh 'git submodule update --init --recursive' + + echo 'Post-submodule diagnostics...' + sh 'ls -la' + sh 'find . -name "premake5.lua" -type f' + sh 'ls -lR | head -50' // Show directory structure echo 'Building the Lush application Docker image...' - // Build the image from the Dockerfile and tag it sh 'docker build -t lush-app:latest .' } } @@ -18,10 +26,16 @@ pipeline { stage('Compile Project in Container') { steps { script { + echo 'Container diagnostics...' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest pwd' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ls -la' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest find . -name "premake5.lua" -type f' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ls -la /app' + echo 'Compiling the Lush project inside the container...' - // Run the container to generate Makefiles and compile - // We mount the current directory to get the compiled artifacts back out - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest' + // First run premake to generate build files + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest premake5 gmake2' + // Then run make to compile sh 'docker run --rm -v "$(pwd)":/app lush-app:latest make' } } @@ -29,8 +43,11 @@ pipeline { stage('Run Lua 5.2 Compatibility Test') { steps { script { + echo 'Pre-test diagnostics...' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ls -la bin/' + sh 'docker run --rm -v "$(pwd)":/app lush-app:latest find . -name "lush" -type f' + echo 'Running the Lua 5.2 compatibility test script...' - // Create the test script file sh ''' cat <<'EOF' > test_52.lua -- Lua 5.2-specific features @@ -53,7 +70,6 @@ pipeline { print("--- Test Complete ---") EOF ''' - // Run the container and execute the test script with the compiled binary sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ./bin/Debug/lush/lush test_52.lua' } } @@ -62,8 +78,7 @@ pipeline { post { always { echo 'Pipeline finished.' - // Clean up the created docker image to save space sh 'docker rmi lush-app:latest || true' } } -} +} \ No newline at end of file From 9586722136cd57e2fded6e86e5cbb5e787a92f54 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 22:50:19 -0500 Subject: [PATCH 11/33] named container to run the build, and then use docker cp to copy the compiled binary out: attempt7 --- Jenkinsfile | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 96fc734..53e580a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,48 +5,42 @@ pipeline { stage('Build Application Image') { steps { script { - echo 'Pre-build diagnostics...' - sh 'pwd' - sh 'ls -la' - sh 'find . -name "premake5.lua" -type f' - echo 'Initializing Git submodules...' + // Manually initialize and update the git submodules sh 'git submodule update --init --recursive' - - echo 'Post-submodule diagnostics...' - sh 'ls -la' - sh 'find . -name "premake5.lua" -type f' - sh 'ls -lR | head -50' // Show directory structure echo 'Building the Lush application Docker image...' sh 'docker build -t lush-app:latest .' } } } - stage('Compile Project in Container') { + stage('Compile Project & Extract Artifacts') { steps { script { - echo 'Container diagnostics...' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest pwd' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ls -la' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest find . -name "premake5.lua" -type f' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ls -la /app' + // Define a unique name for our temporary container + def containerName = "lush-build-${BUILD_NUMBER}" - echo 'Compiling the Lush project inside the container...' - // First run premake to generate build files - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest premake5 gmake2' - // Then run make to compile - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest make' + try { + echo 'Compiling the Lush project inside a container...' + // Run the entire build process in a single, named container. + // This container will be stopped but not removed + // which preserves its filesystem for the next step + sh "docker run --name ${containerName} lush-app:latest /bin/bash -c 'premake5 gmake2 && make'" + + echo 'Extracting compiled binary from the container...' + // Copy the 'bin' directory + // from the container's filesystem to the Jenkins workspace. + sh "docker cp ${containerName}:/app/bin ./" + } finally { + echo "Cleaning up build container: ${containerName}" + sh "docker rm ${containerName} || true" + } } } } stage('Run Lua 5.2 Compatibility Test') { steps { script { - echo 'Pre-test diagnostics...' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ls -la bin/' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest find . -name "lush" -type f' - echo 'Running the Lua 5.2 compatibility test script...' sh ''' cat <<'EOF' > test_52.lua @@ -70,7 +64,8 @@ pipeline { print("--- Test Complete ---") EOF ''' - sh 'docker run --rm -v "$(pwd)":/app lush-app:latest ./bin/Debug/lush/lush test_52.lua' + // bin should be in workspace + sh 'docker run --rm -v "$(pwd)":/work -w /work lush-app:latest ./bin/Debug/lush/lush test_52.lua' } } } @@ -81,4 +76,4 @@ pipeline { sh 'docker rmi lush-app:latest || true' } } -} \ No newline at end of file +} From 50092992fb6d7c149195402252be92d7cf0b7ec2 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 22:54:18 -0500 Subject: [PATCH 12/33] Added liblua5.4-dev package for build --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 6aa22ea..3ec9fe0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,8 @@ RUN apt-get update && apt-get install -y \ build-essential \ wget \ unzip \ + lua5.4 \ + liblua5.4-dev \ && rm -rf /var/lib/apt/lists/* # Download and install Premake5 @@ -23,3 +25,4 @@ COPY . . # Generate the makefiles. This will be the default action if no other command is given. CMD ["premake5", "gmake2"] + From 92c575cedf8a40046113516f490a1d5e0a77337e Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 23:17:16 -0500 Subject: [PATCH 13/33] Fixed the header path for compat: preload compat modules for lua within lua-init block --- premake5.lua | 7 ++++++- src/lush.c | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/premake5.lua b/premake5.lua index 127e86e..20dfa8a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -31,7 +31,12 @@ files({ "lib/hashmap/**.h", "lib/hashmap/**.c", "lib/compat53/c-api/compat-5.3.h", - "lib/compat53/c-api/compat-5.3.c" + "lib/compat53/c-api/compat-5.3.c", + "lib/compat53/lbitlib.c", + "lib/compat53/liolib.c", + "lib/compat53/lstrlib.c", + "lib/compat53/ltablib.c", + "lib/compat53/lutf8lib.c" }) defines({ 'LUSH_VERSION="0.3.2"', 'COMPAT53_PREFIX=""' }) diff --git a/src/lush.c b/src/lush.c index 49b205e..8beed6a 100644 --- a/src/lush.c +++ b/src/lush.c @@ -21,7 +21,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include "lua.h" #include "lua_api.h" #include "lualib.h" -#include "../lib/compat53/c-api/compat-5.3.h" +#include "compat-5.3.h" #include #include #include @@ -43,6 +43,10 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #include #include +// Forward declare the open functions for the compat C modules we need to preload +int luaopen_bit32 (lua_State *L); +int luaopen_utf8 (lua_State *L); + #define BUFFER_SIZE 1024 #define MAX_GLOB 512 @@ -1489,6 +1493,23 @@ int main(int argc, char *argv[]) { // init lua state lua_State *L = luaL_newstate(); luaL_openlibs(L); + + // --- Pre-load compat modules --- + // This is to make C modules available to Lua + luaL_getglobal(L, "package"); + luaL_getfield(L, -1, "preload"); + + // Preload bit32 for Lua 5.1 compatibility + lua_pushcfunction(L, luaopen_bit32); + lua_setfield(L, -2, "bit32"); + + // Preload utf8 for Lua 5.1/5.2 compatibility + lua_pushcfunction(L, luaopen_utf8); + lua_setfield(L, -2, "utf8"); + + // Pop package and preload tables + lua_pop(L, 2); + // --- End pre-loading --- luaopen_compat53(L); lua_register_api(L); lua_run_init(L); From 69001c115100a19955249bfb6ec45ad332cd5ae8 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 23:27:06 -0500 Subject: [PATCH 14/33] Compat53 library uses the floor function, which is part of the C math library (libm); removed the incorrect luaopen_compat53 call that was still present --- premake5.lua | 3 ++- src/lush.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/premake5.lua b/premake5.lua index 20dfa8a..3ec299a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -13,7 +13,8 @@ local lua_lib_path = "/usr/lib" if os.findlib("lua5.4") then lua_inc_path = "/usr/include/lua5.4" lua_lib_path = "/usr/lib/5.4" - links({ "lua5.4" }) +-- Readline for better interactive support, dl for dynamic loading, and m for the math library dependency + links({ "lua5.4", "readline", "dl", "m" }) else links({ "lua" }) end diff --git a/src/lush.c b/src/lush.c index 8beed6a..88d2998 100644 --- a/src/lush.c +++ b/src/lush.c @@ -1510,7 +1510,6 @@ int main(int argc, char *argv[]) { // Pop package and preload tables lua_pop(L, 2); // --- End pre-loading --- - luaopen_compat53(L); lua_register_api(L); lua_run_init(L); From 8f1b0212b219aa97116923876adfab5b90f5986a Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 23:30:27 -0500 Subject: [PATCH 15/33] src/lush.c ln:1500-1508: corrected the 'luaL' typos --- src/lush.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lush.c b/src/lush.c index 88d2998..82c272e 100644 --- a/src/lush.c +++ b/src/lush.c @@ -1492,12 +1492,12 @@ int main(int argc, char *argv[]) { // init lua state lua_State *L = luaL_newstate(); - luaL_openlibs(L); + lua_openlibs(L); // --- Pre-load compat modules --- // This is to make C modules available to Lua - luaL_getglobal(L, "package"); - luaL_getfield(L, -1, "preload"); + lua_getglobal(L, "package"); + lua_getfield(L, -1, "preload"); // Preload bit32 for Lua 5.1 compatibility lua_pushcfunction(L, luaopen_bit32); From 35347bef8d56d9bcd4594d212c9793b8ce59e6ba Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 23:33:27 -0500 Subject: [PATCH 16/33] Re-added luaL_openlibs(L); ln:1495 --- src/lush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lush.c b/src/lush.c index 82c272e..eef8f6d 100644 --- a/src/lush.c +++ b/src/lush.c @@ -1492,7 +1492,7 @@ int main(int argc, char *argv[]) { // init lua state lua_State *L = luaL_newstate(); - lua_openlibs(L); + luaL_openlibs(L); // --- Pre-load compat modules --- // This is to make C modules available to Lua From cfb49d6a6db3a735c54d3008778fe9c10afd0e0a Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 23:45:45 -0500 Subject: [PATCH 17/33] Instead of copying the compiled files out and then mounting a volume in to run the test, we'll do the entire compile and test sequence within a temporary container. Even though it copied the bin directory to the Jenkins workspace, the docker run command with the volume mount (-v) isn't finding it. --- Jenkinsfile | 83 ++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 53e580a..0f7f901 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,61 +14,60 @@ pipeline { } } } - stage('Compile Project & Extract Artifacts') { + stage('Compile & Test Project') { steps { script { - // Define a unique name for our temporary container + // Define a unique name for our temporary build container def containerName = "lush-build-${BUILD_NUMBER}" try { - echo 'Compiling the Lush project inside a container...' - // Run the entire build process in a single, named container. - // This container will be stopped but not removed - // which preserves its filesystem for the next step - sh "docker run --name ${containerName} lush-app:latest /bin/bash -c 'premake5 gmake2 && make'" - + echo 'Creating test script on Jenkins agent...' + sh ''' + cat <<'EOF' > test_52.lua + -- Lua 5.2-specific features + print("--- Running Lua 5.2 Compatibility Test ---") + local _ENV = { print = print, x = 123 } -- lexical environments + function show_x() + print("x =", x) + end + show_x() + -- Bitwise ops (added in 5.2) + local a, b = 0x5, 0x3 + print("Bitwise AND:", a & b) + -- load() replaces loadstring() (binary and text) + local f = load("return 10 + 20") + print("Loaded result:", f()) + -- table.pack / table.unpack + local t = table.pack(1, 2, 3, nil, 5) + print("Packed length:", t.n) + print("Unpacked values:", table.unpack(t, 1, t.n)) + print("--- Test Complete ---") + EOF + ''' + + echo 'Creating and starting the build container...' + // Create the container and keep it running in the background + sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" + + echo 'Copying test script into the container...' + sh "docker cp test_52.lua ${containerName}:/app/test_52.lua" + + echo 'Compiling and running tests inside the container...' + sh "docker exec ${containerName} /bin/bash -c 'premake5 gmake2 && make && ./bin/Debug/lush/lush test_52.lua'" + echo 'Extracting compiled binary from the container...' - // Copy the 'bin' directory - // from the container's filesystem to the Jenkins workspace. + // This is good practice for storing build artifacts sh "docker cp ${containerName}:/app/bin ./" + } finally { + // This block ensures the build container is always stopped and removed echo "Cleaning up build container: ${containerName}" - sh "docker rm ${containerName} || true" + sh "docker stop ${containerName} >/dev/null 2>&1 || true" + sh "docker rm ${containerName} >/dev/null 2>&1 || true" } } } } - stage('Run Lua 5.2 Compatibility Test') { - steps { - script { - echo 'Running the Lua 5.2 compatibility test script...' - sh ''' - cat <<'EOF' > test_52.lua - -- Lua 5.2-specific features - print("--- Running Lua 5.2 Compatibility Test ---") - local _ENV = { print = print, x = 123 } -- lexical environments - function show_x() - print("x =", x) - end - show_x() - -- Bitwise ops (added in 5.2) - local a, b = 0x5, 0x3 - print("Bitwise AND:", a & b) - -- load() replaces loadstring() (binary and text) - local f = load("return 10 + 20") - print("Loaded result:", f()) - -- table.pack / table.unpack - local t = table.pack(1, 2, 3, nil, 5) - print("Packed length:", t.n) - print("Unpacked values:", table.unpack(t, 1, t.n)) - print("--- Test Complete ---") - EOF - ''' - // bin should be in workspace - sh 'docker run --rm -v "$(pwd)":/work -w /work lush-app:latest ./bin/Debug/lush/lush test_52.lua' - } - } - } } post { always { From eed45531bf1c9343810c39a87e6813f8e4c9c6dd Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Tue, 22 Jul 2025 23:53:56 -0500 Subject: [PATCH 18/33] Ensure that the expected directory structure exists inside the container, just as install.sh expects: ln:27 --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3ec9fe0..1856412 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,8 @@ WORKDIR /app COPY . . -# Generate the makefiles. This will be the default action if no other command is given. +# Creates the .lush config directory in the root user home directory as install.sh expects. +RUN mkdir -p /root/.lush && cp -r ./.lush/scripts /root/.lush/ + CMD ["premake5", "gmake2"] From e9c1fc612d339fa89692f3a5562f9b88fa5b8f20 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 00:05:56 -0500 Subject: [PATCH 19/33] Copying the ENTIRE subdirectory as expected: ln:27 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1856412..ac570c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ WORKDIR /app COPY . . # Creates the .lush config directory in the root user home directory as install.sh expects. -RUN mkdir -p /root/.lush && cp -r ./.lush/scripts /root/.lush/ +RUN mkdir -p /root/.lush && cp -r ./.lush/* /root/.lush/ CMD ["premake5", "gmake2"] From e4b34ef9f512f2374a6568aac179edc599946d8d Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 00:13:09 -0500 Subject: [PATCH 20/33] This final change corrects the test script to align with what the compat53 library actually provides: the compat53 library is designed to bring Lua 5.1/5.2 up to the API level of 5.3, but it doesn't add new syntax to the parser, such as the & bitwise operator.: ln:25-47 --- Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0f7f901..122424f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -31,9 +31,10 @@ pipeline { print("x =", x) end show_x() - -- Bitwise ops (added in 5.2) + -- Bitwise ops (using the bit32 library provided by compat53) + local bit32 = require("bit32") local a, b = 0x5, 0x3 - print("Bitwise AND:", a & b) + print("Bitwise AND:", bit32.band(a, b)) -- load() replaces loadstring() (binary and text) local f = load("return 10 + 20") print("Loaded result:", f()) @@ -44,7 +45,6 @@ pipeline { print("--- Test Complete ---") EOF ''' - echo 'Creating and starting the build container...' // Create the container and keep it running in the background sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" From a66d54c6f16f26999f4dca111b5197fddd696744 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 00:19:04 -0500 Subject: [PATCH 21/33] Removed the problematic _ENV;compat53 DOES NOT provide lexical scoping with _ENV: ln:25-64 --- Jenkinsfile | 60 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 122424f..3293c99 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -24,27 +24,45 @@ pipeline { echo 'Creating test script on Jenkins agent...' sh ''' cat <<'EOF' > test_52.lua - -- Lua 5.2-specific features - print("--- Running Lua 5.2 Compatibility Test ---") - local _ENV = { print = print, x = 123 } -- lexical environments - function show_x() - print("x =", x) - end - show_x() - -- Bitwise ops (using the bit32 library provided by compat53) - local bit32 = require("bit32") - local a, b = 0x5, 0x3 - print("Bitwise AND:", bit32.band(a, b)) - -- load() replaces loadstring() (binary and text) - local f = load("return 10 + 20") - print("Loaded result:", f()) - -- table.pack / table.unpack - local t = table.pack(1, 2, 3, nil, 5) - print("Packed length:", t.n) - print("Unpacked values:", table.unpack(t, 1, t.n)) - print("--- Test Complete ---") - EOF +-- Lua 5.2-specific features test +print("--- Running Lua 5.2 Compatibility Test ---") + +-- Test 1: Basic functionality +print("Basic print test: Hello from Lush!") + +-- Test 2: Bitwise operations using bit32 library (provided by compat53) +local bit32 = require("bit32") +local a, b = 0x5, 0x3 +print("Bitwise AND of", a, "and", b, "=", bit32.band(a, b)) +print("Bitwise OR of", a, "and", b, "=", bit32.bor(a, b)) + +-- Test 3: load() function (replaces loadstring in Lua 5.2) +local f = load("return 10 + 20") +if f then + print("Loaded function result:", f()) +else + print("Failed to load function") +end + +-- Test 4: table.pack and table.unpack +local t = table.pack(1, 2, 3, nil, 5) +print("Packed table length:", t.n) +print("First 3 values:", table.unpack(t, 1, 3)) + +-- Test 5: String operations +local str = "Hello, World!" +print("String length:", #str) +print("Substring:", string.sub(str, 1, 5)) + +-- Test 6: Math operations +print("Math operations:") +print(" sqrt(16) =", math.sqrt(16)) +print(" max(10, 20, 5) =", math.max(10, 20, 5)) + +print("--- Test Complete: All basic features working ---") +EOF ''' + echo 'Creating and starting the build container...' // Create the container and keep it running in the background sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" @@ -75,4 +93,4 @@ pipeline { sh 'docker rmi lush-app:latest || true' } } -} +} \ No newline at end of file From 7400ec4c52aab43b1036ec88d9dbd6260cf2d759 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 00:58:09 -0500 Subject: [PATCH 22/33] luaopen_bit32 is called during initialization. This means the bit32 library is already loaded and available in the global space for scripts running within lush. The test script in the Jenkinsfile just needs to call it directly without using require: ln:27-65: also removed gemini's weird copout at ln:38-39; wont be using gemini anymore for this boilerplate, since it's trying to (and failing to...) 'troubleshoot' for me, unprompted. --- Jenkinsfile | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3293c99..51a46d8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,5 @@ +// Jenkinsfile + pipeline { agent any @@ -30,24 +32,23 @@ print("--- Running Lua 5.2 Compatibility Test ---") -- Test 1: Basic functionality print("Basic print test: Hello from Lush!") --- Test 2: Bitwise operations using bit32 library (provided by compat53) -local bit32 = require("bit32") -local a, b = 0x5, 0x3 +-- Test 2: Bitwise operations using the preloaded bit32 library +-- The lush host preloads compat modules, so we don't need to 'require' it. +local a, b = 5, 3 print("Bitwise AND of", a, "and", b, "=", bit32.band(a, b)) print("Bitwise OR of", a, "and", b, "=", bit32.bor(a, b)) -- Test 3: load() function (replaces loadstring in Lua 5.2) -local f = load("return 10 + 20") +local f, err = load("return 10 + 20") if f then print("Loaded function result:", f()) else - print("Failed to load function") + print("Failed to load function:", err) end --- Test 4: table.pack and table.unpack -local t = table.pack(1, 2, 3, nil, 5) -print("Packed table length:", t.n) -print("First 3 values:", table.unpack(t, 1, 3)) +-- Test 4: table.unpack +local t = {1, 2, 3} +print("Unpacked values:", table.unpack(t)) -- Test 5: String operations local str = "Hello, World!" @@ -93,4 +94,4 @@ EOF sh 'docker rmi lush-app:latest || true' } } -} \ No newline at end of file +} From 18052989d5722ba9fe01361b53b98330198dbb1e Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 01:24:29 -0500 Subject: [PATCH 23/33] - The premake5.lua file has been updated to include the LUA_COMPAT_BITLIB compiler definition. This flag instructs the compat-5.3 submodule to build the actual bit32 library instead of a stub that throws a deprecated error. - The main function in src/lush.c is modified to explicitly load the bit32 and utf8 libraries into the global Lua state at startup using luaL_requiref. This makes them directly accessible to all scripts running in the shell, which is necessary for the test script to find and use the bit32 functions without a require() call. - Added a null check after luaL_newstate() in src/lush.c to ensure the Lua state is created successfully before its actually used. --- premake5.lua | 2 +- src/lush.c | 23 +++++++++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/premake5.lua b/premake5.lua index 3ec299a..1043c07 100644 --- a/premake5.lua +++ b/premake5.lua @@ -39,7 +39,7 @@ files({ "lib/compat53/ltablib.c", "lib/compat53/lutf8lib.c" }) -defines({ 'LUSH_VERSION="0.3.2"', 'COMPAT53_PREFIX=""' }) +defines({ 'LUSH_VERSION="0.3.2"', 'COMPAT53_PREFIX=""', 'LUA_COMPAT_BITLIB' }) filter("configurations:Debug") defines({ "DEBUG" }) diff --git a/src/lush.c b/src/lush.c index eef8f6d..b512a70 100644 --- a/src/lush.c +++ b/src/lush.c @@ -1492,23 +1492,18 @@ int main(int argc, char *argv[]) { // init lua state lua_State *L = luaL_newstate(); + if (!L) { + fprintf(stderr, "Failed to create Lua state\n"); + return -1; // or handle appropriately + } luaL_openlibs(L); - // --- Pre-load compat modules --- - // This is to make C modules available to Lua - lua_getglobal(L, "package"); - lua_getfield(L, -1, "preload"); - - // Preload bit32 for Lua 5.1 compatibility - lua_pushcfunction(L, luaopen_bit32); - lua_setfield(L, -2, "bit32"); - - // Preload utf8 for Lua 5.1/5.2 compatibility - lua_pushcfunction(L, luaopen_utf8); - lua_setfield(L, -2, "utf8"); + // --- Load compat modules and make them global --- + luaL_requiref(L, "bit32", luaopen_bit32, 1); + lua_pop(L, 1); // luaL_requiref leaves the module on the stack - // Pop package and preload tables - lua_pop(L, 2); + luaL_requiref(L, "utf8", luaopen_utf8, 1); + lua_pop(L, 1); // --- End pre-loading --- lua_register_api(L); lua_run_init(L); From b034e12d7e4e2433809f7aada72e57f712f12a3d Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 02:20:40 -0500 Subject: [PATCH 24/33] Removing the dependencies from lib/ --- .../workflows/bit32-multi-arch-tests.yml | 52 - .../.github/workflows/compat53-tests.yml | 69 - lib/compat53/.gitignore | 10 - lib/compat53/.travis.yml | 47 - lib/compat53/LICENSE | 21 - lib/compat53/README.md | 243 --- lib/compat53/c-api/compat-5.3.c | 957 ---------- lib/compat53/c-api/compat-5.3.h | 421 ----- lib/compat53/compat53/file_mt.lua | 71 - lib/compat53/compat53/init.lua | 325 ---- lib/compat53/compat53/module.lua | 894 ---------- lib/compat53/lbitlib.c | 243 --- lib/compat53/liolib.c | 776 -------- lib/compat53/lprefix.h | 282 --- lib/compat53/lstrlib.c | 1584 ----------------- lib/compat53/ltablib.c | 450 ----- lib/compat53/lutf8lib.c | 256 --- lib/compat53/rockspecs/bit32-5.3.5-1.rockspec | 28 - .../rockspecs/bit32-5.3.5.1-1.rockspec | 28 - lib/compat53/rockspecs/bit32-scm-1.rockspec | 28 - .../rockspecs/compat53-0.1-1.rockspec | 31 - .../rockspecs/compat53-0.11-1.rockspec | 33 - .../rockspecs/compat53-0.12-1.rockspec | 33 - .../rockspecs/compat53-0.13-1.rockspec | 32 - .../rockspecs/compat53-0.14-1.rockspec | 33 - .../rockspecs/compat53-0.14.1-1.rockspec | 33 - .../rockspecs/compat53-0.14.2-1.rockspec | 32 - .../rockspecs/compat53-0.14.3-1.rockspec | 32 - .../rockspecs/compat53-0.14.4-1.rockspec | 32 - .../rockspecs/compat53-0.2-1.rockspec | 32 - .../rockspecs/compat53-0.3-1.rockspec | 32 - .../rockspecs/compat53-0.4-1.rockspec | 32 - .../rockspecs/compat53-0.5-1.rockspec | 32 - .../rockspecs/compat53-0.7-1.rockspec | 32 - .../rockspecs/compat53-0.8-1.rockspec | 32 - .../rockspecs/compat53-scm-1.rockspec | 34 - lib/compat53/tests/test-bit32.lua | 10 - lib/compat53/tests/test.lua | 866 --------- lib/compat53/tests/testmod.c | 370 ---- lib/hashmap/hashmap.c | 69 - lib/hashmap/hashmap.h | 38 - 41 files changed, 8655 deletions(-) delete mode 100644 lib/compat53/.github/workflows/bit32-multi-arch-tests.yml delete mode 100644 lib/compat53/.github/workflows/compat53-tests.yml delete mode 100644 lib/compat53/.gitignore delete mode 100644 lib/compat53/.travis.yml delete mode 100644 lib/compat53/LICENSE delete mode 100644 lib/compat53/README.md delete mode 100644 lib/compat53/c-api/compat-5.3.c delete mode 100644 lib/compat53/c-api/compat-5.3.h delete mode 100644 lib/compat53/compat53/file_mt.lua delete mode 100644 lib/compat53/compat53/init.lua delete mode 100644 lib/compat53/compat53/module.lua delete mode 100644 lib/compat53/lbitlib.c delete mode 100644 lib/compat53/liolib.c delete mode 100644 lib/compat53/lprefix.h delete mode 100644 lib/compat53/lstrlib.c delete mode 100644 lib/compat53/ltablib.c delete mode 100644 lib/compat53/lutf8lib.c delete mode 100644 lib/compat53/rockspecs/bit32-5.3.5-1.rockspec delete mode 100644 lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec delete mode 100644 lib/compat53/rockspecs/bit32-scm-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.1-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.11-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.12-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.13-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.14-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.14.1-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.14.2-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.14.3-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.14.4-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.2-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.3-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.4-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.5-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.7-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-0.8-1.rockspec delete mode 100644 lib/compat53/rockspecs/compat53-scm-1.rockspec delete mode 100755 lib/compat53/tests/test-bit32.lua delete mode 100755 lib/compat53/tests/test.lua delete mode 100644 lib/compat53/tests/testmod.c delete mode 100644 lib/hashmap/hashmap.c delete mode 100644 lib/hashmap/hashmap.h diff --git a/lib/compat53/.github/workflows/bit32-multi-arch-tests.yml b/lib/compat53/.github/workflows/bit32-multi-arch-tests.yml deleted file mode 100644 index aff29db..0000000 --- a/lib/compat53/.github/workflows/bit32-multi-arch-tests.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: bit32-multi-arch-tests -on: - push: - branches: ["master"] - pull_request: -jobs: - bit32-test: - runs-on: ubuntu-latest - name: bit32 tests on ${{ matrix.luaVersion }} ${{ matrix.arch }} - strategy: - fail-fast: false - matrix: - luaVersion: ["5.1.5", "5.4.1"] - luaRocksVersion: ["3.3.1"] - arch: ["armv7", "aarch64"] - steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 - id: lua-cache - with: - path: .install/${{ matrix.arch }}/lua-${{ matrix.luaVersion }} - key: lua-on-linux-${{ matrix.arch }}-${{ matrix.luaVersion }} - - uses: uraimo/run-on-arch-action@v2 - with: - arch: ${{ matrix.arch }} - distro: ubuntu_rolling - githubToken: ${{ github.token }} - setup: | - mkdir -p ".install/${{ matrix.arch }}" - install: | - apt-get update -q -y - apt-get install -q -y curl unzip build-essential libreadline-dev libncurses-dev clang - rm -rf /var/lib/apt/lists/* - run: | - v() { - echo -n -e "\033[36m" >&2 - echo -n "# $*" >&2 - echo -e "\033[0m" >&2 - "$@" - } - export CC=clang - if [ "${{ steps.lua-cache.outputs.cache-hit }}" != true ]; then - (set -o pipefail; cd ".install/${{ matrix.arch }}" && v curl --fail --silent --location "http://www.lua.org/ftp/lua-${{ matrix.luaVersion }}.tar.gz" | tar xzpf -) - (cd ".install/${{ matrix.arch }}/lua-${{ matrix.luaVersion }}" && v make linux) - fi - (cd ".install/${{ matrix.arch }}/lua-${{ matrix.luaVersion }}" && v make install) - (set -o pipefail; cd .install && v curl --fail --silent --location "http://luarocks.org/releases/luarocks-${{ matrix.luaRocksVersion }}.tar.gz" | tar xzpf -) - (cd ".install/luarocks-${{ matrix.luaRocksVersion }}" && v ./configure && v make bootstrap) - eval "$(luarocks path)" - v luarocks make rockspecs/bit32-scm-1.rockspec - v lua tests/test-bit32.lua - diff --git a/lib/compat53/.github/workflows/compat53-tests.yml b/lib/compat53/.github/workflows/compat53-tests.yml deleted file mode 100644 index 623837f..0000000 --- a/lib/compat53/.github/workflows/compat53-tests.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: compat53-tests -on: - push: - branches: ["master"] - pull_request: -jobs: - compat53-test: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - luaVersion: "lua=5.1" - compiler: gcc - external: false - - luaVersion: "lua=5.1" - compiler: gcc - external: true - - luaVersion: "lua=5.1" - compiler: g++ - external: true - - luaVersion: "lua=5.1" - compiler: clang - external: false - - luaVersion: "luajit=@v2.1 --compat=none" - compiler: gcc - external: false - - luaVersion: "luajit=@v2.1 --compat=none" - compiler: gcc - external: true - - luaVersion: "luajit=@v2.1 --compat=all" - compiler: gcc - external: false - - luaVersion: "luajit=@v2.1 --compat=all" - compiler: gcc - external: true - - luaVersion: "lua=5.2" - compiler: gcc - external: false - - luaVersion: "lua=5.2" - compiler: gcc - external: true - - luaVersion: "lua=5.2" - compiler: g++ - external: true - steps: - - uses: actions/checkout@v2 - - name: install Lua - run: | - sudo apt install libreadline-dev - pip3 install --user hererocks - ~/.local/bin/hererocks old --${{ matrix.luaVersion }} - test -e old/bin/lua || (cd old/bin && ln -s luajit* lua) - ~/.local/bin/hererocks new --lua=5.3 - - name: compile C modules - run: | - export CC=${{ matrix.compiler }} CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC" - export DEF="" SRC="" - if [ "${{ matrix.external }}" = true ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC} - ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC} - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c liolib.c ${SRC} - - name: run test scripts - run: | - (cd old && bin/lua ../tests/test.lua) > old.txt - (cd new && bin/lua ../tests/test.lua) > new.txt - - name: compare script output - run: diff old.txt new.txt || true - diff --git a/lib/compat53/.gitignore b/lib/compat53/.gitignore deleted file mode 100644 index 67c1b76..0000000 --- a/lib/compat53/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# generated files -*.so -*.dll -*.o -*.obj -HISTO - -# vim temporaries -.*.swp - diff --git a/lib/compat53/.travis.yml b/lib/compat53/.travis.yml deleted file mode 100644 index 44ae3a0..0000000 --- a/lib/compat53/.travis.yml +++ /dev/null @@ -1,47 +0,0 @@ -language: c -compiler: gcc - -sudo: false - -env: - - LUA="lua=5.1" - - LUA="lua=5.1" EXTERNAL=true - - LUA="lua=5.1" COMPILER="g++" - - LUA="lua=5.1" EXTERNAL=true COMPILER="g++" - - LUA="luajit=@v2.1 --compat=none" - - LUA="luajit=@v2.1 --compat=none" EXTERNAL=true - - LUA="luajit=@v2.1 --compat=all" - - LUA="luajit=@v2.1 --compat=all" EXTERNAL=true - - LUA="lua=5.2" - - LUA="lua=5.2" EXTERNAL=true - - LUA="lua=5.2" COMPILER="g++" - - LUA="lua=5.2" EXTERNAL=true COMPILER="g++" - -branches: - only: - - master - -git: - depth: 3 - -notifications: - email: false - -before_install: - - pip install --user hererocks - - hererocks old --$LUA - - test -e old/bin/lua || (cd old/bin && ln -s luajit* lua) - - hererocks new --lua=5.3 - -install: - - export CC="${COMPILER:-gcc}" DEF="" SRC="" CFLAGS="-Wall -Wextra -Ic-api -O2 -fPIC" - - if [ "x${EXTERNAL:-}" = xtrue ]; then DEF="-DCOMPAT53_PREFIX=compat53" SRC="c-api/compat-5.3.c"; fi - - ${CC} ${CFLAGS} -Iold/include ${DEF} -shared -o old/testmod.so tests/testmod.c ${SRC} - - ${CC} ${CFLAGS} -Inew/include ${DEF} -shared -o new/testmod.so tests/testmod.c ${SRC} - - gcc ${CFLAGS} -Iold/include ${DEF} -shared -o old/compat53.so ltablib.c lutf8lib.c lstrlib.c liolib.c ${SRC} - -script: - - (cd old && bin/lua ../tests/test.lua) > old.txt - - (cd new && bin/lua ../tests/test.lua) > new.txt - - diff old.txt new.txt || true - diff --git a/lib/compat53/LICENSE b/lib/compat53/LICENSE deleted file mode 100644 index 193ed12..0000000 --- a/lib/compat53/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 1994-2020 Lua.org, PUC-Rio. -Copyright (C) 2013-2023 The Lua-Compat-5.3 authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/compat53/README.md b/lib/compat53/README.md deleted file mode 100644 index 3ee6acf..0000000 --- a/lib/compat53/README.md +++ /dev/null @@ -1,243 +0,0 @@ -[![Compat53 Status](https://github.com/lunarmodules/lua-compat-5.3/workflows/compat53-tests/badge.svg)](https://github.com/lunarmodules/lua-compat-5.3/actions?workflow=compat53-tests) -[![Bit32 Status](https://github.com/lunarmodules/lua-compat-5.3/workflows/bit32-multi-arch-tests/badge.svg)](https://github.com/lunarmodules/lua-compat-5.3/actions?workflow=bit32-multi-arch-tests) - -# lua-compat-5.3 - -Lua-5.3-style APIs for Lua 5.2 and 5.1. - -## What is it - -This is a small module that aims to make it easier to write code -in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua -5.3. This does *not* make Lua 5.2 (or even Lua 5.1) entirely -compatible with Lua 5.3, but it brings the API closer to that of Lua -5.3. - -It includes: - -* _For writing Lua_: The Lua module `compat53`, which can be require'd - from Lua scripts and run in Lua 5.1, 5.2, and 5.3, including a - backport of the `utf8` module, the 5.3 `table` module, and the - string packing functions straight from the Lua 5.3 sources. -* _For writing C_: A C header and file which can be linked to your - Lua module written in C, providing some functions from the C API - of Lua 5.3 that do not exist in Lua 5.2 or 5.1, making it easier to - write C code that compiles with all three versions of liblua. - -## How to use it - -### Lua module - -```lua -require("compat53") -``` - -`compat53` makes changes to your global environment and does not return -a meaningful return value, so the usual idiom of storing the return of -`require` in a local variable makes no sense. - -When run under Lua 5.3+, this module does nothing. - -When run under Lua 5.2 or 5.1, it replaces some of your standard -functions and adds new ones to bring your environment closer to that -of Lua 5.3. It also tries to load the backported `utf8`, `table`, and -string packing modules automatically. If unsuccessful, pure Lua -versions of the new `table` functions are used as a fallback, and -[Roberto's struct library][1] is tried for string packing. - -#### Lua submodules - -```lua -local _ENV = require("compat53.module") -if setfenv then setfenv(1, _ENV) end -``` - -The `compat53.module` module does not modify the global environment, -and so it is safe to use in modules without affecting other Lua files. -It is supposed to be set as the current environment (see above), i.e. -cherry picking individual functions from this module is expressly -*not* supported!). Not all features are available when using this -module (e.g. yieldable (x)pcall support, string/file methods, etc.), -so it is recommended to use plain `require("compat53")` whenever -possible. - -### C code - -There are two ways of adding the C API compatibility functions/macros to -your project: -* If `COMPAT53_PREFIX` is *not* `#define`d, `compat-5.3.h` `#include`s - `compat-5.3.c`, and all functions are made `static`. You don't have to - compile/link/add `compat-5.3.c` yourself. This is useful for one-file - projects. -* If `COMPAT53_PREFIX` is `#define`d, all exported functions are renamed - behind the scenes using this prefix to avoid linker conflicts with other - code using this package. This doesn't change the way you call the - compatibility functions in your code. You have to compile and link - `compat-5.3.c` to your project yourself. You can change the way the - functions are exported using the `COMPAT53_API` macro (e.g. if you need - some `__declspec` magic). While it is technically possible to use - the "lua" prefix (and it looks better in the debugger), this is - discouraged because LuaJIT has started to implement its own Lua 5.2+ - C API functions, and with the "lua" prefix you'd violate the - one-definition rule with recent LuaJIT versions. - -## What's implemented - -### Lua - -* the `utf8` module backported from the Lua 5.3 sources -* `string.pack`, `string.packsize`, and `string.unpack` from the Lua - 5.3 sources or from the `struct` module. (`struct` is not 100% - compatible to Lua 5.3's string packing!) (See [here][4]) -* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`, - and `math.ult` (see [here][5]) -* `assert` accepts non-string error messages -* `ipairs` respects `__index` metamethod -* `table.move` -* `table` library respects metamethods - -For Lua 5.1 additionally: -* `load` and `loadfile` accept `mode` and `env` parameters -* `table.pack` and `table.unpack` -* string patterns may contain embedded zeros (but see [here][6]) -* `string.rep` accepts `sep` argument -* `string.format` calls `tostring` on arguments for `%s` -* `math.log` accepts base argument -* `xpcall` takes additional arguments -* `pcall` and `xpcall` can execute functions that yield (see - [here][22] for a possible problem with `coroutine.running`) -* `pairs` respects `__pairs` metamethod (see [here][7]) -* `rawlen` (but `#` still doesn't respect `__len` for tables) -* `package.searchers` as alias for `package.loaders` -* `package.searchpath` (see [here][8]) -* `coroutine` functions dealing with the main coroutine (see - [here][22] for a possible problem with `coroutine.running`) -* `coroutine.create` accepts functions written in C -* return code of `os.execute` (see [here][9]) -* `io.write` and `file:write` return file handle -* `io.lines` and `file:lines` accept format arguments (like `io.read`) - (see [here][10] and [here][11]) -* `file:close` returns three results when a process is opened - with `io.popen` -* `debug.setmetatable` returns object -* `debug.getuservalue` (see [here][12]) -* `debug.setuservalue` (see [here][13]) - -### C - -* `lua_KContext` (see [here][14]) -* `lua_KFunction` (see [here][14]) -* `lua_dump` (extra `strip` parameter, ignored, see [here][15]) -* `lua_getextraspace` (limited compatibilitiy, see [here][24]) -* `lua_getfield` (return value) -* `lua_geti` and `lua_seti` -* `lua_getglobal` (return value) -* `lua_getmetafield` (return value) -* `lua_gettable` (return value) -* `lua_getuservalue` (limited compatibility, see [here][16]) -* `lua_setuservalue` (limited compatibility, see [here][17]) -* `lua_isinteger` -* `lua_numbertointeger` -* `lua_callk` and `lua_pcallk` (limited compatibility, see [here][14]) -* `lua_resume` -* `lua_rawget` and `lua_rawgeti` (return values) -* `lua_rawgetp` and `lua_rawsetp` -* `luaL_requiref` (now checks `package.loaded` first) -* `lua_rotate` -* `lua_stringtonumber` (see [here][18]) - -For Lua 5.1 additionally: -* `LUA_OK` -* `LUA_ERRGCMM` -* `LUA_OP*` macros for `lua_arith` and `lua_compare` -* `LUA_FILEHANDLE` -* `lua_Unsigned` -* `luaL_Stream` (limited compatibility, see [here][19]) -* `lua_absindex` -* `lua_arith` (see [here][20]) -* `lua_compare` -* `lua_len`, `lua_rawlen`, and `luaL_len` -* `lua_load` (mode argument) -* `lua_pushstring`, `lua_pushlstring` (return value) -* `lua_copy` -* `lua_pushglobaltable` -* `luaL_testudata` -* `luaL_setfuncs`, `luaL_newlibtable`, and `luaL_newlib` -* `luaL_setmetatable` -* `luaL_getsubtable` -* `luaL_traceback` -* `luaL_execresult` -* `luaL_fileresult` -* `luaL_loadbufferx` -* `luaL_loadfilex` -* `luaL_checkversion` (with empty body, only to avoid compile errors, - see [here][21]) -* `luaL_tolstring` -* `luaL_buffinitsize`, `luaL_prepbuffsize`, and `luaL_pushresultsize` - (see [here][22]) -* `lua_pushunsigned`, `lua_tounsignedx`, `lua_tounsigned`, - `luaL_checkunsigned`, `luaL_optunsigned`, if - `LUA_COMPAT_APIINTCASTS` is defined. - -## What's not implemented - -* bit operators -* integer division operator -* utf8 escape sequences -* 64 bit integers -* `coroutine.isyieldable` -* Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See - [`lua-compat-5.2`][2] for a detailed list. -* the following C API functions/macros: - * `lua_isyieldable` - * `lua_arith` (new operators missing) - * `lua_push(v)fstring` (new formats missing) - * `lua_upvalueid` (5.1) - * `lua_upvaluejoin` (5.1) - * `lua_version` (5.1) - * `lua_yieldk` (5.1) - -## See also - -* For Lua-5.2-style APIs under Lua 5.1, see [lua-compat-5.2][2], - which also is the basis for most of the code in this project. -* For Lua-5.1-style APIs under Lua 5.0, see [Compat-5.1][3] - -## Credits - -This package contains code written by: - -* [The Lua Team](http://www.lua.org) -* Philipp Janda ([@siffiejoe](http://github.com/siffiejoe)) -* Tomás Guisasola Gorham ([@tomasguisasola](http://github.com/tomasguisasola)) -* Hisham Muhammad ([@hishamhm](http://github.com/hishamhm)) -* Renato Maia ([@renatomaia](http://github.com/renatomaia)) -* [@ThePhD](http://github.com/ThePhD) -* [@Daurnimator](http://github.com/Daurnimator) - - - [1]: http://www.inf.puc-rio.br/~roberto/struct/ - [2]: http://github.com/lunarmodules/lua-compat-5.2/ - [3]: http://lunarmodules.org/compat/ - [4]: https://github.com/lunarmodules/lua-compat-5.3/wiki/string_packing - [5]: https://github.com/lunarmodules/lua-compat-5.3/wiki/math.type - [6]: https://github.com/lunarmodules/lua-compat-5.3/wiki/pattern_matching - [7]: https://github.com/lunarmodules/lua-compat-5.3/wiki/pairs - [8]: https://github.com/lunarmodules/lua-compat-5.3/wiki/package.searchpath - [9]: https://github.com/lunarmodules/lua-compat-5.3/wiki/os.execute - [10]: https://github.com/lunarmodules/lua-compat-5.3/wiki/io.lines - [11]: https://github.com/lunarmodules/lua-compat-5.3/wiki/file.lines - [12]: https://github.com/lunarmodules/lua-compat-5.3/wiki/debug.getuservalue - [13]: https://github.com/lunarmodules/lua-compat-5.3/wiki/debug.setuservalue - [14]: https://github.com/lunarmodules/lua-compat-5.3/wiki/yieldable_c_functions - [15]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_dump - [16]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_getuservalue - [17]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_setuservalue - [18]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_stringtonumber - [19]: https://github.com/lunarmodules/lua-compat-5.3/wiki/luaL_Stream - [20]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_arith - [21]: https://github.com/lunarmodules/lua-compat-5.3/wiki/luaL_checkversion - [22]: https://github.com/lunarmodules/lua-compat-5.3/wiki/luaL_Buffer - [23]: https://github.com/lunarmodules/lua-compat-5.3/wiki/coroutine.running - [24]: https://github.com/lunarmodules/lua-compat-5.3/wiki/lua_getextraspace - diff --git a/lib/compat53/c-api/compat-5.3.c b/lib/compat53/c-api/compat-5.3.c deleted file mode 100644 index 1901a82..0000000 --- a/lib/compat53/c-api/compat-5.3.c +++ /dev/null @@ -1,957 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "compat-5.3.h" - -/* don't compile it again if it already is included via compat53.h */ -#ifndef COMPAT53_C_ -#define COMPAT53_C_ - - - -/* definitions for Lua 5.1 only */ -#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 - -#ifndef COMPAT53_FOPEN_NO_LOCK -# if defined(_MSC_VER) -# define COMPAT53_FOPEN_NO_LOCK 1 -# else /* otherwise */ -# define COMPAT53_FOPEN_NO_LOCK 0 -# endif /* VC++ only so far */ -#endif /* No-lock fopen_s usage if possible */ - -#if defined(_MSC_VER) && COMPAT53_FOPEN_NO_LOCK -# include -#endif /* VC++ _fsopen for share-allowed file read */ - -#ifndef COMPAT53_HAVE_STRERROR_R -# if (!defined(_WIN32)) && \ - ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ - (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || \ - defined(__APPLE__)) -# define COMPAT53_HAVE_STRERROR_R 1 -# else /* none of the defines matched: define to 0 */ -# define COMPAT53_HAVE_STRERROR_R 0 -# endif /* have strerror_r of some form */ -#endif /* strerror_r */ - -#ifndef COMPAT53_HAVE_STRERROR_S -# if defined(_MSC_VER) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \ - defined(__STDC_LIB_EXT1__) && __STDC_LIB_EXT1__) -# define COMPAT53_HAVE_STRERROR_S 1 -# else /* not VC++ or C11 */ -# define COMPAT53_HAVE_STRERROR_S 0 -# endif /* strerror_s from VC++ or C11 */ -#endif /* strerror_s */ - -#ifndef COMPAT53_LUA_FILE_BUFFER_SIZE -# define COMPAT53_LUA_FILE_BUFFER_SIZE 4096 -#endif /* Lua File Buffer Size */ - - -static char* compat53_strerror (int en, char* buff, size_t sz) { -#if COMPAT53_HAVE_STRERROR_R - /* use strerror_r here, because it's available on these specific platforms */ - if (sz > 0) { - buff[0] = '\0'; - /* we don't care whether the GNU version or the XSI version is used: */ - if (strerror_r(en, buff, sz)) { - /* Yes, we really DO want to ignore the return value! - * GCC makes that extra hard, not even a (void) cast will do. */ - } - if (buff[0] == '\0') { - /* Buffer is unchanged, so we probably have called GNU strerror_r which - * returned a static constant string. Chances are that strerror will - * return the same static constant string and therefore be thread-safe. */ - return strerror(en); - } - } - return buff; /* sz is 0 *or* strerror_r wrote into the buffer */ -#elif COMPAT53_HAVE_STRERROR_S - /* for MSVC and other C11 implementations, use strerror_s since it's - * provided by default by the libraries */ - strerror_s(buff, sz, en); - return buff; -#else - /* fallback, but strerror is not guaranteed to be threadsafe due to modifying - * errno itself and some impls not locking a static buffer for it ... but most - * known systems have threadsafe errno: this might only change if the locale - * is changed out from under someone while this function is being called */ - (void)buff; - (void)sz; - return strerror(en); -#endif -} - - -COMPAT53_API int lua_absindex (lua_State *L, int i) { - if (i < 0 && i > LUA_REGISTRYINDEX) - i += lua_gettop(L) + 1; - return i; -} - - -static void compat53_call_lua (lua_State *L, char const code[], size_t len, - int nargs, int nret) { - lua_rawgetp(L, LUA_REGISTRYINDEX, (void*)code); - if (lua_type(L, -1) != LUA_TFUNCTION) { - lua_pop(L, 1); - if (luaL_loadbuffer(L, code, len, "=none")) - lua_error(L); - lua_pushvalue(L, -1); - lua_rawsetp(L, LUA_REGISTRYINDEX, (void*)code); - } - lua_insert(L, -nargs-1); - lua_call(L, nargs, nret); -} - - -static const char compat53_arith_code[] = - "local op,a,b=...\n" - "if op==0 then return a+b\n" - "elseif op==1 then return a-b\n" - "elseif op==2 then return a*b\n" - "elseif op==3 then return a/b\n" - "elseif op==4 then return a%b\n" - "elseif op==5 then return a^b\n" - "elseif op==6 then return -a\n" - "end\n"; - -COMPAT53_API void lua_arith (lua_State *L, int op) { - if (op < LUA_OPADD || op > LUA_OPUNM) - luaL_error(L, "invalid 'op' argument for lua_arith"); - luaL_checkstack(L, 5, "not enough stack slots"); - if (op == LUA_OPUNM) - lua_pushvalue(L, -1); - lua_pushnumber(L, op); - lua_insert(L, -3); - compat53_call_lua(L, compat53_arith_code, - sizeof(compat53_arith_code)-1, 3, 1); -} - - -static const char compat53_compare_code[] = - "local a,b=...\n" - "return a<=b\n"; - -COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op) { - int result = 0; - switch (op) { - case LUA_OPEQ: - return lua_equal(L, idx1, idx2); - case LUA_OPLT: - return lua_lessthan(L, idx1, idx2); - case LUA_OPLE: - luaL_checkstack(L, 5, "not enough stack slots"); - idx1 = lua_absindex(L, idx1); - idx2 = lua_absindex(L, idx2); - lua_pushvalue(L, idx1); - lua_pushvalue(L, idx2); - compat53_call_lua(L, compat53_compare_code, - sizeof(compat53_compare_code)-1, 2, 1); - result = lua_toboolean(L, -1); - lua_pop(L, 1); - return result; - default: - luaL_error(L, "invalid 'op' argument for lua_compare"); - } - return 0; -} - - -COMPAT53_API void lua_copy (lua_State *L, int from, int to) { - int abs_to = lua_absindex(L, to); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushvalue(L, from); - lua_replace(L, abs_to); -} - - -COMPAT53_API void lua_len (lua_State *L, int i) { - switch (lua_type(L, i)) { - case LUA_TSTRING: - lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); - break; - case LUA_TTABLE: - if (!luaL_callmeta(L, i, "__len")) - lua_pushnumber(L, (lua_Number)lua_objlen(L, i)); - break; - case LUA_TUSERDATA: - if (luaL_callmeta(L, i, "__len")) - break; - /* FALLTHROUGH */ - default: - luaL_error(L, "attempt to get length of a %s value", - lua_typename(L, lua_type(L, i))); - } -} - - -COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p) { - int abs_i = lua_absindex(L, i); - lua_pushlightuserdata(L, (void*)p); - lua_rawget(L, abs_i); - return lua_type(L, -1); -} - -COMPAT53_API void lua_rawsetp (lua_State *L, int i, const void *p) { - int abs_i = lua_absindex(L, i); - luaL_checkstack(L, 1, "not enough stack slots"); - lua_pushlightuserdata(L, (void*)p); - lua_insert(L, -2); - lua_rawset(L, abs_i); -} - - -COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum) { - lua_Number n = lua_tonumber(L, i); - if (isnum != NULL) { - *isnum = (n != 0 || lua_isnumber(L, i)); - } - return n; -} - - -COMPAT53_API void luaL_checkversion (lua_State *L) { - (void)L; -} - - -COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg) { - if (!lua_checkstack(L, sp+LUA_MINSTACK)) { - if (msg != NULL) - luaL_error(L, "stack overflow (%s)", msg); - else { - lua_pushliteral(L, "stack overflow"); - lua_error(L); - } - } -} - - -COMPAT53_API int luaL_getsubtable (lua_State *L, int i, const char *name) { - int abs_i = lua_absindex(L, i); - luaL_checkstack(L, 3, "not enough stack slots"); - lua_pushstring(L, name); - lua_gettable(L, abs_i); - if (lua_istable(L, -1)) - return 1; - lua_pop(L, 1); - lua_newtable(L); - lua_pushstring(L, name); - lua_pushvalue(L, -2); - lua_settable(L, abs_i); - return 0; -} - - -COMPAT53_API lua_Integer luaL_len (lua_State *L, int i) { - lua_Integer res = 0; - int isnum = 0; - luaL_checkstack(L, 1, "not enough stack slots"); - lua_len(L, i); - res = lua_tointegerx(L, -1, &isnum); - lua_pop(L, 1); - if (!isnum) - luaL_error(L, "object length is not an integer"); - return res; -} - - -COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup+1, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - lua_pushstring(L, l->name); - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup + 1)); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ - } - lua_pop(L, nup); /* remove upvalues */ -} - - -COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname) { - luaL_checkstack(L, 1, "not enough stack slots"); - luaL_getmetatable(L, tname); - lua_setmetatable(L, -2); -} - - -COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname) { - void *p = lua_touserdata(L, i); - luaL_checkstack(L, 2, "not enough stack slots"); - if (p == NULL || !lua_getmetatable(L, i)) - return NULL; - else { - int res = 0; - luaL_getmetatable(L, tname); - res = lua_rawequal(L, -1, -2); - lua_pop(L, 2); - if (!res) - p = NULL; - } - return p; -} - - -static int compat53_countlevels (lua_State *L) { - lua_Debug ar; - int li = 1, le = 1; - /* find an upper bound */ - while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } - /* do a binary search */ - while (li < le) { - int m = (li + le)/2; - if (lua_getstack(L, m, &ar)) li = m + 1; - else le = m; - } - return le - 1; -} - -static int compat53_findfield (lua_State *L, int objidx, int level) { - if (level == 0 || !lua_istable(L, -1)) - return 0; /* not found */ - lua_pushnil(L); /* start 'next' loop */ - while (lua_next(L, -2)) { /* for each pair in table */ - if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ - if (lua_rawequal(L, objidx, -1)) { /* found object? */ - lua_pop(L, 1); /* remove value (but keep name) */ - return 1; - } - else if (compat53_findfield(L, objidx, level - 1)) { /* try recursively */ - lua_remove(L, -2); /* remove table (but keep name) */ - lua_pushliteral(L, "."); - lua_insert(L, -2); /* place '.' between the two names */ - lua_concat(L, 3); - return 1; - } - } - lua_pop(L, 1); /* remove value */ - } - return 0; /* not found */ -} - -static int compat53_pushglobalfuncname (lua_State *L, lua_Debug *ar) { - int top = lua_gettop(L); - lua_getinfo(L, "f", ar); /* push function */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - if (compat53_findfield(L, top + 1, 2)) { - lua_copy(L, -1, top + 1); /* move name to proper place */ - lua_pop(L, 2); /* remove pushed values */ - return 1; - } - else { - lua_settop(L, top); /* remove function and global table */ - return 0; - } -} - -static void compat53_pushfuncname (lua_State *L, lua_Debug *ar) { - if (*ar->namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, "function " LUA_QS, ar->name); - else if (*ar->what == 'm') /* main? */ - lua_pushliteral(L, "main chunk"); - else if (*ar->what == 'C') { - if (compat53_pushglobalfuncname(L, ar)) { - lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else - lua_pushliteral(L, "?"); - } - else - lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); -} - -#define COMPAT53_LEVELS1 12 /* size of the first part of the stack */ -#define COMPAT53_LEVELS2 10 /* size of the second part of the stack */ - -COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, - const char *msg, int level) { - lua_Debug ar; - int top = lua_gettop(L); - int numlevels = compat53_countlevels(L1); - int mark = (numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2) ? COMPAT53_LEVELS1 : 0; - if (msg) lua_pushfstring(L, "%s\n", msg); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, &ar)) { - if (level == mark) { /* too many levels? */ - lua_pushliteral(L, "\n\t..."); /* add a '...' */ - level = numlevels - COMPAT53_LEVELS2; /* and skip to last ones */ - } - else { - lua_getinfo(L1, "Slnt", &ar); - lua_pushfstring(L, "\n\t%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - lua_pushliteral(L, " in "); - compat53_pushfuncname(L, &ar); - lua_concat(L, lua_gettop(L) - top); - } - } - lua_concat(L, lua_gettop(L) - top); -} - - -COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { - const char *serr = NULL; - int en = errno; /* calls to Lua API may change this value */ - char buf[512] = { 0 }; - if (stat) { - lua_pushboolean(L, 1); - return 1; - } - else { - lua_pushnil(L); - serr = compat53_strerror(en, buf, sizeof(buf)); - if (fname) - lua_pushfstring(L, "%s: %s", fname, serr); - else - lua_pushstring(L, serr); - lua_pushnumber(L, (lua_Number)en); - return 3; - } -} - - -static int compat53_checkmode (lua_State *L, const char *mode, const char *modename, int err) { - if (mode && strchr(mode, modename[0]) == NULL) { - lua_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", modename, mode); - return err; - } - return LUA_OK; -} - - -typedef struct { - lua_Reader reader; - void *ud; - int has_peeked_data; - const char *peeked_data; - size_t peeked_data_size; -} compat53_reader_data; - - -static const char *compat53_reader (lua_State *L, void *ud, size_t *size) { - compat53_reader_data *data = (compat53_reader_data *)ud; - if (data->has_peeked_data) { - data->has_peeked_data = 0; - *size = data->peeked_data_size; - return data->peeked_data; - } else - return data->reader(L, data->ud, size); -} - - -COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *source, const char *mode) { - int status = LUA_OK; - compat53_reader_data compat53_data = { 0, NULL, 1, 0, 0 }; - compat53_data.reader = reader; - compat53_data.ud = data; - compat53_data.peeked_data = reader(L, data, &(compat53_data.peeked_data_size)); - if (compat53_data.peeked_data && compat53_data.peeked_data_size && - compat53_data.peeked_data[0] == LUA_SIGNATURE[0]) /* binary file? */ - status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); - else - status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); - if (status != LUA_OK) - return status; - /* we need to call the original 5.1 version of lua_load! */ -#undef lua_load - return lua_load(L, compat53_reader, &compat53_data, source); -#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) -} - - -typedef struct { - int n; /* number of pre-read characters */ - FILE *f; /* file being read */ - char buff[COMPAT53_LUA_FILE_BUFFER_SIZE]; /* area for reading file */ -} compat53_LoadF; - - -static const char *compat53_getF (lua_State *L, void *ud, size_t *size) { - compat53_LoadF *lf = (compat53_LoadF *)ud; - (void)L; /* not used */ - if (lf->n > 0) { /* are there pre-read characters to be read? */ - *size = lf->n; /* return them (chars already in buffer) */ - lf->n = 0; /* no more pre-read characters */ - } - else { /* read a block from file */ - /* 'fread' can return > 0 *and* set the EOF flag. If next call to - 'compat53_getF' called 'fread', it might still wait for user input. - The next check avoids this problem. */ - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ - } - return lf->buff; -} - - -static int compat53_errfile (lua_State *L, const char *what, int fnameindex) { - char buf[512] = {0}; - const char *serr = compat53_strerror(errno, buf, sizeof(buf)); - const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); - lua_remove(L, fnameindex); - return LUA_ERRFILE; -} - - -static int compat53_skipBOM (compat53_LoadF *lf) { - const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ - int c; - lf->n = 0; - do { - c = getc(lf->f); - if (c == EOF || c != *(const unsigned char *)p++) return c; - lf->buff[lf->n++] = (char)c; /* to be read by the parser */ - } while (*p != '\0'); - lf->n = 0; /* prefix matched; discard it */ - return getc(lf->f); /* return next character */ -} - - -/* -** reads the first character of file 'f' and skips an optional BOM mark -** in its beginning plus its first line if it starts with '#'. Returns -** true if it skipped the first line. In any case, '*cp' has the -** first "valid" character of the file (after the optional BOM and -** a first-line comment). -*/ -static int compat53_skipcomment (compat53_LoadF *lf, int *cp) { - int c = *cp = compat53_skipBOM(lf); - if (c == '#') { /* first line is a comment (Unix exec. file)? */ - do { /* skip first line */ - c = getc(lf->f); - } while (c != EOF && c != '\n'); - *cp = getc(lf->f); /* skip end-of-line, if present */ - return 1; /* there was a comment */ - } - else return 0; /* no comment */ -} - - -COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { - compat53_LoadF lf; - int status, readstatus; - int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - if (filename == NULL) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - } - else { - lua_pushfstring(L, "@%s", filename); -#if defined(_MSC_VER) - /* This code is here to stop a deprecation error that stops builds - * if a certain macro is defined. While normally not caring would - * be best, some header-only libraries and builds can't afford to - * dictate this to the user. A quick check shows that fopen_s this - * goes back to VS 2005, and _fsopen goes back to VS 2003 .NET, - * possibly even before that so we don't need to do any version - * number checks, since this has been there since forever. */ - - /* TO USER: if you want the behavior of typical fopen_s/fopen, - * which does lock the file on VC++, define the macro used below to 0 */ -#if COMPAT53_FOPEN_NO_LOCK - lf.f = _fsopen(filename, "r", _SH_DENYNO); /* do not lock the file in any way */ - if (lf.f == NULL) - return compat53_errfile(L, "open", fnameindex); -#else /* use default locking version */ - if (fopen_s(&lf.f, filename, "r") != 0) - return compat53_errfile(L, "open", fnameindex); -#endif /* Locking vs. No-locking fopen variants */ -#else - lf.f = fopen(filename, "r"); /* default stdlib doesn't forcefully lock files here */ - if (lf.f == NULL) return compat53_errfile(L, "open", fnameindex); -#endif - } - if (compat53_skipcomment(&lf, &c)) /* read initial portion */ - lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ - if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ -#if defined(_MSC_VER) - if (freopen_s(&lf.f, filename, "rb", lf.f) != 0) - return compat53_errfile(L, "reopen", fnameindex); -#else - lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ - if (lf.f == NULL) return compat53_errfile(L, "reopen", fnameindex); -#endif - compat53_skipcomment(&lf, &c); /* re-read initial portion */ - } - if (c != EOF) - lf.buff[lf.n++] = (char)c; /* 'c' is the first character of the stream */ - status = lua_load(L, &compat53_getF, &lf, lua_tostring(L, -1), mode); - readstatus = ferror(lf.f); - if (filename) fclose(lf.f); /* close file (even in case of errors) */ - if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ - return compat53_errfile(L, "read", fnameindex); - } - lua_remove(L, fnameindex); - return status; -} - - -COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode) { - int status = LUA_OK; - if (sz > 0 && buff[0] == LUA_SIGNATURE[0]) { - status = compat53_checkmode(L, mode, "binary", LUA_ERRSYNTAX); - } - else { - status = compat53_checkmode(L, mode, "text", LUA_ERRSYNTAX); - } - if (status != LUA_OK) - return status; - return luaL_loadbuffer(L, buff, sz, name); -} - - -#if !defined(l_inspectstat) && \ - (defined(unix) || defined(__unix) || defined(__unix__) || \ - defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \ - (defined(__APPLE__) && defined(__MACH__))) -/* some form of unix; check feature macros in unistd.h for details */ -# include -/* check posix version; the relevant include files and macros probably - * were available before 2001, but I'm not sure */ -# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L -# include -# define l_inspectstat(stat,what) \ - if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ - else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } -# endif -#endif - -/* provide default (no-op) version */ -#if !defined(l_inspectstat) -# define l_inspectstat(stat,what) ((void)0) -#endif - - -COMPAT53_API int luaL_execresult (lua_State *L, int stat) { - const char *what = "exit"; - if (stat == -1) - return luaL_fileresult(L, 0, NULL); - else { - l_inspectstat(stat, what); - if (*what == 'e' && stat == 0) - lua_pushboolean(L, 1); - else - lua_pushnil(L); - lua_pushstring(L, what); - lua_pushinteger(L, stat); - return 3; - } -} - - -COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B) { - /* make it crash if used via pointer to a 5.1-style luaL_Buffer */ - B->b.p = NULL; - B->b.L = NULL; - B->b.lvl = 0; - /* reuse the buffer from the 5.1-style luaL_Buffer though! */ - B->ptr = B->b.buffer; - B->capacity = LUAL_BUFFERSIZE; - B->nelems = 0; - B->L2 = L; -} - - -COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s) { - if (B->capacity - B->nelems < s) { /* needs to grow */ - char* newptr = NULL; - size_t newcap = B->capacity * 2; - if (newcap - B->nelems < s) - newcap = B->nelems + s; - if (newcap < B->capacity) /* overflow */ - luaL_error(B->L2, "buffer too large"); - newptr = (char*)lua_newuserdata(B->L2, newcap); - memcpy(newptr, B->ptr, B->nelems); - if (B->ptr != B->b.buffer) - lua_replace(B->L2, -2); /* remove old buffer */ - B->ptr = newptr; - B->capacity = newcap; - } - return B->ptr+B->nelems; -} - - -COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l) { - memcpy(luaL_prepbuffsize(B, l), s, l); - luaL_addsize(B, l); -} - - -COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B) { - size_t len = 0; - const char *s = lua_tolstring(B->L2, -1, &len); - if (!s) - luaL_error(B->L2, "cannot convert value to string"); - if (B->ptr != B->b.buffer) - lua_insert(B->L2, -2); /* userdata buffer must be at stack top */ - luaL_addlstring(B, s, len); - lua_remove(B->L2, B->ptr != B->b.buffer ? -2 : -1); -} - - -void luaL_pushresult (luaL_Buffer_53 *B) { - lua_pushlstring(B->L2, B->ptr, B->nelems); - if (B->ptr != B->b.buffer) - lua_replace(B->L2, -2); /* remove userdata buffer */ -} - - -#endif /* Lua 5.1 */ - - - -/* definitions for Lua 5.1 and Lua 5.2 */ -#if defined( LUA_VERSION_NUM ) && LUA_VERSION_NUM <= 502 - - -COMPAT53_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { -#undef lua_pushlstring - lua_pushlstring(L, len > 0 ? s : "", len); -#define lua_pushlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _pushlstring_53) - return lua_tostring(L, -1); -} - - -COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i) { - index = lua_absindex(L, index); - lua_pushinteger(L, i); - lua_gettable(L, index); - return lua_type(L, -1); -} - - -#ifndef LUA_EXTRASPACE -#define LUA_EXTRASPACE (sizeof(void*)) -#endif - -COMPAT53_API void *lua_getextraspace (lua_State *L) { - int is_main = 0; - void *ptr = NULL; - luaL_checkstack(L, 4, "not enough stack slots available"); - lua_pushliteral(L, "__compat53_extraspace"); - lua_pushvalue(L, -1); - lua_rawget(L, LUA_REGISTRYINDEX); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - lua_createtable(L, 0, 2); - lua_createtable(L, 0, 1); - lua_pushliteral(L, "k"); - lua_setfield(L, -2, "__mode"); - lua_setmetatable(L, -2); - lua_pushvalue(L, -2); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); - } - lua_replace(L, -2); - is_main = lua_pushthread(L); - lua_rawget(L, -2); - ptr = lua_touserdata(L, -1); - if (!ptr) { - lua_pop(L, 1); - ptr = lua_newuserdata(L, LUA_EXTRASPACE); - if (is_main) { - memset(ptr, '\0', LUA_EXTRASPACE); - lua_pushthread(L); - lua_pushvalue(L, -2); - lua_rawset(L, -4); - lua_pushboolean(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, -4); - } else { - void* mptr = NULL; - lua_pushboolean(L, 1); - lua_rawget(L, -3); - mptr = lua_touserdata(L, -1); - if (mptr) - memcpy(ptr, mptr, LUA_EXTRASPACE); - else - memset(ptr, '\0', LUA_EXTRASPACE); - lua_pop(L, 1); - lua_pushthread(L); - lua_pushvalue(L, -2); - lua_rawset(L, -4); - } - } - lua_pop(L, 2); - return ptr; -} - - -COMPAT53_API int lua_isinteger (lua_State *L, int index) { - if (lua_type(L, index) == LUA_TNUMBER) { - lua_Number n = lua_tonumber(L, index); - lua_Integer i = lua_tointeger(L, index); - if (i == n) - return 1; - } - return 0; -} - - -COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum) { - int ok = 0; - lua_Number n = lua_tonumberx(L, i, &ok); - if (ok) { - if (n == (lua_Integer)n) { - if (isnum) - *isnum = 1; - return (lua_Integer)n; - } - } - if (isnum) - *isnum = 0; - return 0; -} - - -static void compat53_reverse (lua_State *L, int a, int b) { - for (; a < b; ++a, --b) { - lua_pushvalue(L, a); - lua_pushvalue(L, b); - lua_replace(L, a); - lua_replace(L, b); - } -} - - -COMPAT53_API void lua_rotate (lua_State *L, int idx, int n) { - int n_elems = 0; - idx = lua_absindex(L, idx); - n_elems = lua_gettop(L)-idx+1; - if (n < 0) - n += n_elems; - if ( n > 0 && n < n_elems) { - luaL_checkstack(L, 2, "not enough stack slots available"); - n = n_elems - n; - compat53_reverse(L, idx, idx+n-1); - compat53_reverse(L, idx+n, idx+n_elems-1); - compat53_reverse(L, idx, idx+n_elems-1); - } -} - - -COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i) { - luaL_checkstack(L, 1, "not enough stack slots available"); - index = lua_absindex(L, index); - lua_pushinteger(L, i); - lua_insert(L, -2); - lua_settable(L, index); -} - - -#if !defined(lua_str2number) -# define lua_str2number(s, p) strtod((s), (p)) -#endif - -COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s) { - char* endptr; - lua_Number n = lua_str2number(s, &endptr); - if (endptr != s) { - while (*endptr != '\0' && isspace((unsigned char)*endptr)) - ++endptr; - if (*endptr == '\0') { - lua_pushnumber(L, n); - return endptr - s + 1; - } - } - return 0; -} - - -COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { - if (!luaL_callmeta(L, idx, "__tostring")) { - int t = lua_type(L, idx), tt = 0; - char const* name = NULL; - switch (t) { - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - case LUA_TSTRING: - case LUA_TNUMBER: - lua_pushvalue(L, idx); - break; - case LUA_TBOOLEAN: - if (lua_toboolean(L, idx)) - lua_pushliteral(L, "true"); - else - lua_pushliteral(L, "false"); - break; - default: - tt = luaL_getmetafield(L, idx, "__name"); - name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t); - lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx)); - if (tt != LUA_TNIL) - lua_replace(L, -2); - break; - } - } else { - if (!lua_isstring(L, -1)) - luaL_error(L, "'__tostring' must return a string"); - } - return lua_tolstring(L, -1, len); -} - - -COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, - lua_CFunction openf, int glb) { - luaL_checkstack(L, 3, "not enough stack slots available"); - luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); - if (lua_getfield(L, -1, modname) == LUA_TNIL) { - lua_pop(L, 1); - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); - lua_call(L, 1, 1); - lua_pushvalue(L, -1); - lua_setfield(L, -3, modname); - } - if (glb) { - lua_pushvalue(L, -1); - lua_setglobal(L, modname); - } - lua_replace(L, -2); -} - - -#endif /* Lua 5.1 and 5.2 */ - - -#endif /* COMPAT53_C_ */ - - -/********************************************************************* -* This file contains parts of Lua 5.2's and Lua 5.3's source code: -* -* Copyright (C) 1994-2014 Lua.org, PUC-Rio. -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*********************************************************************/ - diff --git a/lib/compat53/c-api/compat-5.3.h b/lib/compat53/c-api/compat-5.3.h deleted file mode 100644 index 6f66dad..0000000 --- a/lib/compat53/c-api/compat-5.3.h +++ /dev/null @@ -1,421 +0,0 @@ -#ifndef COMPAT53_H_ -#define COMPAT53_H_ - -#include -#include -#include -#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) -extern "C" { -#endif -#include -#include -#include -#if defined(__cplusplus) && !defined(COMPAT53_LUA_CPP) -} -#endif - - -#undef COMPAT53_INCLUDE_SOURCE -#if defined(COMPAT53_PREFIX) -/* - change the symbol names of functions to avoid linker conflicts - * - compat-5.3.c needs to be compiled (and linked) separately - */ -# if !defined(COMPAT53_API) -# define COMPAT53_API extern -# endif -#else /* COMPAT53_PREFIX */ -/* - make all functions static and include the source. - * - compat-5.3.c doesn't need to be compiled (and linked) separately - */ -# define COMPAT53_PREFIX compat53 -# undef COMPAT53_API -# if defined(__GNUC__) || defined(__clang__) -# define COMPAT53_API __attribute__((__unused__)) static -# else -# define COMPAT53_API static -# endif -# define COMPAT53_INCLUDE_SOURCE -#endif /* COMPAT53_PREFIX */ - -#define COMPAT53_CONCAT_HELPER(a, b) a##b -#define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b) - - - -/* declarations for Lua 5.1 */ -#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 - -/* XXX not implemented: - * lua_arith (new operators) - * lua_upvalueid - * lua_upvaluejoin - * lua_version - * lua_yieldk - */ - -#ifndef LUA_OK -# define LUA_OK 0 -#endif -#ifndef LUA_OPADD -# define LUA_OPADD 0 -#endif -#ifndef LUA_OPSUB -# define LUA_OPSUB 1 -#endif -#ifndef LUA_OPMUL -# define LUA_OPMUL 2 -#endif -#ifndef LUA_OPDIV -# define LUA_OPDIV 3 -#endif -#ifndef LUA_OPMOD -# define LUA_OPMOD 4 -#endif -#ifndef LUA_OPPOW -# define LUA_OPPOW 5 -#endif -#ifndef LUA_OPUNM -# define LUA_OPUNM 6 -#endif -#ifndef LUA_OPEQ -# define LUA_OPEQ 0 -#endif -#ifndef LUA_OPLT -# define LUA_OPLT 1 -#endif -#ifndef LUA_OPLE -# define LUA_OPLE 2 -#endif - -/* LuaJIT/Lua 5.1 does not have the updated - * error codes for thread status/function returns (but some patched versions do) - * define it only if it's not found - */ -#if !defined(LUA_ERRGCMM) -/* Use + 2 because in some versions of Lua (Lua 5.1) - * LUA_ERRFILE is defined as (LUA_ERRERR+1) - * so we need to avoid it (LuaJIT might have something at this - * integer value too) - */ -# define LUA_ERRGCMM (LUA_ERRERR + 2) -#endif /* LUA_ERRGCMM define */ - -typedef size_t lua_Unsigned; - -typedef struct luaL_Buffer_53 { - luaL_Buffer b; /* make incorrect code crash! */ - char *ptr; - size_t nelems; - size_t capacity; - lua_State *L2; -} luaL_Buffer_53; -#define luaL_Buffer luaL_Buffer_53 - -/* In PUC-Rio 5.1, userdata is a simple FILE* - * In LuaJIT, it's a struct where the first member is a FILE* - * We can't support the `closef` member - */ -typedef struct luaL_Stream { - FILE *f; -} luaL_Stream; - -#define lua_absindex COMPAT53_CONCAT(COMPAT53_PREFIX, _absindex) -COMPAT53_API int lua_absindex (lua_State *L, int i); - -#define lua_arith COMPAT53_CONCAT(COMPAT53_PREFIX, _arith) -COMPAT53_API void lua_arith (lua_State *L, int op); - -#define lua_compare COMPAT53_CONCAT(COMPAT53_PREFIX, _compare) -COMPAT53_API int lua_compare (lua_State *L, int idx1, int idx2, int op); - -#define lua_copy COMPAT53_CONCAT(COMPAT53_PREFIX, _copy) -COMPAT53_API void lua_copy (lua_State *L, int from, int to); - -#define lua_getuservalue(L, i) \ - (lua_getfenv((L), (i)), lua_type((L), -1)) -#define lua_setuservalue(L, i) \ - (luaL_checktype((L), -1, LUA_TTABLE), lua_setfenv((L), (i))) - -#define lua_len COMPAT53_CONCAT(COMPAT53_PREFIX, _len) -COMPAT53_API void lua_len (lua_State *L, int i); - -#define lua_pushstring(L, s) \ - (lua_pushstring((L), (s)), lua_tostring((L), -1)) - -#ifndef luaL_newlibtable -# define luaL_newlibtable(L, l) \ - (lua_createtable((L), 0, sizeof((l))/sizeof(*(l))-1)) -#endif -#ifndef luaL_newlib -# define luaL_newlib(L, l) \ - (luaL_newlibtable((L), (l)), luaL_register((L), NULL, (l))) -#endif - -#define lua_pushglobaltable(L) \ - lua_pushvalue((L), LUA_GLOBALSINDEX) - -#define lua_rawgetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawgetp) -COMPAT53_API int lua_rawgetp (lua_State *L, int i, const void *p); - -#define lua_rawsetp COMPAT53_CONCAT(COMPAT53_PREFIX, _rawsetp) -COMPAT53_API void lua_rawsetp(lua_State *L, int i, const void *p); - -#define lua_rawlen(L, i) lua_objlen((L), (i)) - -#define lua_tointeger(L, i) lua_tointegerx((L), (i), NULL) - -#define lua_tonumberx COMPAT53_CONCAT(COMPAT53_PREFIX, _tonumberx) -COMPAT53_API lua_Number lua_tonumberx (lua_State *L, int i, int *isnum); - -#define luaL_checkversion COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkversion) -COMPAT53_API void luaL_checkversion (lua_State *L); - -#define lua_load COMPAT53_CONCAT(COMPAT53_PREFIX, _load_53) -COMPAT53_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char* source, const char* mode); - -#define luaL_loadfilex COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadfilex) -COMPAT53_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode); - -#define luaL_loadbufferx COMPAT53_CONCAT(COMPAT53_PREFIX, L_loadbufferx) -COMPAT53_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); - -#define luaL_checkstack COMPAT53_CONCAT(COMPAT53_PREFIX, L_checkstack_53) -COMPAT53_API void luaL_checkstack (lua_State *L, int sp, const char *msg); - -#define luaL_getsubtable COMPAT53_CONCAT(COMPAT53_PREFIX, L_getsubtable) -COMPAT53_API int luaL_getsubtable (lua_State* L, int i, const char *name); - -#define luaL_len COMPAT53_CONCAT(COMPAT53_PREFIX, L_len) -COMPAT53_API lua_Integer luaL_len (lua_State *L, int i); - -#define luaL_setfuncs COMPAT53_CONCAT(COMPAT53_PREFIX, L_setfuncs) -COMPAT53_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup); - -#define luaL_setmetatable COMPAT53_CONCAT(COMPAT53_PREFIX, L_setmetatable) -COMPAT53_API void luaL_setmetatable (lua_State *L, const char *tname); - -#define luaL_testudata COMPAT53_CONCAT(COMPAT53_PREFIX, L_testudata) -COMPAT53_API void *luaL_testudata (lua_State *L, int i, const char *tname); - -#define luaL_traceback COMPAT53_CONCAT(COMPAT53_PREFIX, L_traceback) -COMPAT53_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level); - -#define luaL_fileresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_fileresult) -COMPAT53_API int luaL_fileresult (lua_State *L, int stat, const char *fname); - -#define luaL_execresult COMPAT53_CONCAT(COMPAT53_PREFIX, L_execresult) -COMPAT53_API int luaL_execresult (lua_State *L, int stat); - -#define lua_callk(L, na, nr, ctx, cont) \ - ((void)(ctx), (void)(cont), lua_call((L), (na), (nr))) -#define lua_pcallk(L, na, nr, err, ctx, cont) \ - ((void)(ctx), (void)(cont), lua_pcall((L), (na), (nr), (err))) - -#define lua_resume(L, from, nargs) \ - ((void)(from), lua_resume((L), (nargs))) - -#define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53) -COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B); - -#define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53) -COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s); - -#define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53) -COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l); - -#define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53) -COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B); - -#define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53) -COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B); - -#undef luaL_buffinitsize -#define luaL_buffinitsize(L, B, s) \ - (luaL_buffinit((L), (B)), luaL_prepbuffsize((B), (s))) - -#undef luaL_prepbuffer -#define luaL_prepbuffer(B) \ - luaL_prepbuffsize((B), LUAL_BUFFERSIZE) - -#undef luaL_addchar -#define luaL_addchar(B, c) \ - ((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize((B), 1)), \ - ((B)->ptr[(B)->nelems++] = (c))) - -#undef luaL_addsize -#define luaL_addsize(B, s) \ - ((B)->nelems += (s)) - -#undef luaL_addstring -#define luaL_addstring(B, s) \ - luaL_addlstring((B), (s), strlen((s))) - -#undef luaL_pushresultsize -#define luaL_pushresultsize(B, s) \ - (luaL_addsize((B), (s)), luaL_pushresult((B))) - -#if defined(LUA_COMPAT_APIINTCASTS) -#define lua_pushunsigned(L, n) \ - lua_pushinteger((L), (lua_Integer)(n)) -#define lua_tounsignedx(L, i, is) \ - ((lua_Unsigned)lua_tointegerx((L), (i), (is))) -#define lua_tounsigned(L, i) \ - lua_tounsignedx((L), (i), NULL) -#define luaL_checkunsigned(L, a) \ - ((lua_Unsigned)luaL_checkinteger((L), (a))) -#define luaL_optunsigned(L, a, d) \ - ((lua_Unsigned)luaL_optinteger((L), (a), (lua_Integer)(d))) -#endif - -#endif /* Lua 5.1 only */ - - - -/* declarations for Lua 5.1 and 5.2 */ -#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502 - -typedef int lua_KContext; - -typedef int (*lua_KFunction)(lua_State *L, int status, lua_KContext ctx); - -#define lua_dump(L, w, d, s) \ - ((void)(s), lua_dump((L), (w), (d))) - -#define lua_getfield(L, i, k) \ - (lua_getfield((L), (i), (k)), lua_type((L), -1)) - -#define lua_gettable(L, i) \ - (lua_gettable((L), (i)), lua_type((L), -1)) - -#define lua_pushlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _pushlstring_53) -COMPAT53_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len); - -#define lua_geti COMPAT53_CONCAT(COMPAT53_PREFIX, _geti) -COMPAT53_API int lua_geti (lua_State *L, int index, lua_Integer i); - -#define lua_getextraspace COMPAT53_CONCAT(COMPAT53_PREFIX, _getextraspace) -COMPAT53_API void *lua_getextraspace (lua_State *L); - -#define lua_isinteger COMPAT53_CONCAT(COMPAT53_PREFIX, _isinteger) -COMPAT53_API int lua_isinteger (lua_State *L, int index); - -#define lua_tointegerx COMPAT53_CONCAT(COMPAT53_PREFIX, _tointegerx_53) -COMPAT53_API lua_Integer lua_tointegerx (lua_State *L, int i, int *isnum); - -#define lua_numbertointeger(n, p) \ - ((*(p) = (lua_Integer)(n)), 1) - -#define lua_rawget(L, i) \ - (lua_rawget((L), (i)), lua_type((L), -1)) - -#define lua_rawgeti(L, i, n) \ - (lua_rawgeti((L), (i), (n)), lua_type((L), -1)) - -#define lua_rotate COMPAT53_CONCAT(COMPAT53_PREFIX, _rotate) -COMPAT53_API void lua_rotate (lua_State *L, int idx, int n); - -#define lua_seti COMPAT53_CONCAT(COMPAT53_PREFIX, _seti) -COMPAT53_API void lua_seti (lua_State *L, int index, lua_Integer i); - -#define lua_stringtonumber COMPAT53_CONCAT(COMPAT53_PREFIX, _stringtonumber) -COMPAT53_API size_t lua_stringtonumber (lua_State *L, const char *s); - -#define luaL_tolstring COMPAT53_CONCAT(COMPAT53_PREFIX, L_tolstring) -COMPAT53_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len); - -#define luaL_getmetafield(L, o, e) \ - (luaL_getmetafield((L), (o), (e)) ? lua_type((L), -1) : LUA_TNIL) - -#define luaL_newmetatable(L, tn) \ - (luaL_newmetatable((L), (tn)) ? (lua_pushstring((L), (tn)), lua_setfield((L), -2, "__name"), 1) : 0) - -#define luaL_requiref COMPAT53_CONCAT(COMPAT53_PREFIX, L_requiref_53) -COMPAT53_API void luaL_requiref (lua_State *L, const char *modname, - lua_CFunction openf, int glb ); - -#endif /* Lua 5.1 and Lua 5.2 */ - - - -/* declarations for Lua 5.2 */ -#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 502 - -/* XXX not implemented: - * lua_isyieldable - * lua_arith (new operators) - * lua_pushfstring (new formats) - */ - -#define lua_getglobal(L, n) \ - (lua_getglobal((L), (n)), lua_type((L), -1)) - -#define lua_getuservalue(L, i) \ - (lua_getuservalue((L), (i)), lua_type((L), -1)) - -#define lua_rawgetp(L, i, p) \ - (lua_rawgetp((L), (i), (p)), lua_type((L), -1)) - -#define LUA_KFUNCTION(_name) \ - static int (_name)(lua_State *L, int status, lua_KContext ctx); \ - static int (_name ## _52)(lua_State *L) { \ - lua_KContext ctx; \ - int status = lua_getctx(L, &ctx); \ - return (_name)(L, status, ctx); \ - } \ - static int (_name)(lua_State *L, int status, lua_KContext ctx) - -#define lua_pcallk(L, na, nr, err, ctx, cont) \ - lua_pcallk((L), (na), (nr), (err), (ctx), cont ## _52) - -#define lua_callk(L, na, nr, ctx, cont) \ - lua_callk((L), (na), (nr), (ctx), cont ## _52) - -#define lua_yieldk(L, nr, ctx, cont) \ - lua_yieldk((L), (nr), (ctx), cont ## _52) - -#ifdef lua_call -# undef lua_call -# define lua_call(L, na, nr) \ - (lua_callk)((L), (na), (nr), 0, NULL) -#endif - -#ifdef lua_pcall -# undef lua_pcall -# define lua_pcall(L, na, nr, err) \ - (lua_pcallk)((L), (na), (nr), (err), 0, NULL) -#endif - -#ifdef lua_yield -# undef lua_yield -# define lua_yield(L, nr) \ - (lua_yieldk)((L), (nr), 0, NULL) -#endif - -#endif /* Lua 5.2 only */ - - - -/* other Lua versions */ -#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 501 || LUA_VERSION_NUM > 504 - -# error "unsupported Lua version (i.e. not Lua 5.1, 5.2, 5.3, or 5.4)" - -#endif /* other Lua versions except 5.1, 5.2, 5.3, and 5.4 */ - - - -/* helper macro for defining continuation functions (for every version - * *except* Lua 5.2) */ -#ifndef LUA_KFUNCTION -#define LUA_KFUNCTION(_name) \ - static int (_name)(lua_State *L, int status, lua_KContext ctx) -#endif - - -#if defined(COMPAT53_INCLUDE_SOURCE) -# include "compat-5.3.c" -#endif - - -#endif /* COMPAT53_H_ */ - diff --git a/lib/compat53/compat53/file_mt.lua b/lib/compat53/compat53/file_mt.lua deleted file mode 100644 index 6433619..0000000 --- a/lib/compat53/compat53/file_mt.lua +++ /dev/null @@ -1,71 +0,0 @@ -local lua_version = _VERSION:sub(-3) - -local M = {} - -local unpack = lua_version == "5.1" and unpack or table.unpack - -local function addasterisk(fmt) - if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then - return "*"..fmt - else - return fmt - end -end - -function M.update_file_meta(file_meta, is_luajit52) - - -- make '*' optional for file:read and file:lines - - local file_lines = file_meta.__index.lines - file_meta.__index.lines = function(self, ...) - local n = select('#', ...) - for i = 1, n do - local a = select(i, ...) - local b = addasterisk(a) - -- as an optimization we only allocate a table for the - -- modified format arguments when we have a '*' somewhere - if a ~= b then - local args = { ... } - args[i] = b - for j = i+1, n do - args[j] = addasterisk(args[j]) - end - return file_lines(self, unpack(args, 1, n)) - end - end - return file_lines(self, ...) - end - - local file_read = file_meta.__index.read - file_meta.__index.read = function(self, ...) - local n = select('#', ...) - for i = 1, n do - local a = select(i, ...) - local b = addasterisk(a) - -- as an optimization we only allocate a table for the - -- modified format arguments when we have a '*' somewhere - if a ~= b then - local args = { ... } - args[i] = b - for j = i+1, n do - args[j] = addasterisk(args[j]) - end - return file_read(self, unpack(args, 1, n)) - end - end - return file_read(self, ...) - end - - if not is_luajit52 then - local file_write = file_meta.__index.write - file_meta.__index.write = function(self, ...) - local ret, err = file_write(self, ...) - if ret then - return self - end - return ret, err - end - end -end - -return M diff --git a/lib/compat53/compat53/init.lua b/lib/compat53/compat53/init.lua deleted file mode 100644 index b507571..0000000 --- a/lib/compat53/compat53/init.lua +++ /dev/null @@ -1,325 +0,0 @@ -local lua_version = _VERSION:sub(-3) - - -if lua_version < "5.3" then - - local _G, pairs, require, select, type = - _G, pairs, require, select, type - local debug, io = debug, io - local unpack = lua_version == "5.1" and unpack or table.unpack - - local M = require("compat53.module") - - -- select the most powerful getmetatable function available - local gmt = type(debug) == "table" and debug.getmetatable or - getmetatable or function() return false end - -- metatable for file objects from Lua's standard io library - local file_meta = gmt(io.stdout) - - - -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) - local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" - local is_luajit52 = is_luajit and - #setmetatable({}, { __len = function() return 1 end }) == 1 - - - if type(file_meta) == "table" and type(file_meta.__index) == "table" then - local file_mt = require("compat53.file_mt") - file_mt.update_file_meta(file_meta, is_luajit52) - end -- got a valid metatable for file objects - - - -- changes for Lua 5.1 only - if lua_version == "5.1" then - - -- cache globals - local error, pcall, rawset, setmetatable, tostring, xpcall = - error, pcall, rawset, setmetatable, tostring, xpcall - local coroutine, package, string = coroutine, package, string - local coroutine_resume = coroutine.resume - local coroutine_running = coroutine.running - local coroutine_status = coroutine.status - local coroutine_yield = coroutine.yield - local io_type = io.type - - - -- make package.searchers available as an alias for package.loaders - local p_index = { searchers = package.loaders } - setmetatable(package, { - __index = p_index, - __newindex = function(p, k, v) - if k == "searchers" then - rawset(p, "loaders", v) - p_index.searchers = v - else - rawset(p, k, v) - end - end - }) - - - if type(file_meta) == "table" and type(file_meta.__index) == "table" then - if not is_luajit then - local function helper(_, var_1, ...) - if var_1 == nil then - if (...) ~= nil then - error((...), 2) - end - end - return var_1, ... - end - - local function lines_iterator(st) - return helper(st, st.f:read(unpack(st, 1, st.n))) - end - - local file_write = file_meta.__index.write - file_meta.__index.write = function(self, ...) - local res, msg, errno = file_write(self, ...) - if res then - return self - else - return nil, msg, errno - end - end - - file_meta.__index.lines = function(self, ...) - if io_type(self) == "closed file" then - error("attempt to use a closed file", 2) - end - local st = { f=self, n=select('#', ...), ... } - for i = 1, st.n do - local t = type(st[i]) - if t == "string" then - local fmt = st[i]:match("^*?([aln])") - if not fmt then - error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) - end - st[i] = "*"..fmt - elseif t ~= "number" then - error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) - end - end - return lines_iterator, st - end - end -- not luajit - end -- file_meta valid - - - -- the (x)pcall implementations start a new coroutine internally - -- to allow yielding even in Lua 5.1. to allow for accurate - -- stack traces we keep track of the nested coroutine activations - -- in the weak tables below: - local weak_meta = { __mode = "kv" } - -- maps the internal pcall coroutines to the user coroutine that - -- *should* be running if pcall didn't use coroutines internally - local pcall_mainOf = setmetatable({}, weak_meta) - -- table that maps each running coroutine started by pcall to - -- the coroutine that resumed it (user coroutine *or* pcall - -- coroutine!) - local pcall_previous = setmetatable({}, weak_meta) - -- reverse of `pcall_mainOf`. maps a user coroutine to the - -- currently active pcall coroutine started within it - local pcall_callOf = setmetatable({}, weak_meta) - -- similar to `pcall_mainOf` but is used only while executing - -- the error handler of xpcall (thus no nesting is necessary!) - local xpcall_running = setmetatable({}, weak_meta) - - -- handle debug functions - if type(debug) == "table" then - local debug_getinfo = debug.getinfo - local debug_traceback = debug.traceback - - if not is_luajit then - local function calculate_trace_level(co, level) - if level ~= nil then - for out = 1, 1/0 do - local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") - if info == nil then - local max = out-1 - if level <= max then - return level - end - return nil, level-max - end - end - end - return 1 - end - - local stack_pattern = "\nstack traceback:" - local stack_replace = "" - function debug.traceback(co, msg, level) - local lvl - local nilmsg - if type(co) ~= "thread" then - co, msg, level = coroutine_running(), co, msg - end - if msg == nil then - msg = "" - nilmsg = true - elseif type(msg) ~= "string" then - return msg - end - if co == nil then - msg = debug_traceback(msg, level or 1) - else - local xpco = xpcall_running[co] - if xpco ~= nil then - lvl, level = calculate_trace_level(xpco, level) - if lvl then - msg = debug_traceback(xpco, msg, lvl) - else - msg = msg..stack_pattern - end - lvl, level = calculate_trace_level(co, level) - if lvl then - local trace = debug_traceback(co, "", lvl) - msg = msg..trace:gsub(stack_pattern, stack_replace) - end - else - co = pcall_callOf[co] or co - lvl, level = calculate_trace_level(co, level) - if lvl then - msg = debug_traceback(co, msg, lvl) - else - msg = msg..stack_pattern - end - end - co = pcall_previous[co] - while co ~= nil do - lvl, level = calculate_trace_level(co, level) - if lvl then - local trace = debug_traceback(co, "", lvl) - msg = msg..trace:gsub(stack_pattern, stack_replace) - end - co = pcall_previous[co] - end - end - if nilmsg then - msg = msg:gsub("^\n", "") - end - msg = msg:gsub("\n\t%(tail call%): %?", "\000") - msg = msg:gsub("\n\t%.%.%.\n", "\001\n") - msg = msg:gsub("\n\t%.%.%.$", "\001") - msg = msg:gsub("(%z+)\001(%z+)", function(some, other) - return "\n\t(..."..#some+#other.."+ tail call(s)...)" - end) - msg = msg:gsub("\001(%z+)", function(zeros) - return "\n\t(..."..#zeros.."+ tail call(s)...)" - end) - msg = msg:gsub("(%z+)\001", function(zeros) - return "\n\t(..."..#zeros.."+ tail call(s)...)" - end) - msg = msg:gsub("%z+", function(zeros) - return "\n\t(..."..#zeros.." tail call(s)...)" - end) - msg = msg:gsub("\001", function() - return "\n\t..." - end) - return msg - end - end -- is not luajit - end -- debug table available - - - if not is_luajit52 then - local coroutine_running52 = M.coroutine.running - function M.coroutine.running() - local co, ismain = coroutine_running52() - if ismain then - return co, true - else - return pcall_mainOf[co] or co, false - end - end - end - - if not is_luajit then - local function pcall_results(current, call, success, ...) - if coroutine_status(call) == "suspended" then - return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) - end - if pcall_previous then - pcall_previous[call] = nil - local main = pcall_mainOf[call] - if main == current then current = nil end - pcall_callOf[main] = current - end - pcall_mainOf[call] = nil - return success, ... - end - - local function pcall_exec(current, call, ...) - local main = pcall_mainOf[current] or current - pcall_mainOf[call] = main - if pcall_previous then - pcall_previous[call] = current - pcall_callOf[main] = call - end - return pcall_results(current, call, coroutine_resume(call, ...)) - end - - local coroutine_create52 = M.coroutine.create - - local function pcall_coroutine(func) - if type(func) ~= "function" then - local callable = func - func = function (...) return callable(...) end - end - return coroutine_create52(func) - end - - function M.pcall(func, ...) - local current = coroutine_running() - if not current then return pcall(func, ...) end - return pcall_exec(current, pcall_coroutine(func), ...) - end - - local function xpcall_catch(current, call, msgh, success, ...) - if not success then - xpcall_running[current] = call - local ok, result = pcall(msgh, ...) - xpcall_running[current] = nil - if not ok then - return false, "error in error handling ("..tostring(result)..")" - end - return false, result - end - return true, ... - end - - function M.xpcall(f, msgh, ...) - local current = coroutine_running() - if not current then - local args, n = { ... }, select('#', ...) - return xpcall(function() return f(unpack(args, 1, n)) end, msgh) - end - local call = pcall_coroutine(f) - return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) - end - end -- not luajit - - end -- lua 5.1 - - - -- handle exporting to global scope - local function extend_table(from, to) - if from ~= to then - for k,v in pairs(from) do - if type(v) == "table" and - type(to[k]) == "table" and - v ~= to[k] then - extend_table(v, to[k]) - else - to[k] = v - end - end - end - end - - extend_table(M, _G) - -end -- lua < 5.3 - --- vi: set expandtab softtabstop=3 shiftwidth=3 : diff --git a/lib/compat53/compat53/module.lua b/lib/compat53/compat53/module.lua deleted file mode 100644 index 52b1dd6..0000000 --- a/lib/compat53/compat53/module.lua +++ /dev/null @@ -1,894 +0,0 @@ -local _G, _VERSION = _G, _VERSION -local lua_version = _VERSION:sub(-3) - - -local M = _G - -if lua_version < "5.3" then - - -- cache globals in upvalues - local error, ipairs, pairs, pcall, require, select, setmetatable, type = - error, ipairs, pairs, pcall, require, select, setmetatable, type - local debug, io, math, package, string, table = - debug, io, math, package, string, table - local io_lines = io.lines - local io_read = io.read - local io_open = io.open - local io_popen = io.popen - local io_tmpfile = io.tmpfile - local unpack = lua_version == "5.1" and unpack or table.unpack - local debug_setmetatable = type(debug) == "table" and debug.setmetatable - - -- create module table - M = {} - local M_meta = { - __index = _G, - -- __newindex is set at the end - } - setmetatable(M, M_meta) - - -- create subtables - M.io = setmetatable({}, { __index = io }) - M.math = setmetatable({}, { __index = math }) - M.string = setmetatable({}, { __index = string }) - M.table = setmetatable({}, { __index = table }) - M.utf8 = {} - - - -- select the most powerful getmetatable function available - local gmt = type(debug) == "table" and debug.getmetatable or - getmetatable or function() return false end - - -- type checking functions - local checkinteger -- forward declararation - - local function argcheck(cond, i, f, extra) - if not cond then - error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0) - end - end - - - -- load utf8 library - local utf8_ok, utf8lib = pcall(require, "compat53.utf8") - if utf8_ok then - if lua_version == "5.1" then - utf8lib.charpattern = "[%z\1-\127\194-\244][\128-\191]*" - end - for k,v in pairs(utf8lib) do - M.utf8[k] = v - end - package.loaded["utf8"] = M.utf8 - end - - - -- load table library - local table_ok, tablib = pcall(require, "compat53.table") - if table_ok then - for k,v in pairs(tablib) do - M.table[k] = v - end - end - - - -- load io functions - local io_ok, iolib = pcall(require, "compat53.io") - if io_ok then - for k,v in pairs(iolib) do - M.io[k] = v - end - end - - - -- load string packing functions - local str_ok, strlib = pcall(require, "compat53.string") - if str_ok then - for k,v in pairs(strlib) do - M.string[k] = v - end - end - - - -- try Roberto's struct module for string packing/unpacking if - -- compat53.string is unavailable - if not str_ok then - local struct_ok, struct = pcall(require, "struct") - if struct_ok then - M.string.pack = struct.pack - M.string.packsize = struct.size - M.string.unpack = struct.unpack - end - end - - - -- update math library - do - local maxint, minint = 1 - - while maxint+1 > maxint and 2*maxint > maxint do - maxint = maxint * 2 - end - if 2*maxint <= maxint then - maxint = 2*maxint-1 - minint = -maxint-1 - else - maxint = maxint - minint = -maxint - end - M.math.maxinteger = maxint - M.math.mininteger = minint - - function M.math.tointeger(n) - n = tonumber(n) - if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then - return n - end - return nil - end - - function M.math.type(n) - if type(n) == "number" then - if n <= maxint and n >= minint and n % 1 == 0 then - return "integer" - else - return "float" - end - else - return nil - end - end - - function checkinteger(x, i, f) - local t = type(x) - if t ~= "number" then - error("bad argument #"..i.." to '"..f.. - "' (number expected, got "..t..")", 0) - elseif x > maxint or x < minint or x % 1 ~= 0 then - error("bad argument #"..i.." to '"..f.. - "' (number has no integer representation)", 0) - else - return x - end - end - - function M.math.ult(m, n) - m = checkinteger(m, "1", "math.ult") - n = checkinteger(n, "2", "math.ult") - if m >= 0 and n < 0 then - return true - elseif m < 0 and n >= 0 then - return false - else - return m < n - end - end - end - - - -- assert should allow non-string error objects - function M.assert(cond, ...) - if cond then - return cond, ... - elseif select('#', ...) > 0 then - error((...), 0) - else - error("assertion failed!", 0) - end - end - - - -- ipairs should respect __index metamethod - do - local function ipairs_iterator(st, var) - var = var + 1 - local val = st[var] - if val ~= nil then - return var, st[var] - end - end - function M.ipairs(t) - if gmt(t) ~= nil then -- t has metatable - return ipairs_iterator, t, 0 - else - return ipairs(t) - end - end - end - - - -- make '*' optional for io.read and io.lines - do - local function addasterisk(fmt) - if type(fmt) == "string" and fmt:sub(1, 1) ~= "*" then - return "*"..fmt - else - return fmt - end - end - - function M.io.read(...) - local n = select('#', ...) - for i = 1, n do - local a = select(i, ...) - local b = addasterisk(a) - -- as an optimization we only allocate a table for the - -- modified format arguments when we have a '*' somewhere. - if a ~= b then - local args = { ... } - args[i] = b - for j = i+1, n do - args[j] = addasterisk(args[j]) - end - return io_read(unpack(args, 1, n)) - end - end - return io_read(...) - end - - -- PUC-Rio Lua 5.1 uses a different implementation for io.lines! - function M.io.lines(...) - local n = select('#', ...) - for i = 2, n do - local a = select(i, ...) - local b = addasterisk(a) - -- as an optimization we only allocate a table for the - -- modified format arguments when we have a '*' somewhere. - if a ~= b then - local args = { ... } - args[i] = b - for j = i+1, n do - args[j] = addasterisk(args[j]) - end - return io_lines(unpack(args, 1, n)) - end - end - return io_lines(...) - end - end - - - -- update table library (if C module not available) - if not table_ok then - local table_concat = table.concat - local table_insert = table.insert - local table_remove = table.remove - local table_sort = table.sort - - function M.table.concat(list, sep, i, j) - local mt = gmt(list) - if type(mt) == "table" and type(mt.__len) == "function" then - local src = list - list, i, j = {}, i or 1, j or mt.__len(src) - for k = i, j do - list[k] = src[k] - end - end - return table_concat(list, sep, i, j) - end - - function M.table.insert(list, ...) - local mt = gmt(list) - local has_mt = type(mt) == "table" - local has_len = has_mt and type(mt.__len) == "function" - if has_mt and (has_len or mt.__index or mt.__newindex) then - local e = (has_len and mt.__len(list) or #list)+1 - local nargs, pos, value = select('#', ...), ... - if nargs == 1 then - pos, value = e, pos - elseif nargs == 2 then - pos = checkinteger(pos, "2", "table.insert") - argcheck(1 <= pos and pos <= e, "2", "table.insert", - "position out of bounds" ) - else - error("wrong number of arguments to 'insert'", 0) - end - for i = e-1, pos, -1 do - list[i+1] = list[i] - end - list[pos] = value - else - return table_insert(list, ...) - end - end - - function M.table.move(a1, f, e, t, a2) - a2 = a2 or a1 - f = checkinteger(f, "2", "table.move") - argcheck(f > 0, "2", "table.move", - "initial position must be positive") - e = checkinteger(e, "3", "table.move") - t = checkinteger(t, "4", "table.move") - if e >= f then - local m, n, d = 0, e-f, 1 - if t > f then m, n, d = n, m, -1 end - for i = m, n, d do - a2[t+i] = a1[f+i] - end - end - return a2 - end - - function M.table.remove(list, pos) - local mt = gmt(list) - local has_mt = type(mt) == "table" - local has_len = has_mt and type(mt.__len) == "function" - if has_mt and (has_len or mt.__index or mt.__newindex) then - local e = (has_len and mt.__len(list) or #list) - pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e - if pos ~= e then - argcheck(1 <= pos and pos <= e+1, "2", "table.remove", - "position out of bounds" ) - end - local result = list[pos] - while pos < e do - list[pos] = list[pos+1] - pos = pos + 1 - end - list[pos] = nil - return result - else - return table_remove(list, pos) - end - end - - do - local function pivot(list, cmp, a, b) - local m = b - a - if m > 2 then - local c = a + (m-m%2)/2 - local x, y, z = list[a], list[b], list[c] - if not cmp(x, y) then - x, y, a, b = y, x, b, a - end - if not cmp(y, z) then - y, b = z, c - end - if not cmp(x, y) then - y, b = x, a - end - return b, y - else - return b, list[b] - end - end - - local function lt_cmp(a, b) - return a < b - end - - local function qsort(list, cmp, b, e) - if b < e then - local i, j, k, val = b, e, pivot(list, cmp, b, e) - while i < j do - while i < j and cmp(list[i], val) do - i = i + 1 - end - while i < j and not cmp(list[j], val) do - j = j - 1 - end - if i < j then - list[i], list[j] = list[j], list[i] - if i == k then k = j end -- update pivot position - i, j = i+1, j-1 - end - end - if i ~= k and not cmp(list[i], val) then - list[i], list[k] = val, list[i] - k = i -- update pivot position - end - qsort(list, cmp, b, i == k and i-1 or i) - return qsort(list, cmp, i+1, e) - end - end - - function M.table.sort(list, cmp) - local mt = gmt(list) - local has_mt = type(mt) == "table" - local has_len = has_mt and type(mt.__len) == "function" - if has_len then - cmp = cmp or lt_cmp - local len = mt.__len(list) - return qsort(list, cmp, 1, len) - else - return table_sort(list, cmp) - end - end - end - - local function unpack_helper(list, i, j, ...) - if j < i then - return ... - else - return unpack_helper(list, i, j-1, list[j], ...) - end - end - function M.table.unpack(list, i, j) - local mt = gmt(list) - local has_mt = type(mt) == "table" - local has_len = has_mt and type(mt.__len) == "function" - if has_mt and (has_len or mt.__index) then - i, j = i or 1, j or (has_len and mt.__len(list)) or #list - return unpack_helper(list, i, j) - else - return unpack(list, i, j) - end - end - end -- update table library - - - -- bring Lua 5.1 (and LuaJIT) up to speed with Lua 5.2 - if lua_version == "5.1" then - -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag) - local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ" - local is_luajit52 = is_luajit and - #setmetatable({}, { __len = function() return 1 end }) == 1 - - -- cache globals in upvalues - local load, loadfile, loadstring, setfenv, xpcall = - load, loadfile, loadstring, setfenv, xpcall - local coroutine, os = coroutine, os - local coroutine_create = coroutine.create - local coroutine_resume = coroutine.resume - local coroutine_running = coroutine.running - local coroutine_status = coroutine.status - local coroutine_yield = coroutine.yield - local io_input = io.input - local io_open = io.open - local io_output = io.output - local io_write = io.write - local math_log = math.log - local os_execute = os.execute - local string_find = string.find - local string_format = string.format - local string_gmatch = string.gmatch - local string_gsub = string.gsub - local string_match = string.match - local string_rep = string.rep - local table_concat = table.concat - - -- create subtables - M.coroutine = setmetatable({}, { __index = coroutine }) - M.os = setmetatable({}, { __index = os }) - M.package = setmetatable({}, { __index = package }) - - -- handle debug functions - if type(debug) == "table" then - local debug_setfenv = debug.setfenv - local debug_getfenv = debug.getfenv - - M.debug = setmetatable({}, { __index = debug }) - - if not is_luajit52 then - function M.debug.setuservalue(obj, value) - if type(obj) ~= "userdata" then - error("bad argument #1 to 'setuservalue' (userdata expected, got ".. - type(obj)..")", 2) - end - if value == nil then value = _G end - if type(value) ~= "table" then - error("bad argument #2 to 'setuservalue' (table expected, got ".. - type(value)..")", 2) - end - return debug_setfenv(obj, value) - end - - function M.debug.getuservalue(obj) - if type(obj) ~= "userdata" then - return nil - else - local v = debug_getfenv(obj) - if v == _G or v == package then - return nil - end - return v - end - end - - function M.debug.setmetatable(value, tab) - debug_setmetatable(value, tab) - return value - end - end -- not luajit with compat52 enabled - end -- debug table available - - - if not is_luajit52 then - function M.pairs(t) - local mt = gmt(t) - if type(mt) == "table" and type(mt.__pairs) == "function" then - return mt.__pairs(t) - else - return pairs(t) - end - end - end - - - if not is_luajit then - local function check_mode(mode, prefix) - local has = { text = false, binary = false } - for i = 1,#mode do - local c = mode:sub(i, i) - if c == "t" then has.text = true end - if c == "b" then has.binary = true end - end - local t = prefix:sub(1, 1) == "\27" and "binary" or "text" - if not has[t] then - return "attempt to load a "..t.." chunk (mode is '"..mode.."')" - end - end - - function M.load(ld, source, mode, env) - mode = mode or "bt" - local chunk, msg - if type( ld ) == "string" then - if mode ~= "bt" then - local merr = check_mode(mode, ld) - if merr then return nil, merr end - end - chunk, msg = loadstring(ld, source) - else - local ld_type = type(ld) - if ld_type ~= "function" then - error("bad argument #1 to 'load' (function expected, got ".. - ld_type..")", 2) - end - if mode ~= "bt" then - local checked, merr = false, nil - local function checked_ld() - if checked then - return ld() - else - checked = true - local v = ld() - merr = check_mode(mode, v or "") - if merr then return nil end - return v - end - end - chunk, msg = load(checked_ld, source) - if merr then return nil, merr end - else - chunk, msg = load(ld, source) - end - end - if not chunk then - return chunk, msg - end - if env ~= nil then - setfenv(chunk, env) - end - return chunk - end - - M.loadstring = M.load - - function M.loadfile(file, mode, env) - mode = mode or "bt" - if mode ~= "bt" then - local f = io_open(file, "rb") - if f then - local prefix = f:read(1) - f:close() - if prefix then - local merr = check_mode(mode, prefix) - if merr then return nil, merr end - end - end - end - local chunk, msg = loadfile(file) - if not chunk then - return chunk, msg - end - if env ~= nil then - setfenv(chunk, env) - end - return chunk - end - end -- not luajit - - - if not is_luajit52 then - function M.rawlen(v) - local t = type(v) - if t ~= "string" and t ~= "table" then - error("bad argument #1 to 'rawlen' (table or string expected)", 2) - end - return #v - end - end - - - if not is_luajit then - function M.xpcall(f, msgh, ...) - local args, n = { ... }, select('#', ...) - return xpcall(function() return f(unpack(args, 1, n)) end, msgh) - end - end - - - if not is_luajit52 then - function M.os.execute(cmd) - local code = os_execute(cmd) - -- Lua 5.1 does not report exit by signal. - if code == 0 then - return true, "exit", code - else - if package.config:sub(1, 1) == '/' then - code = code/256 -- only correct on Linux! - end - return nil, "exit", code - end - end - end - - - if not table_ok and not is_luajit52 then - M.table.pack = function(...) - return { n = select('#', ...), ... } - end - end - - - local main_coroutine = coroutine_create(function() end) - - function M.coroutine.create(func) - local success, result = pcall(coroutine_create, func) - if not success then - if type(func) ~= "function" then - error("bad argument #1 (function expected)", 0) - end - result = coroutine_create(function(...) return func(...) end) - end - return result - end - - if not is_luajit52 then - function M.coroutine.running() - local co = coroutine_running() - if co then - return co, false - else - return main_coroutine, true - end - end - end - - function M.coroutine.yield(...) - local co, flag = coroutine_running() - if co and not flag then - return coroutine_yield(...) - else - error("attempt to yield from outside a coroutine", 0) - end - end - - if not is_luajit then - function M.coroutine.resume(co, ...) - if co == main_coroutine then - return false, "cannot resume non-suspended coroutine" - else - return coroutine_resume(co, ...) - end - end - - function M.coroutine.status(co) - local notmain = coroutine_running() - if co == main_coroutine then - return notmain and "normal" or "running" - else - return coroutine_status(co) - end - end - end -- not luajit - - - if not is_luajit then - M.math.log = function(x, base) - if base ~= nil then - return math_log(x)/math_log(base) - else - return math_log(x) - end - end - end - - - if not is_luajit then - function M.package.searchpath(name, path, sep, rep) - sep = (sep or "."):gsub("(%p)", "%%%1") - rep = (rep or package.config:sub(1, 1)):gsub("(%%)", "%%%1") - local pname = name:gsub(sep, rep):gsub("(%%)", "%%%1") - local msg = {} - for subpath in path:gmatch("[^;]+") do - local fpath = subpath:gsub("%?", pname) - local f = io_open(fpath, "r") - if f then - f:close() - return fpath - end - msg[#msg+1] = "\n\tno file '" .. fpath .. "'" - end - return nil, table_concat(msg) - end - end - - - local function fix_pattern(pattern) - return (string_gsub(pattern, "%z", "%%z")) - end - - function M.string.find(s, pattern, ...) - return string_find(s, fix_pattern(pattern), ...) - end - - function M.string.gmatch(s, pattern) - return string_gmatch(s, fix_pattern(pattern)) - end - - function M.string.gsub(s, pattern, ...) - return string_gsub(s, fix_pattern(pattern), ...) - end - - function M.string.match(s, pattern, ...) - return string_match(s, fix_pattern(pattern), ...) - end - - if not is_luajit then - function M.string.rep(s, n, sep) - if sep ~= nil and sep ~= "" and n >= 2 then - return s .. string_rep(sep..s, n-1) - else - return string_rep(s, n) - end - end - end - - if not is_luajit then - do - local addqt = { - ["\n"] = "\\\n", - ["\\"] = "\\\\", - ["\""] = "\\\"" - } - - local function addquoted(c, d) - return (addqt[c] or string_format(d~="" and "\\%03d" or "\\%d", c:byte()))..d - end - - function M.string.format(fmt, ...) - local args, n = { ... }, select('#', ...) - local i = 0 - local function adjust_fmt(lead, mods, kind) - if #lead % 2 == 0 then - i = i + 1 - if kind == "s" then - args[i] = _G.tostring(args[i]) - elseif kind == "q" then - args[i] = '"'..string_gsub(args[i], "([%z%c\\\"\n])(%d?)", addquoted)..'"' - return lead.."%"..mods.."s" - end - end - end - fmt = string_gsub(fmt, "(%%*)%%([%d%.%-%+%# ]*)(%a)", adjust_fmt) - return string_format(fmt, unpack(args, 1, n)) - end - end - end - - - function M.io.write(...) - local res, msg, errno = io_write(...) - if res then - return io_output() - else - return nil, msg, errno - end - end - - if not is_luajit then - local function helper(st, var_1, ...) - if var_1 == nil then - if st.doclose then st.f:close() end - if (...) ~= nil then - error((...), 2) - end - end - return var_1, ... - end - - local function lines_iterator(st) - return helper(st, st.f:read(unpack(st, 1, st.n))) - end - - function M.io.lines(fname, ...) - local doclose, file, msg - if fname ~= nil then - doclose, file, msg = true, io_open(fname, "r") - if not file then error(msg, 2) end - else - doclose, file = false, io_input() - end - local st = { f=file, doclose=doclose, n=select('#', ...), ... } - for i = 1, st.n do - local t = type(st[i]) - if t == "string" then - local fmt = st[i]:match("^%*?([aln])") - if not fmt then - error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) - end - st[i] = "*"..fmt - elseif t ~= "number" then - error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) - end - end - return lines_iterator, st - end - end -- not luajit - - if is_luajit then - local compat_file_meta = {} - local compat_file_meta_loaded = 0 - - local function load_compat_file_meta(file_meta) - -- fill compat_file_meta with original entries - for k, v in pairs(file_meta) do - compat_file_meta[k] = v - end - compat_file_meta.__index = {} - for k, v in pairs(file_meta.__index) do - compat_file_meta.__index[k] = v - end - - compat_file_meta_loaded = 1 - - -- update it with compatibility functions - local file_mt_ok, file_mt = pcall(require, "compat53.file_mt") - if file_mt_ok then - file_mt.update_file_meta(compat_file_meta, is_luajit52) - - compat_file_meta_loaded = 2 - end - end - - local function return_fd(fd, err, code) - if not fd then - return fd, err, code - end - if fd and debug_setmetatable then - if compat_file_meta_loaded == 0 then - local file_meta = gmt(fd) - load_compat_file_meta(file_meta) - end - if compat_file_meta_loaded == 2 then - debug_setmetatable(fd, compat_file_meta) - end - end - return fd - end - - function M.io.open(...) - return return_fd(io_open(...)) - end - - function M.io.popen(...) - return return_fd(io_popen(...)) - end - - function M.io.tmpfile(...) - return return_fd(io_tmpfile(...)) - end - end - - end -- lua 5.1 - - -- further write should be forwarded to _G - M_meta.__newindex = _G - -end -- lua < 5.3 - - --- return module table -return M - --- vi: set expandtab softtabstop=3 shiftwidth=3 : diff --git a/lib/compat53/lbitlib.c b/lib/compat53/lbitlib.c deleted file mode 100644 index db2652a..0000000 --- a/lib/compat53/lbitlib.c +++ /dev/null @@ -1,243 +0,0 @@ -/* -** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ -** Standard library for bitwise operations -** See Copyright Notice in lua.h -*/ - -#define lbitlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#if defined(LUA_COMPAT_BITLIB) /* { */ - - -#define pushunsigned(L,n) (sizeof(lua_Integer) > 4 ? lua_pushinteger(L, (lua_Integer)(n)) : lua_pushnumber(L, (lua_Number)(n))) -static lua_Unsigned checkunsigned(lua_State *L, int i) { - if (sizeof(lua_Integer) > 4) - return (lua_Unsigned)luaL_checkinteger(L, i); - else { - lua_Number d = luaL_checknumber(L, i); - if (d < 0) - d = (d + 1) + (~(lua_Unsigned)0); - luaL_argcheck(L, d >= 0 && d <= (~(lua_Unsigned)0), i, "value out of range"); - return (lua_Unsigned)d; - } -} - - -/* number of bits to consider in a number */ -#if !defined(LUA_NBITS) -#define LUA_NBITS 32 -#endif - - -/* -** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must -** be made in two parts to avoid problems when LUA_NBITS is equal to the -** number of bits in a lua_Unsigned.) -*/ -#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) - - -/* macro to trim extra bits */ -#define trim(x) ((x) & ALLONES) - - -/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ -#define mask(n) (~((ALLONES << 1) << ((n) - 1))) - - - -static lua_Unsigned andaux (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = ~(lua_Unsigned)0; - for (i = 1; i <= n; i++) - r &= checkunsigned(L, i); - return trim(r); -} - - -static int b_and (lua_State *L) { - lua_Unsigned r = andaux(L); - pushunsigned(L, r); - return 1; -} - - -static int b_test (lua_State *L) { - lua_Unsigned r = andaux(L); - lua_pushboolean(L, r != 0); - return 1; -} - - -static int b_or (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = 0; - for (i = 1; i <= n; i++) - r |= checkunsigned(L, i); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_xor (lua_State *L) { - int i, n = lua_gettop(L); - lua_Unsigned r = 0; - for (i = 1; i <= n; i++) - r ^= checkunsigned(L, i); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_not (lua_State *L) { - lua_Unsigned r = ~checkunsigned(L, 1); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { - if (i < 0) { /* shift right? */ - i = -i; - r = trim(r); - if (i >= LUA_NBITS) r = 0; - else r >>= i; - } - else { /* shift left */ - if (i >= LUA_NBITS) r = 0; - else r <<= i; - r = trim(r); - } - pushunsigned(L, r); - return 1; -} - - -static int b_lshift (lua_State *L) { - return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); -} - - -static int b_rshift (lua_State *L) { - return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); -} - - -static int b_arshift (lua_State *L) { - lua_Unsigned r = checkunsigned(L, 1); - lua_Integer i = luaL_checkinteger(L, 2); - if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) - return b_shift(L, r, -i); - else { /* arithmetic shift for 'negative' number */ - if (i >= LUA_NBITS) r = ALLONES; - else - r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ - pushunsigned(L, r); - return 1; - } -} - - -static int b_rot (lua_State *L, lua_Integer d) { - lua_Unsigned r = checkunsigned(L, 1); - int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ - r = trim(r); - if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ - r = (r << i) | (r >> (LUA_NBITS - i)); - pushunsigned(L, trim(r)); - return 1; -} - - -static int b_lrot (lua_State *L) { - return b_rot(L, luaL_checkinteger(L, 2)); -} - - -static int b_rrot (lua_State *L) { - return b_rot(L, -luaL_checkinteger(L, 2)); -} - - -/* -** get field and width arguments for field-manipulation functions, -** checking whether they are valid. -** ('luaL_error' called without 'return' to avoid later warnings about -** 'width' being used uninitialized.) -*/ -static int fieldargs (lua_State *L, int farg, int *width) { - lua_Integer f = luaL_checkinteger(L, farg); - lua_Integer w = luaL_optinteger(L, farg + 1, 1); - luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); - luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); - if (f + w > LUA_NBITS) - luaL_error(L, "trying to access non-existent bits"); - *width = (int)w; - return (int)f; -} - - -static int b_extract (lua_State *L) { - int w; - lua_Unsigned r = trim(checkunsigned(L, 1)); - int f = fieldargs(L, 2, &w); - r = (r >> f) & mask(w); - pushunsigned(L, r); - return 1; -} - - -static int b_replace (lua_State *L) { - int w; - lua_Unsigned r = trim(checkunsigned(L, 1)); - lua_Unsigned v = trim(checkunsigned(L, 2)); - int f = fieldargs(L, 3, &w); - lua_Unsigned m = mask(w); - r = (r & ~(m << f)) | ((v & m) << f); - pushunsigned(L, r); - return 1; -} - - -static const luaL_Reg bitlib[] = { - {"arshift", b_arshift}, - {"band", b_and}, - {"bnot", b_not}, - {"bor", b_or}, - {"bxor", b_xor}, - {"btest", b_test}, - {"extract", b_extract}, - {"lrotate", b_lrot}, - {"lshift", b_lshift}, - {"replace", b_replace}, - {"rrotate", b_rrot}, - {"rshift", b_rshift}, - {NULL, NULL} -}; - - - -LUAMOD_API int luaopen_bit32 (lua_State *L) { - luaL_newlib(L, bitlib); - return 1; -} - - -#else /* }{ */ - - -LUAMOD_API int luaopen_bit32 (lua_State *L) { - return luaL_error(L, "library 'bit32' has been deprecated"); -} - -#endif /* } */ diff --git a/lib/compat53/liolib.c b/lib/compat53/liolib.c deleted file mode 100644 index 8a9e75c..0000000 --- a/lib/compat53/liolib.c +++ /dev/null @@ -1,776 +0,0 @@ -/* -** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard I/O (and system) library -** See Copyright Notice in lua.h -*/ - -#define liolib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - - -/* -** Change this macro to accept other modes for 'fopen' besides -** the standard ones. -*/ -#if !defined(l_checkmode) - -/* accepted extensions to 'mode' in 'fopen' */ -#if !defined(L_MODEEXT) -#define L_MODEEXT "b" -#endif - -/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ -static int l_checkmode (const char *mode) { - return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && - (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ - (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */ -} - -#endif - -/* -** {====================================================== -** l_popen spawns a new process connected to the current -** one through the file streams. -** ======================================================= -*/ - -#if !defined(l_popen) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) -#define l_pclose(L,file) (pclose(file)) - -#elif defined(LUA_USE_WINDOWS) /* }{ */ - -#define l_popen(L,c,m) (_popen(c,m)) -#define l_pclose(L,file) (_pclose(file)) - -#else /* }{ */ - -/* ISO C definitions */ -#define l_popen(L,c,m) \ - ((void)((void)c, m), \ - luaL_error(L, "'popen' not supported"), \ - (FILE*)0) -#define l_pclose(L,file) ((void)L, (void)file, -1) - -#endif /* } */ - -#endif /* } */ - -/* }====================================================== */ - - -#if !defined(l_getc) /* { */ - -#if defined(LUA_USE_POSIX) -#define l_getc(f) getc_unlocked(f) -#define l_lockfile(f) flockfile(f) -#define l_unlockfile(f) funlockfile(f) -#else -#define l_getc(f) getc(f) -#define l_lockfile(f) ((void)0) -#define l_unlockfile(f) ((void)0) -#endif - -#endif /* } */ - - -/* -** {====================================================== -** l_fseek: configuration for longer offsets -** ======================================================= -*/ - -#if !defined(l_fseek) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include - -#define l_fseek(f,o,w) fseeko(f,o,w) -#define l_ftell(f) ftello(f) -#define l_seeknum off_t - -#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ - && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ - -/* Windows (but not DDK) and Visual C++ 2005 or higher */ -#define l_fseek(f,o,w) _fseeki64(f,o,w) -#define l_ftell(f) _ftelli64(f) -#define l_seeknum __int64 - -#else /* }{ */ - -/* ISO C definitions */ -#define l_fseek(f,o,w) fseek(f,o,w) -#define l_ftell(f) ftell(f) -#define l_seeknum long - -#endif /* } */ - -#endif /* } */ - -/* }====================================================== */ - - -#define IO_PREFIX "_IO_" -#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) -#define IO_INPUT (IO_PREFIX "input") -#define IO_OUTPUT (IO_PREFIX "output") - - -typedef luaL_Stream LStream; - - -#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) - -#define isclosed(p) ((p)->closef == NULL) - - -static int io_type (lua_State *L) { - LStream *p; - luaL_checkany(L, 1); - p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); - if (p == NULL) - lua_pushnil(L); /* not a file */ - else if (isclosed(p)) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; -} - - -static int f_tostring (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - lua_pushliteral(L, "file (closed)"); - else - lua_pushfstring(L, "file (%p)", p->f); - return 1; -} - - -static FILE *tofile (lua_State *L) { - LStream *p = tolstream(L); - if (isclosed(p)) - luaL_error(L, "attempt to use a closed file"); - lua_assert(p->f); - return p->f; -} - - -/* -** When creating file handles, always creates a 'closed' file handle -** before opening the actual file; so, if there is a memory error, the -** handle is in a consistent state. -*/ -static LStream *newprefile (lua_State *L) { - LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); - p->closef = NULL; /* mark file handle as 'closed' */ - luaL_setmetatable(L, LUA_FILEHANDLE); - return p; -} - - -/* -** Calls the 'close' function from a file handle. The 'volatile' avoids -** a bug in some versions of the Clang compiler (e.g., clang 3.0 for -** 32 bits). -*/ -static int aux_close (lua_State *L) { - LStream *p = tolstream(L); - volatile lua_CFunction cf = p->closef; - p->closef = NULL; /* mark stream as closed */ - return (*cf)(L); /* close it */ -} - - -static int f_close (lua_State *L) { - tofile(L); /* make sure argument is an open stream */ - return aux_close(L); -} - - -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ - return f_close(L); -} - - -static int f_gc (lua_State *L) { - LStream *p = tolstream(L); - if (!isclosed(p) && p->f != NULL) - aux_close(L); /* ignore closed and incompletely open files */ - return 0; -} - - -/* -** function to close regular files -*/ -static int io_fclose (lua_State *L) { - LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); -} - - -static LStream *newfile (lua_State *L) { - LStream *p = newprefile(L); - p->f = NULL; - p->closef = &io_fclose; - return p; -} - - -static void opencheck (lua_State *L, const char *fname, const char *mode) { - LStream *p = newfile(L); - p->f = fopen(fname, mode); - if (p->f == NULL) - luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); -} - - -static int io_open (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newfile(L); - const char *md = mode; /* to traverse/check mode */ - luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); - p->f = fopen(filename, mode); - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -/* -** function to close 'popen' files -*/ -static int io_pclose (lua_State *L) { - LStream *p = tolstream(L); - return luaL_execresult(L, l_pclose(L, p->f)); -} - - -static int io_popen (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - LStream *p = newprefile(L); - p->f = l_popen(L, filename, mode); - p->closef = &io_pclose; - return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; -} - - -static int io_tmpfile (lua_State *L) { - LStream *p = newfile(L); - p->f = tmpfile(); - return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; -} - - -static FILE *getiofile (lua_State *L, const char *findex) { - LStream *p; - lua_getfield(L, LUA_REGISTRYINDEX, findex); - p = (LStream *)lua_touserdata(L, -1); - if (isclosed(p)) - luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); - return p->f; -} - - -static int g_iofile (lua_State *L, const char *f, const char *mode) { - if (!lua_isnoneornil(L, 1)) { - const char *filename = lua_tostring(L, 1); - if (filename) - opencheck(L, filename, mode); - else { - tofile(L); /* check that it's a valid file handle */ - lua_pushvalue(L, 1); - } - lua_setfield(L, LUA_REGISTRYINDEX, f); - } - /* return current value */ - lua_getfield(L, LUA_REGISTRYINDEX, f); - return 1; -} - - -static int io_input (lua_State *L) { - return g_iofile(L, IO_INPUT, "r"); -} - - -static int io_output (lua_State *L) { - return g_iofile(L, IO_OUTPUT, "w"); -} - - -static int io_readline (lua_State *L); - - -/* -** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit -** in the limit for upvalues of a closure) -*/ -#define MAXARGLINE 250 - -static void aux_lines (lua_State *L, int toclose) { - int n = lua_gettop(L) - 1; /* number of arguments to read */ - luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); - lua_pushinteger(L, n); /* number of arguments to read */ - lua_pushboolean(L, toclose); /* close/not close file when finished */ - lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ - lua_pushcclosure(L, io_readline, 3 + n); -} - - -static int f_lines (lua_State *L) { - tofile(L); /* check that it's a valid file handle */ - aux_lines(L, 0); - return 1; -} - - -static int io_lines (lua_State *L) { - int toclose; - if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ - if (lua_isnil(L, 1)) { /* no file name? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ - lua_replace(L, 1); /* put it at index 1 */ - tofile(L); /* check that it's a valid file handle */ - toclose = 0; /* do not close it after iteration */ - } - else { /* open a new file */ - const char *filename = luaL_checkstring(L, 1); - opencheck(L, filename, "r"); - lua_replace(L, 1); /* put file at index 1 */ - toclose = 1; /* close it after iteration */ - } - aux_lines(L, toclose); - return 1; -} - - -/* -** {====================================================== -** READ -** ======================================================= -*/ - - -/* maximum length of a numeral */ -#if !defined (L_MAXLENNUM) -#define L_MAXLENNUM 200 -#endif - - -/* auxiliary structure used by 'read_number' */ -typedef struct { - FILE *f; /* file being read */ - int c; /* current character (look ahead) */ - int n; /* number of elements in buffer 'buff' */ - char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ -} RN; - - -/* -** Add current char to buffer (if not out of space) and read next one -*/ -static int nextc (RN *rn) { - if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ - rn->buff[0] = '\0'; /* invalidate result */ - return 0; /* fail */ - } - else { - rn->buff[rn->n++] = rn->c; /* save current char */ - rn->c = l_getc(rn->f); /* read next one */ - return 1; - } -} - - -/* -** Accept current char if it is in 'set' (of size 2) -*/ -static int test2 (RN *rn, const char *set) { - if (rn->c == set[0] || rn->c == set[1]) - return nextc(rn); - else return 0; -} - - -/* -** Read a sequence of (hex)digits -*/ -static int readdigits (RN *rn, int hex) { - int count = 0; - while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) - count++; - return count; -} - - -/* -** Read a number: first reads a valid prefix of a numeral into a buffer. -** Then it calls 'lua_stringtonumber' to check whether the format is -** correct and to convert it to a Lua number -*/ -static int read_number (lua_State *L, FILE *f) { - RN rn; - int count = 0; - int hex = 0; - char decp[2]; - rn.f = f; rn.n = 0; - decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ - decp[1] = '.'; /* always accept a dot */ - l_lockfile(rn.f); - do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ - test2(&rn, "-+"); /* optional signal */ - if (test2(&rn, "00")) { - if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ - else count = 1; /* count initial '0' as a valid digit */ - } - count += readdigits(&rn, hex); /* integral part */ - if (test2(&rn, decp)) /* decimal point? */ - count += readdigits(&rn, hex); /* fractional part */ - if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ - test2(&rn, "-+"); /* exponent signal */ - readdigits(&rn, 0); /* exponent digits */ - } - ungetc(rn.c, rn.f); /* unread look-ahead char */ - l_unlockfile(rn.f); - rn.buff[rn.n] = '\0'; /* finish string */ - if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ - return 1; /* ok */ - else { /* invalid format */ - lua_pushnil(L); /* "result" to be removed */ - return 0; /* read fails */ - } -} - - -static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); - ungetc(c, f); /* no-op when c == EOF */ - lua_pushliteral(L, ""); - return (c != EOF); -} - - -static int read_line (lua_State *L, FILE *f, int chop) { - luaL_Buffer b; - int c = '\0'; - luaL_buffinit(L, &b); - while (c != EOF && c != '\n') { /* repeat until end of line */ - char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ - int i = 0; - l_lockfile(f); /* no memory errors can happen inside the lock */ - while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') - buff[i++] = c; - l_unlockfile(f); - luaL_addsize(&b, i); - } - if (!chop && c == '\n') /* want a newline and have one? */ - luaL_addchar(&b, c); /* add ending newline to result */ - luaL_pushresult(&b); /* close buffer */ - /* return ok if read something (either a newline or something else) */ - return (c == '\n' || lua_rawlen(L, -1) > 0); -} - - -static void read_all (lua_State *L, FILE *f) { - size_t nr; - luaL_Buffer b; - luaL_buffinit(L, &b); - do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ - char *p = luaL_prepbuffer(&b); - nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); - luaL_addsize(&b, nr); - } while (nr == LUAL_BUFFERSIZE); - luaL_pushresult(&b); /* close buffer */ -} - - -static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t nr; /* number of chars actually read */ - char *p; - luaL_Buffer b; - luaL_buffinit(L, &b); - p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ - nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ - luaL_addsize(&b, nr); - luaL_pushresult(&b); /* close buffer */ - return (nr > 0); /* true iff read something */ -} - - -static int g_read (lua_State *L, FILE *f, int first) { - int nargs = lua_gettop(L) - 1; - int success; - int n; - clearerr(f); - if (nargs == 0) { /* no arguments? */ - success = read_line(L, f, 1); - n = first+1; /* to return 1 result */ - } - else { /* ensure stack space for all results and for auxlib's buffer */ - luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); - success = 1; - for (n = first; nargs-- && success; n++) { - if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)luaL_checkinteger(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - const char *p = luaL_checkstring(L, n); - if (*p == '*') p++; /* skip optional '*' (for compatibility) */ - switch (*p) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f, 1); - break; - case 'L': /* line with end-of-line */ - success = read_line(L, f, 0); - break; - case 'a': /* file */ - read_all(L, f); /* read entire file */ - success = 1; /* always success */ - break; - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - if (ferror(f)) - return luaL_fileresult(L, 0, NULL); - if (!success) { - lua_pop(L, 1); /* remove last result */ - lua_pushnil(L); /* push nil instead */ - } - return n - first; -} - - -static int io_read (lua_State *L) { - return g_read(L, getiofile(L, IO_INPUT), 1); -} - - -static int f_read (lua_State *L) { - return g_read(L, tofile(L), 2); -} - - -static int io_readline (lua_State *L) { - LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); - int i; - int n = (int)lua_tointeger(L, lua_upvalueindex(2)); - if (isclosed(p)) /* file is already closed? */ - return luaL_error(L, "file is already closed"); - lua_settop(L , 1); - luaL_checkstack(L, n, "too many arguments"); - for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ - lua_pushvalue(L, lua_upvalueindex(3 + i)); - n = g_read(L, p->f, 2); /* 'n' is number of results */ - lua_assert(n > 0); /* should return at least a nil */ - if (lua_toboolean(L, -n)) /* read at least one value? */ - return n; /* return them */ - else { /* first result is nil: EOF or error */ - if (n > 1) { /* is there error information? */ - /* 2nd result is error message */ - return luaL_error(L, "%s", lua_tostring(L, -n + 1)); - } - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ - lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(1)); - aux_close(L); /* close it */ - } - return 0; - } -} - -/* }====================================================== */ - - -static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - arg; - int status = 1; - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - int len = lua_isinteger(L, arg) - ? fprintf(f, LUA_INTEGER_FMT, - (LUAI_UACINT)lua_tointeger(L, arg)) - : fprintf(f, LUA_NUMBER_FMT, - (LUAI_UACNUMBER)lua_tonumber(L, arg)); - status = status && (len > 0); - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - if (status) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); -} - - -static int io_write (lua_State *L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); -} - - -static int f_write (lua_State *L) { - FILE *f = tofile(L); - lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ - return g_write(L, f, 2); -} - - -static int f_seek (lua_State *L) { - static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; - static const char *const modenames[] = {"set", "cur", "end", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Integer p3 = luaL_optinteger(L, 3, 0); - l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Integer)offset == p3, 3, - "not an integer in proper range"); - op = l_fseek(f, offset, mode[op]); - if (op) - return luaL_fileresult(L, 0, NULL); /* error */ - else { - lua_pushinteger(L, (lua_Integer)l_ftell(f)); - return 1; - } -} - - -static int f_setvbuf (lua_State *L) { - static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; - static const char *const modenames[] = {"no", "full", "line", NULL}; - FILE *f = tofile(L); - int op = luaL_checkoption(L, 2, NULL, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); - return luaL_fileresult(L, res == 0, NULL); -} - - - -static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); -} - - -static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); -} - - -/* -** functions for 'io' library -*/ -static const luaL_Reg iolib[] = { - {"close", io_close}, - {"flush", io_flush}, - {"input", io_input}, - {"lines", io_lines}, - {"open", io_open}, - {"output", io_output}, - {"popen", io_popen}, - {"read", io_read}, - {"tmpfile", io_tmpfile}, - {"type", io_type}, - {"write", io_write}, - {NULL, NULL} -}; - - -/* -** methods for file handles -*/ -static const luaL_Reg flib[] = { - {"close", f_close}, - {"flush", f_flush}, - {"lines", f_lines}, - {"read", f_read}, - {"seek", f_seek}, - {"setvbuf", f_setvbuf}, - {"write", f_write}, - {"__gc", f_gc}, - {"__tostring", f_tostring}, - {NULL, NULL} -}; - - -static void createmeta (lua_State *L) { - luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ - lua_pop(L, 1); /* pop new metatable */ -} - - -/* -** function to (not) close the standard files stdin, stdout, and stderr -*/ -static int io_noclose (lua_State *L) { - LStream *p = tolstream(L); - p->closef = &io_noclose; /* keep file opened */ - lua_pushnil(L); - lua_pushliteral(L, "cannot close standard file"); - return 2; -} - - -static void createstdfile (lua_State *L, FILE *f, const char *k, - const char *fname) { - LStream *p = newprefile(L); - p->f = f; - p->closef = &io_noclose; - if (k != NULL) { - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ - } - lua_setfield(L, -2, fname); /* add file to module */ -} - - -LUAMOD_API int luaopen_io (lua_State *L) { - luaL_newlib(L, iolib); /* new module */ - createmeta(L); - /* create (and set) default files */ - createstdfile(L, stdin, IO_INPUT, "stdin"); - createstdfile(L, stdout, IO_OUTPUT, "stdout"); - createstdfile(L, stderr, NULL, "stderr"); - return 1; -} - diff --git a/lib/compat53/lprefix.h b/lib/compat53/lprefix.h deleted file mode 100644 index 0f83906..0000000 --- a/lib/compat53/lprefix.h +++ /dev/null @@ -1,282 +0,0 @@ -/* -** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ -** Definitions for Lua code that must come before any other header file -** See Copyright Notice in lua.h -*/ - -#ifndef lprefix_h -#define lprefix_h - - -/* -** Allows POSIX/XSI stuff -*/ -#if !defined(LUA_USE_C89) /* { */ - -#if !defined(_XOPEN_SOURCE) -#define _XOPEN_SOURCE 600 -#elif _XOPEN_SOURCE == 0 -#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ -#endif - -/* -** Allows manipulation of large files in gcc and some other compilers -*/ -#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) -#define _LARGEFILE_SOURCE 1 -#define _FILE_OFFSET_BITS 64 -#endif - -#endif /* } */ - - -/* -** Windows stuff -*/ -#if defined(_WIN32) /* { */ - -#if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ -#endif - -#endif /* } */ - - -/* COMPAT53 adaptation */ -#include "c-api/compat-5.3.h" - -#undef LUAMOD_API -#define LUAMOD_API extern - - -#ifdef lutf8lib_c -# define luaopen_utf8 luaopen_compat53_utf8 -/* we don't support the %U format string of lua_pushfstring! - * code below adapted from the Lua 5.3 sources: - */ -static const char *compat53_utf8_escape (lua_State* L, long x) { - if (x < 0x80) { /* ASCII */ - char c = (char)x; - lua_pushlstring(L, &c, 1); - } else { - char buff[8] = { 0 }; - unsigned int mfb = 0x3f; - int n = 1; - do { - buff[8 - (n++)] = (char)(0x80|(x & 0x3f)); - x >>= 6; - mfb >>= 1; - } while (x > mfb); - buff[8-n] = (char)((~mfb << 1) | x); - lua_pushlstring(L, buff+8-n, n); - } - return lua_tostring(L, -1); -} -# define lua_pushfstring(L, fmt, l) \ - compat53_utf8_escape(L, l) -#endif - - -#ifdef ltablib_c -# define luaopen_table luaopen_compat53_table -# ifndef LUA_MAXINTEGER -/* conservative estimate: */ -# define LUA_MAXINTEGER INT_MAX -# endif -#endif /* ltablib_c */ - - -#ifdef lstrlib_c -#include -#include -/* move the string library open function out of the way (we only take - * the string packing functions)! - */ -# define luaopen_string luaopen_string_XXX -/* used in string.format implementation, which we don't use: */ -# ifndef LUA_INTEGER_FRMLEN -# define LUA_INTEGER_FRMLEN "" -# define LUA_NUMBER_FRMLEN "" -# endif -# ifndef LUA_MININTEGER -# define LUA_MININTEGER 0 -# endif -# ifndef LUA_INTEGER_FMT -# define LUA_INTEGER_FMT "%d" -# endif -# ifndef LUAI_UACINT -# define LUAI_UACINT lua_Integer -# endif -/* different Lua 5.3 versions have conflicting variants of this macro - * in luaconf.h, there's a fallback implementation in lstrlib.c, and - * the macro isn't used for string (un)packing anyway! - * */ -# undef lua_number2strx -# if LUA_VERSION_NUM < 503 -/* lstrlib assumes that lua_Integer and lua_Unsigned have the same - * size, so we use the unsigned equivalent of ptrdiff_t! */ -# define lua_Unsigned size_t -# endif -# ifndef l_mathlim -# ifdef LUA_NUMBER_DOUBLE -# define l_mathlim(n) (DBL_##n) -# else -# define l_mathlim(n) (FLT_##n) -# endif -# endif -# ifndef l_mathop -# ifdef LUA_NUMBER_DOUBLE -# define l_mathop(op) op -# else -# define l_mathop(op) op##f -# endif -# endif -# ifndef lua_getlocaledecpoint -# define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) -# endif -# ifndef l_sprintf -# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -# define l_sprintf(s,sz,f,i) (snprintf(s, sz, f, i)) -# else -# define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s, f, i)) -# endif -# endif - -static int str_pack (lua_State *L); -static int str_packsize (lua_State *L); -static int str_unpack (lua_State *L); -LUAMOD_API int luaopen_compat53_string (lua_State *L) { - luaL_Reg const funcs[] = { - { "pack", str_pack }, - { "packsize", str_packsize }, - { "unpack", str_unpack }, - { NULL, NULL } - }; - luaL_newlib(L, funcs); - return 1; -} -/* fake CLANG feature detection on other compilers */ -# ifndef __has_attribute -# define __has_attribute(x) 0 -# endif -/* make luaopen_string(_XXX) static, so it (and all other referenced - * string functions) won't be included in the resulting dll - * (hopefully). - */ -# undef LUAMOD_API -# if defined(__GNUC__) || __has_attribute(__unused__) -# define LUAMOD_API __attribute__((__unused__)) static -# else -# define LUAMOD_API static -# endif -#endif /* lstrlib.c */ - -#endif - - -#ifdef liolib_c -/* move the io library open function out of the way (we only take - * the popen and type functions)! - */ -# define luaopen_io luaopen_io_XXX - -#include -#include - -# if !defined(lua_getlocaledecpoint) -# define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) -# endif - -# ifndef LUA_INTEGER_FMT -# define LUA_INTEGER_FMT "%ld" -# endif -# ifndef LUAI_UACINT -# define LUAI_UACINT lua_Integer -# endif - -/* choose which popen implementation to pick */ -# if (defined(_WIN32) && !defined(__CYGWIN__)) -# define LUA_USE_WINDOWS 1 -# endif -# if (!defined(LUA_USE_WINDOWS) && !defined(LUA_USE_POSIX)) && \ - ((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ - (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) || \ - defined(__APPLE__)) -# define LUA_USE_POSIX 1 -# endif - -typedef struct COMPAT53_luaL_Stream { - FILE *f; /* stream (NULL for incompletely created streams) */ - lua_CFunction closef; /* to close stream (NULL for closed streams) */ -} COMPAT53_luaL_Stream; - -#define luaL_Stream COMPAT53_luaL_Stream - -#define COMPAT53_LUA_PFILEHANDLE "PFILE*" - -static int io_ptype (lua_State *L) { - luaL_Stream *p; - luaL_checkany(L, 1); - p = (luaL_Stream *)luaL_testudata(L, 1, COMPAT53_LUA_PFILEHANDLE); - if (p) { - /* Lua 5.3 implementation, for popen files */ - if (p->closef == NULL) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; - } else { - /* Lua 5.1 implementation, for plain files */ - void *ud = lua_touserdata(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); - if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1)) - lua_pushnil(L); /* not a file */ - else if (*((FILE **)ud) == NULL) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; - } -} - -static int io_popen (lua_State *L); -static void createmeta (lua_State *L); - -# undef LUA_FILEHANDLE -# define LUA_FILEHANDLE COMPAT53_LUA_PFILEHANDLE - -LUAMOD_API int luaopen_compat53_io (lua_State *L) { - luaL_Reg const funcs[] = { - -/* for PUC-Rio Lua 5.1 only */ -# if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 && !defined(LUA_JITLIBNAME) - - { "popen", io_popen }, - { "type", io_ptype }, - -# endif /* for PUC-Rio Lua 5.1 only */ - - { NULL, NULL } - }; - luaL_newlib(L, funcs); - createmeta(L); - return 1; -} - - -/* fake CLANG feature detection on other compilers */ -# ifndef __has_attribute -# define __has_attribute(x) 0 -# endif -/* make luaopen_io(_XXX) static, so it (and all other referenced - * io functions) won't be included in the resulting dll - * (hopefully). - */ -# undef LUAMOD_API -# if defined(__GNUC__) || __has_attribute(__unused__) -# define LUAMOD_API __attribute__((__unused__)) static -# else -# define LUAMOD_API static -# endif - -#endif /* iolib.c */ diff --git a/lib/compat53/lstrlib.c b/lib/compat53/lstrlib.c deleted file mode 100644 index b4bed7e..0000000 --- a/lib/compat53/lstrlib.c +++ /dev/null @@ -1,1584 +0,0 @@ -/* -** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard library for string operations and pattern-matching -** See Copyright Notice in lua.h -*/ - -#define lstrlib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** maximum number of captures that a pattern can do during -** pattern-matching. This limit is arbitrary, but must fit in -** an unsigned char. -*/ -#if !defined(LUA_MAXCAPTURES) -#define LUA_MAXCAPTURES 32 -#endif - - -/* macro to 'unsign' a character */ -#define uchar(c) ((unsigned char)(c)) - - -/* -** Some sizes are better limited to fit in 'int', but must also fit in -** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) -*/ -#define MAX_SIZET ((size_t)(~(size_t)0)) - -#define MAXSIZE \ - (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) - - - - -static int str_len (lua_State *L) { - size_t l; - luaL_checklstring(L, 1, &l); - lua_pushinteger(L, (lua_Integer)l); - return 1; -} - - -/* translate a relative string position: negative means back from end */ -static lua_Integer posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; -} - - -static int str_sub (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); - lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (lua_Integer)l) end = l; - if (start <= end) - lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); - else lua_pushliteral(L, ""); - return 1; -} - - -static int str_reverse (lua_State *L) { - size_t l, i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i = 0; i < l; i++) - p[i] = s[l - i - 1]; - luaL_pushresultsize(&b, l); - return 1; -} - - -static int str_lower (lua_State *L) { - size_t l; - size_t i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - char *p = luaL_buffinitsize(L, &b, l); - for (i=0; i MAXSIZE / n) /* may overflow? */ - return luaL_error(L, "resulting string too large"); - else { - size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; - luaL_Buffer b; - char *p = luaL_buffinitsize(L, &b, totallen); - while (n-- > 1) { /* first n-1 copies (followed by separator) */ - memcpy(p, s, l * sizeof(char)); p += l; - if (lsep > 0) { /* empty 'memcpy' is not that cheap */ - memcpy(p, sep, lsep * sizeof(char)); - p += lsep; - } - } - memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ - luaL_pushresultsize(&b, totallen); - } - return 1; -} - - -static int str_byte (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); - lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); - int n, i; - if (posi < 1) posi = 1; - if (pose > (lua_Integer)l) pose = l; - if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* arithmetic overflow? */ - return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; - luaL_checkstack(L, n, "string slice too long"); - for (i=0; i= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index %%%d", l + 1); - return l; -} - - -static int capture_to_close (MatchState *ms) { - int level = ms->level; - for (level--; level>=0; level--) - if (ms->capture[level].len == CAP_UNFINISHED) return level; - return luaL_error(ms->L, "invalid pattern capture"); -} - - -static const char *classend (MatchState *ms, const char *p) { - switch (*p++) { - case L_ESC: { - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (ends with '%%')"); - return p+1; - } - case '[': { - if (*p == '^') p++; - do { /* look for a ']' */ - if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (missing ']')"); - if (*(p++) == L_ESC && p < ms->p_end) - p++; /* skip escapes (e.g. '%]') */ - } while (*p != ']'); - return p+1; - } - default: { - return p; - } - } -} - - -static int match_class (int c, int cl) { - int res; - switch (tolower(cl)) { - case 'a' : res = isalpha(c); break; - case 'c' : res = iscntrl(c); break; - case 'd' : res = isdigit(c); break; - case 'g' : res = isgraph(c); break; - case 'l' : res = islower(c); break; - case 'p' : res = ispunct(c); break; - case 's' : res = isspace(c); break; - case 'u' : res = isupper(c); break; - case 'w' : res = isalnum(c); break; - case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; /* deprecated option */ - default: return (cl == c); - } - return (islower(cl) ? res : !res); -} - - -static int matchbracketclass (int c, const char *p, const char *ec) { - int sig = 1; - if (*(p+1) == '^') { - sig = 0; - p++; /* skip the '^' */ - } - while (++p < ec) { - if (*p == L_ESC) { - p++; - if (match_class(c, uchar(*p))) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < ec)) { - p+=2; - if (uchar(*(p-2)) <= c && c <= uchar(*p)) - return sig; - } - else if (uchar(*p) == c) return sig; - } - return !sig; -} - - -static int singlematch (MatchState *ms, const char *s, const char *p, - const char *ep) { - if (s >= ms->src_end) - return 0; - else { - int c = uchar(*s); - switch (*p) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, uchar(*(p+1))); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); - } - } -} - - -static const char *matchbalance (MatchState *ms, const char *s, - const char *p) { - if (p >= ms->p_end - 1) - luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); - if (*s != *p) return NULL; - else { - int b = *p; - int e = *(p+1); - int cont = 1; - while (++s < ms->src_end) { - if (*s == e) { - if (--cont == 0) return s+1; - } - else if (*s == b) cont++; - } - } - return NULL; /* string ends out of balance */ -} - - -static const char *max_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - ptrdiff_t i = 0; /* counts maximum expand for item */ - while (singlematch(ms, s + i, p, ep)) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - const char *res = match(ms, (s+i), ep+1); - if (res) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return NULL; -} - - -static const char *min_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - for (;;) { - const char *res = match(ms, s, ep+1); - if (res != NULL) - return res; - else if (singlematch(ms, s, p, ep)) - s++; /* try with one more repetition */ - else return NULL; - } -} - - -static const char *start_capture (MatchState *ms, const char *s, - const char *p, int what) { - const char *res; - int level = ms->level; - if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); - ms->capture[level].init = s; - ms->capture[level].len = what; - ms->level = level+1; - if ((res=match(ms, s, p)) == NULL) /* match failed? */ - ms->level--; /* undo capture */ - return res; -} - - -static const char *end_capture (MatchState *ms, const char *s, - const char *p) { - int l = capture_to_close(ms); - const char *res; - ms->capture[l].len = s - ms->capture[l].init; /* close capture */ - if ((res = match(ms, s, p)) == NULL) /* match failed? */ - ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ - return res; -} - - -static const char *match_capture (MatchState *ms, const char *s, int l) { - size_t len; - l = check_capture(ms, l); - len = ms->capture[l].len; - if ((size_t)(ms->src_end-s) >= len && - memcmp(ms->capture[l].init, s, len) == 0) - return s+len; - else return NULL; -} - - -static const char *match (MatchState *ms, const char *s, const char *p) { - if (ms->matchdepth-- == 0) - luaL_error(ms->L, "pattern too complex"); - init: /* using goto's to optimize tail recursion */ - if (p != ms->p_end) { /* end of pattern? */ - switch (*p) { - case '(': { /* start capture */ - if (*(p + 1) == ')') /* position capture? */ - s = start_capture(ms, s, p + 2, CAP_POSITION); - else - s = start_capture(ms, s, p + 1, CAP_UNFINISHED); - break; - } - case ')': { /* end capture */ - s = end_capture(ms, s, p + 1); - break; - } - case '$': { - if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ - goto dflt; /* no; go to default */ - s = (s == ms->src_end) ? s : NULL; /* check end of string */ - break; - } - case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ - switch (*(p + 1)) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p + 2); - if (s != NULL) { - p += 4; goto init; /* return match(ms, s, p + 4); */ - } /* else fail (s == NULL) */ - break; - } - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - luaL_error(ms->L, "missing '[' after '%%f' in pattern"); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s - 1); - if (!matchbracketclass(uchar(previous), p, ep - 1) && - matchbracketclass(uchar(*s), p, ep - 1)) { - p = ep; goto init; /* return match(ms, s, ep); */ - } - s = NULL; /* match failed */ - break; - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p + 1))); - if (s != NULL) { - p += 2; goto init; /* return match(ms, s, p + 2) */ - } - break; - } - default: goto dflt; - } - break; - } - default: dflt: { /* pattern class plus optional suffix */ - const char *ep = classend(ms, p); /* points to optional suffix */ - /* does not match at least once? */ - if (!singlematch(ms, s, p, ep)) { - if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ - p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ - } - else /* '+' or no suffix */ - s = NULL; /* fail */ - } - else { /* matched once */ - switch (*ep) { /* handle optional suffix */ - case '?': { /* optional */ - const char *res; - if ((res = match(ms, s + 1, ep + 1)) != NULL) - s = res; - else { - p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ - } - break; - } - case '+': /* 1 or more repetitions */ - s++; /* 1 match already done */ - /* FALLTHROUGH */ - case '*': /* 0 or more repetitions */ - s = max_expand(ms, s, p, ep); - break; - case '-': /* 0 or more repetitions (minimum) */ - s = min_expand(ms, s, p, ep); - break; - default: /* no suffix */ - s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ - } - } - break; - } - } - } - ms->matchdepth++; - return s; -} - - - -static const char *lmemfind (const char *s1, size_t l1, - const char *s2, size_t l2) { - if (l2 == 0) return s1; /* empty strings are everywhere */ - else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ - else { - const char *init; /* to search for a '*s2' inside 's1' */ - l2--; /* 1st char will be checked by 'memchr' */ - l1 = l1-l2; /* 's2' cannot be found after that */ - while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { - init++; /* 1st char is already checked */ - if (memcmp(init, s2+1, l2) == 0) - return init-1; - else { /* correct 'l1' and 's1' to try again */ - l1 -= init-s1; - s1 = init; - } - } - return NULL; /* not found */ - } -} - - -static void push_onecapture (MatchState *ms, int i, const char *s, - const char *e) { - if (i >= ms->level) { - if (i == 0) /* ms->level == 0, too */ - lua_pushlstring(ms->L, s, e - s); /* add whole match */ - else - luaL_error(ms->L, "invalid capture index %%%d", i + 1); - } - else { - ptrdiff_t l = ms->capture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); - else - lua_pushlstring(ms->L, ms->capture[i].init, l); - } -} - - -static int push_captures (MatchState *ms, const char *s, const char *e) { - int i; - int nlevels = (ms->level == 0 && s) ? 1 : ms->level; - luaL_checkstack(ms->L, nlevels, "too many captures"); - for (i = 0; i < nlevels; i++) - push_onecapture(ms, i, s, e); - return nlevels; /* number of strings pushed */ -} - - -/* check whether pattern has no special characters */ -static int nospecials (const char *p, size_t l) { - size_t upto = 0; - do { - if (strpbrk(p + upto, SPECIALS)) - return 0; /* pattern has a special character */ - upto += strlen(p + upto) + 1; /* may have more after \0 */ - } while (upto <= l); - return 1; /* no special chars found */ -} - - -static void prepstate (MatchState *ms, lua_State *L, - const char *s, size_t ls, const char *p, size_t lp) { - ms->L = L; - ms->matchdepth = MAXCCALLS; - ms->src_init = s; - ms->src_end = s + ls; - ms->p_end = p + lp; -} - - -static void reprepstate (MatchState *ms) { - ms->level = 0; - lua_assert(ms->matchdepth == MAXCCALLS); -} - - -static int str_find_aux (lua_State *L, int find) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); - if (init < 1) init = 1; - else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ - lua_pushnil(L); /* cannot find anything */ - return 1; - } - /* explicit request or no special characters? */ - if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { - /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); - if (s2) { - lua_pushinteger(L, (s2 - s) + 1); - lua_pushinteger(L, (s2 - s) + lp); - return 2; - } - } - else { - MatchState ms; - const char *s1 = s + init - 1; - int anchor = (*p == '^'); - if (anchor) { - p++; lp--; /* skip anchor character */ - } - prepstate(&ms, L, s, ls, p, lp); - do { - const char *res; - reprepstate(&ms); - if ((res=match(&ms, s1, p)) != NULL) { - if (find) { - lua_pushinteger(L, (s1 - s) + 1); /* start */ - lua_pushinteger(L, res - s); /* end */ - return push_captures(&ms, NULL, 0) + 2; - } - else - return push_captures(&ms, s1, res); - } - } while (s1++ < ms.src_end && !anchor); - } - lua_pushnil(L); /* not found */ - return 1; -} - - -static int str_find (lua_State *L) { - return str_find_aux(L, 1); -} - - -static int str_match (lua_State *L) { - return str_find_aux(L, 0); -} - - -/* state for 'gmatch' */ -typedef struct GMatchState { - const char *src; /* current position */ - const char *p; /* pattern */ - const char *lastmatch; /* end of last match */ - MatchState ms; /* match state */ -} GMatchState; - - -static int gmatch_aux (lua_State *L) { - GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); - const char *src; - gm->ms.L = L; - for (src = gm->src; src <= gm->ms.src_end; src++) { - const char *e; - reprepstate(&gm->ms); - if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { - gm->src = gm->lastmatch = e; - return push_captures(&gm->ms, src, e); - } - } - return 0; /* not found */ -} - - -static int gmatch (lua_State *L) { - size_t ls, lp; - const char *s = luaL_checklstring(L, 1, &ls); - const char *p = luaL_checklstring(L, 2, &lp); - GMatchState *gm; - lua_settop(L, 2); /* keep them on closure to avoid being collected */ - gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); - prepstate(&gm->ms, L, s, ls, p, lp); - gm->src = s; gm->p = p; gm->lastmatch = NULL; - lua_pushcclosure(L, gmatch_aux, 3); - return 1; -} - - -static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e) { - size_t l, i; - lua_State *L = ms->L; - const char *news = lua_tolstring(L, 3, &l); - for (i = 0; i < l; i++) { - if (news[i] != L_ESC) - luaL_addchar(b, news[i]); - else { - i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) { - if (news[i] != L_ESC) - luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); - luaL_addchar(b, news[i]); - } - else if (news[i] == '0') - luaL_addlstring(b, s, e - s); - else { - push_onecapture(ms, news[i] - '1', s, e); - luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ - lua_remove(L, -2); /* remove original value */ - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } -} - - -static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, - const char *e, int tr) { - lua_State *L = ms->L; - switch (tr) { - case LUA_TFUNCTION: { - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - break; - } - case LUA_TTABLE: { - push_onecapture(ms, 0, s, e); - lua_gettable(L, 3); - break; - } - default: { /* LUA_TNUMBER or LUA_TSTRING */ - add_s(ms, b, s, e); - return; - } - } - if (!lua_toboolean(L, -1)) { /* nil or false? */ - lua_pop(L, 1); - lua_pushlstring(L, s, e - s); /* keep original text */ - } - else if (!lua_isstring(L, -1)) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); - luaL_addvalue(b); /* add result to accumulator */ -} - - -static int str_gsub (lua_State *L) { - size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ - const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ - const char *lastmatch = NULL; /* end of last match */ - int tr = lua_type(L, 3); /* replacement type */ - lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ - int anchor = (*p == '^'); - lua_Integer n = 0; /* replacement count */ - MatchState ms; - luaL_Buffer b; - luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || - tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, - "string/function/table expected"); - luaL_buffinit(L, &b); - if (anchor) { - p++; lp--; /* skip anchor character */ - } - prepstate(&ms, L, src, srcl, p, lp); - while (n < max_s) { - const char *e; - reprepstate(&ms); /* (re)prepare state for new match */ - if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ - n++; - add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ - src = lastmatch = e; - } - else if (src < ms.src_end) /* otherwise, skip one character */ - luaL_addchar(&b, *src++); - else break; /* end of subject */ - if (anchor) break; - } - luaL_addlstring(&b, src, ms.src_end-src); - luaL_pushresult(&b); - lua_pushinteger(L, n); /* number of substitutions */ - return 2; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** STRING FORMAT -** ======================================================= -*/ - -#if !defined(lua_number2strx) /* { */ - -/* -** Hexadecimal floating-point formatter -*/ - -#include - -#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) - - -/* -** Number of bits that goes into the first digit. It can be any value -** between 1 and 4; the following definition tries to align the number -** to nibble boundaries by making what is left after that first digit a -** multiple of 4. -*/ -#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) - - -/* -** Add integer part of 'x' to buffer and return new 'x' -*/ -static lua_Number adddigit (char *buff, int n, lua_Number x) { - lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ - int d = (int)dd; - buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ - return x - dd; /* return what is left */ -} - - -static int num2straux (char *buff, int sz, lua_Number x) { - /* if 'inf' or 'NaN', format it like '%g' */ - if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL) - return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x); - else if (x == 0) { /* can be -0... */ - /* create "0" or "-0" followed by exponent */ - return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x); - } - else { - int e; - lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ - int n = 0; /* character count */ - if (m < 0) { /* is number negative? */ - buff[n++] = '-'; /* add signal */ - m = -m; /* make it positive */ - } - buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ - m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ - e -= L_NBFD; /* this digit goes before the radix point */ - if (m > 0) { /* more digits? */ - buff[n++] = lua_getlocaledecpoint(); /* add radix point */ - do { /* add as many digits as needed */ - m = adddigit(buff, n++, m * 16); - } while (m > 0); - } - n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ - lua_assert(n < sz); - return n; - } -} - - -static int lua_number2strx (lua_State *L, char *buff, int sz, - const char *fmt, lua_Number x) { - int n = num2straux(buff, sz, x); - if (fmt[SIZELENMOD] == 'A') { - int i; - for (i = 0; i < n; i++) - buff[i] = toupper(uchar(buff[i])); - } - else if (fmt[SIZELENMOD] != 'a') - return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); - return n; -} - -#endif /* } */ - - -/* -** Maximum size of each formatted item. This maximum size is produced -** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', -** and '\0') + number of decimal digits to represent maxfloat (which -** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra -** expenses", such as locale-dependent stuff) -*/ -#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) - - -/* valid flags in a format specification */ -#define FLAGS "-+ #0" - -/* -** maximum size of each format specification (such as "%-099.99d") -*/ -#define MAX_FORMAT 32 - - -static void addquoted (luaL_Buffer *b, const char *s, size_t len) { - luaL_addchar(b, '"'); - while (len--) { - if (*s == '"' || *s == '\\' || *s == '\n') { - luaL_addchar(b, '\\'); - luaL_addchar(b, *s); - } - else if (iscntrl(uchar(*s))) { - char buff[10]; - if (!isdigit(uchar(*(s+1)))) - l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); - else - l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); - luaL_addstring(b, buff); - } - else - luaL_addchar(b, *s); - s++; - } - luaL_addchar(b, '"'); -} - - -/* -** Ensures the 'buff' string uses a dot as the radix character. -*/ -static void checkdp (char *buff, int nb) { - if (memchr(buff, '.', nb) == NULL) { /* no dot? */ - char point = lua_getlocaledecpoint(); /* try locale point */ - char *ppoint = (char *)memchr(buff, point, nb); - if (ppoint) *ppoint = '.'; /* change it to a dot */ - } -} - - -static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { - switch (lua_type(L, arg)) { - case LUA_TSTRING: { - size_t len; - const char *s = lua_tolstring(L, arg, &len); - addquoted(b, s, len); - break; - } - case LUA_TNUMBER: { - char *buff = luaL_prepbuffsize(b, MAX_ITEM); - int nb; - if (!lua_isinteger(L, arg)) { /* float? */ - lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ - nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); - checkdp(buff, nb); /* ensure it uses a dot */ - } - else { /* integers */ - lua_Integer n = lua_tointeger(L, arg); - const char *format = (n == LUA_MININTEGER) /* corner case? */ - ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ - : LUA_INTEGER_FMT; /* else use default format */ - nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); - } - luaL_addsize(b, nb); - break; - } - case LUA_TNIL: case LUA_TBOOLEAN: { - luaL_tolstring(L, arg, NULL); - luaL_addvalue(b); - break; - } - default: { - luaL_argerror(L, arg, "value has no literal form"); - } - } -} - - -static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { - const char *p = strfrmt; - while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit(uchar(*p))) p++; /* skip width */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - if (*p == '.') { - p++; - if (isdigit(uchar(*p))) p++; /* skip precision */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - } - if (isdigit(uchar(*p))) - luaL_error(L, "invalid format (width or precision too long)"); - *(form++) = '%'; - memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); - form += (p - strfrmt) + 1; - *form = '\0'; - return p; -} - - -/* -** add length modifier into formats -*/ -static void addlenmod (char *form, const char *lenmod) { - size_t l = strlen(form); - size_t lm = strlen(lenmod); - char spec = form[l - 1]; - strcpy(form + l - 1, lenmod); - form[l + lm - 1] = spec; - form[l + lm] = '\0'; -} - - -static int str_format (lua_State *L) { - int top = lua_gettop(L); - int arg = 1; - size_t sfl; - const char *strfrmt = luaL_checklstring(L, arg, &sfl); - const char *strfrmt_end = strfrmt+sfl; - luaL_Buffer b; - luaL_buffinit(L, &b); - while (strfrmt < strfrmt_end) { - if (*strfrmt != L_ESC) - luaL_addchar(&b, *strfrmt++); - else if (*++strfrmt == L_ESC) - luaL_addchar(&b, *strfrmt++); /* %% */ - else { /* format item */ - char form[MAX_FORMAT]; /* to store the format ('%...') */ - char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ - int nb = 0; /* number of bytes in added item */ - if (++arg > top) - luaL_argerror(L, arg, "no value"); - strfrmt = scanformat(L, strfrmt, form); - switch (*strfrmt++) { - case 'c': { - nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); - break; - } - case 'd': case 'i': - case 'o': case 'u': case 'x': case 'X': { - lua_Integer n = luaL_checkinteger(L, arg); - addlenmod(form, LUA_INTEGER_FRMLEN); - nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); - break; - } - case 'a': case 'A': - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = lua_number2strx(L, buff, MAX_ITEM, form, - luaL_checknumber(L, arg)); - break; - case 'e': case 'E': case 'f': - case 'g': case 'G': { - lua_Number n = luaL_checknumber(L, arg); - addlenmod(form, LUA_NUMBER_FRMLEN); - nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); - break; - } - case 'q': { - addliteral(L, &b, arg); - break; - } - case 's': { - size_t l; - const char *s = luaL_tolstring(L, arg, &l); - if (form[2] == '\0') /* no modifiers? */ - luaL_addvalue(&b); /* keep entire string */ - else { - luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); - if (!strchr(form, '.') && l >= 100) { - /* no precision and string is too long to be formatted */ - luaL_addvalue(&b); /* keep entire string */ - } - else { /* format the string into 'buff' */ - nb = l_sprintf(buff, MAX_ITEM, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - } - } - break; - } - default: { /* also treat cases 'pnLlh' */ - return luaL_error(L, "invalid option '%%%c' to 'format'", - *(strfrmt - 1)); - } - } - lua_assert(nb < MAX_ITEM); - luaL_addsize(&b, nb); - } - } - luaL_pushresult(&b); - return 1; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** PACK/UNPACK -** ======================================================= -*/ - - -/* value used for padding */ -#if !defined(LUAL_PACKPADBYTE) -#define LUAL_PACKPADBYTE 0x00 -#endif - -/* maximum size for the binary representation of an integer */ -#define MAXINTSIZE 16 - -/* number of bits in a character */ -#define NB CHAR_BIT - -/* mask for one character (NB 1's) */ -#define MC ((1 << NB) - 1) - -/* size of a lua_Integer */ -#define SZINT ((int)sizeof(lua_Integer)) - - -/* dummy union to get native endianness */ -static const union { - int dummy; - char little; /* true iff machine is little endian */ -} nativeendian = {1}; - - -/* dummy structure to get native alignment requirements */ -struct cD { - char c; - union { double d; void *p; lua_Integer i; lua_Number n; } u; -}; - -#define MAXALIGN (offsetof(struct cD, u)) - - -/* -** Union for serializing floats -*/ -typedef union Ftypes { - float f; - double d; - lua_Number n; - char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ -} Ftypes; - - -/* -** information to pack/unpack stuff -*/ -typedef struct Header { - lua_State *L; - int islittle; - int maxalign; -} Header; - - -/* -** options for pack/unpack -*/ -typedef enum KOption { - Kint, /* signed integers */ - Kuint, /* unsigned integers */ - Kfloat, /* floating-point numbers */ - Kchar, /* fixed-length strings */ - Kstring, /* strings with prefixed length */ - Kzstr, /* zero-terminated strings */ - Kpadding, /* padding */ - Kpaddalign, /* padding for alignment */ - Knop /* no-op (configuration or spaces) */ -} KOption; - - -/* -** Read an integer numeral from string 'fmt' or return 'df' if -** there is no numeral -*/ -static int digit (int c) { return '0' <= c && c <= '9'; } - -static int getnum (const char **fmt, int df) { - if (!digit(**fmt)) /* no number? */ - return df; /* return default value */ - else { - int a = 0; - do { - a = a*10 + (*((*fmt)++) - '0'); - } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); - return a; - } -} - - -/* -** Read an integer numeral and raises an error if it is larger -** than the maximum size for integers. -*/ -static int getnumlimit (Header *h, const char **fmt, int df) { - int sz = getnum(fmt, df); - if (sz > MAXINTSIZE || sz <= 0) - return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", - sz, MAXINTSIZE); - return sz; -} - - -/* -** Initialize Header -*/ -static void initheader (lua_State *L, Header *h) { - h->L = L; - h->islittle = nativeendian.little; - h->maxalign = 1; -} - - -/* -** Read and classify next option. 'size' is filled with option's size. -*/ -static KOption getoption (Header *h, const char **fmt, int *size) { - int opt = *((*fmt)++); - *size = 0; /* default */ - switch (opt) { - case 'b': *size = sizeof(char); return Kint; - case 'B': *size = sizeof(char); return Kuint; - case 'h': *size = sizeof(short); return Kint; - case 'H': *size = sizeof(short); return Kuint; - case 'l': *size = sizeof(long); return Kint; - case 'L': *size = sizeof(long); return Kuint; - case 'j': *size = sizeof(lua_Integer); return Kint; - case 'J': *size = sizeof(lua_Integer); return Kuint; - case 'T': *size = sizeof(size_t); return Kuint; - case 'f': *size = sizeof(float); return Kfloat; - case 'd': *size = sizeof(double); return Kfloat; - case 'n': *size = sizeof(lua_Number); return Kfloat; - case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; - case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; - case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; - case 'c': - *size = getnum(fmt, -1); - if (*size == -1) - luaL_error(h->L, "missing size for format option 'c'"); - return Kchar; - case 'z': return Kzstr; - case 'x': *size = 1; return Kpadding; - case 'X': return Kpaddalign; - case ' ': break; - case '<': h->islittle = 1; break; - case '>': h->islittle = 0; break; - case '=': h->islittle = nativeendian.little; break; - case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; - default: luaL_error(h->L, "invalid format option '%c'", opt); - } - return Knop; -} - - -/* -** Read, classify, and fill other details about the next option. -** 'psize' is filled with option's size, 'notoalign' with its -** alignment requirements. -** Local variable 'size' gets the size to be aligned. (Kpadal option -** always gets its full alignment, other options are limited by -** the maximum alignment ('maxalign'). Kchar option needs no alignment -** despite its size. -*/ -static KOption getdetails (Header *h, size_t totalsize, - const char **fmt, int *psize, int *ntoalign) { - KOption opt = getoption(h, fmt, psize); - int align = *psize; /* usually, alignment follows size */ - if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ - if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) - luaL_argerror(h->L, 1, "invalid next option for option 'X'"); - } - if (align <= 1 || opt == Kchar) /* need no alignment? */ - *ntoalign = 0; - else { - if (align > h->maxalign) /* enforce maximum alignment */ - align = h->maxalign; - if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ - luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); - *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); - } - return opt; -} - - -/* -** Pack integer 'n' with 'size' bytes and 'islittle' endianness. -** The final 'if' handles the case when 'size' is larger than -** the size of a Lua integer, correcting the extra sign-extension -** bytes if necessary (by default they would be zeros). -*/ -static void packint (luaL_Buffer *b, lua_Unsigned n, - int islittle, int size, int neg) { - char *buff = luaL_prepbuffsize(b, size); - int i; - buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ - for (i = 1; i < size; i++) { - n >>= NB; - buff[islittle ? i : size - 1 - i] = (char)(n & MC); - } - if (neg && size > SZINT) { /* negative number need sign extension? */ - for (i = SZINT; i < size; i++) /* correct extra bytes */ - buff[islittle ? i : size - 1 - i] = (char)MC; - } - luaL_addsize(b, size); /* add result to buffer */ -} - - -/* -** Copy 'size' bytes from 'src' to 'dest', correcting endianness if -** given 'islittle' is different from native endianness. -*/ -static void copywithendian (volatile char *dest, volatile const char *src, - int size, int islittle) { - if (islittle == nativeendian.little) { - while (size-- != 0) - *(dest++) = *(src++); - } - else { - dest += size - 1; - while (size-- != 0) - *(dest--) = *(src++); - } -} - - -static int str_pack (lua_State *L) { - luaL_Buffer b; - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - int arg = 1; /* current argument to pack */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - lua_pushnil(L); /* mark to separate arguments from string buffer */ - luaL_buffinit(L, &b); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - totalsize += ntoalign + size; - while (ntoalign-- > 0) - luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ - arg++; - switch (opt) { - case Kint: { /* signed integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) { /* need overflow check? */ - lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); - luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); - } - packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); - break; - } - case Kuint: { /* unsigned integers */ - lua_Integer n = luaL_checkinteger(L, arg); - if (size < SZINT) /* need overflow check? */ - luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), - arg, "unsigned overflow"); - packint(&b, (lua_Unsigned)n, h.islittle, size, 0); - break; - } - case Kfloat: { /* floating-point options */ - volatile Ftypes u; - char *buff = luaL_prepbuffsize(&b, size); - lua_Number n = luaL_checknumber(L, arg); /* get argument */ - if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ - else if (size == sizeof(u.d)) u.d = (double)n; - else u.n = n; - /* move 'u' to final result, correcting endianness if needed */ - copywithendian(buff, u.buff, size, h.islittle); - luaL_addsize(&b, size); - break; - } - case Kchar: { /* fixed-size string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, len <= (size_t)size, arg, - "string longer than given size"); - luaL_addlstring(&b, s, len); /* add string */ - while (len++ < (size_t)size) /* pad extra space */ - luaL_addchar(&b, LUAL_PACKPADBYTE); - break; - } - case Kstring: { /* strings with length count */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, size >= (int)sizeof(size_t) || - len < ((size_t)1 << (size * NB)), - arg, "string length does not fit in given size"); - packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ - luaL_addlstring(&b, s, len); - totalsize += len; - break; - } - case Kzstr: { /* zero-terminated string */ - size_t len; - const char *s = luaL_checklstring(L, arg, &len); - luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); - luaL_addlstring(&b, s, len); - luaL_addchar(&b, '\0'); /* add zero at the end */ - totalsize += len + 1; - break; - } - case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ - case Kpaddalign: case Knop: - arg--; /* undo increment */ - break; - } - } - luaL_pushresult(&b); - return 1; -} - - -static int str_packsize (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); /* format string */ - size_t totalsize = 0; /* accumulate total size of result */ - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); - size += ntoalign; /* total space used by option */ - luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, - "format result too large"); - totalsize += size; - switch (opt) { - case Kstring: /* strings with length count */ - case Kzstr: /* zero-terminated string */ - luaL_argerror(L, 1, "variable-length format"); - /* call never return, but to avoid warnings: *//* FALLTHROUGH */ - default: break; - } - } - lua_pushinteger(L, (lua_Integer)totalsize); - return 1; -} - - -/* -** Unpack an integer with 'size' bytes and 'islittle' endianness. -** If size is smaller than the size of a Lua integer and integer -** is signed, must do sign extension (propagating the sign to the -** higher bits); if size is larger than the size of a Lua integer, -** it must check the unread bytes to see whether they do not cause an -** overflow. -*/ -static lua_Integer unpackint (lua_State *L, const char *str, - int islittle, int size, int issigned) { - lua_Unsigned res = 0; - int i; - int limit = (size <= SZINT) ? size : SZINT; - for (i = limit - 1; i >= 0; i--) { - res <<= NB; - res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; - } - if (size < SZINT) { /* real size smaller than lua_Integer? */ - if (issigned) { /* needs sign extension? */ - lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); - res = ((res ^ mask) - mask); /* do sign extension */ - } - } - else if (size > SZINT) { /* must check unread bytes */ - int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; - for (i = limit; i < size; i++) { - if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) - luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); - } - } - return (lua_Integer)res; -} - - -static int str_unpack (lua_State *L) { - Header h; - const char *fmt = luaL_checkstring(L, 1); - size_t ld; - const char *data = luaL_checklstring(L, 2, &ld); - size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; - int n = 0; /* number of results */ - luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); - initheader(L, &h); - while (*fmt != '\0') { - int size, ntoalign; - KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); - if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) - luaL_argerror(L, 2, "data string too short"); - pos += ntoalign; /* skip alignment */ - /* stack space for item + next position */ - luaL_checkstack(L, 2, "too many results"); - n++; - switch (opt) { - case Kint: - case Kuint: { - lua_Integer res = unpackint(L, data + pos, h.islittle, size, - (opt == Kint)); - lua_pushinteger(L, res); - break; - } - case Kfloat: { - volatile Ftypes u; - lua_Number num; - copywithendian(u.buff, data + pos, size, h.islittle); - if (size == sizeof(u.f)) num = (lua_Number)u.f; - else if (size == sizeof(u.d)) num = (lua_Number)u.d; - else num = u.n; - lua_pushnumber(L, num); - break; - } - case Kchar: { - lua_pushlstring(L, data + pos, size); - break; - } - case Kstring: { - size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); - luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); - lua_pushlstring(L, data + pos + size, len); - pos += len; /* skip string */ - break; - } - case Kzstr: { - size_t len = (int)strlen(data + pos); - lua_pushlstring(L, data + pos, len); - pos += len + 1; /* skip string plus final '\0' */ - break; - } - case Kpaddalign: case Kpadding: case Knop: - n--; /* undo increment */ - break; - } - pos += size; - } - lua_pushinteger(L, pos + 1); /* next position */ - return n + 1; -} - -/* }====================================================== */ - - -static const luaL_Reg strlib[] = { - {"byte", str_byte}, - {"char", str_char}, - {"dump", str_dump}, - {"find", str_find}, - {"format", str_format}, - {"gmatch", gmatch}, - {"gsub", str_gsub}, - {"len", str_len}, - {"lower", str_lower}, - {"match", str_match}, - {"rep", str_rep}, - {"reverse", str_reverse}, - {"sub", str_sub}, - {"upper", str_upper}, - {"pack", str_pack}, - {"packsize", str_packsize}, - {"unpack", str_unpack}, - {NULL, NULL} -}; - - -static void createmetatable (lua_State *L) { - lua_createtable(L, 0, 1); /* table to be metatable for strings */ - lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); /* copy table */ - lua_setmetatable(L, -2); /* set table as metatable for strings */ - lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* get string library */ - lua_setfield(L, -2, "__index"); /* metatable.__index = string */ - lua_pop(L, 1); /* pop metatable */ -} - - -/* -** Open string library -*/ -LUAMOD_API int luaopen_string (lua_State *L) { - luaL_newlib(L, strlib); - createmetatable(L); - return 1; -} - diff --git a/lib/compat53/ltablib.c b/lib/compat53/ltablib.c deleted file mode 100644 index c534957..0000000 --- a/lib/compat53/ltablib.c +++ /dev/null @@ -1,450 +0,0 @@ -/* -** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ -** Library for Table Manipulation -** See Copyright Notice in lua.h -*/ - -#define ltablib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* -** Operations that an object must define to mimic a table -** (some functions only need some of them) -*/ -#define TAB_R 1 /* read */ -#define TAB_W 2 /* write */ -#define TAB_L 4 /* length */ -#define TAB_RW (TAB_R | TAB_W) /* read/write */ - - -#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) - - -static int checkfield (lua_State *L, const char *key, int n) { - lua_pushstring(L, key); - return (lua_rawget(L, -n) != LUA_TNIL); -} - - -/* -** Check that 'arg' either is a table or can behave like one (that is, -** has a metatable with the required metamethods) -*/ -static void checktab (lua_State *L, int arg, int what) { - if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ - int n = 1; /* number of elements to pop */ - if (lua_getmetatable(L, arg) && /* must have metatable */ - (!(what & TAB_R) || checkfield(L, "__index", ++n)) && - (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && - (!(what & TAB_L) || checkfield(L, "__len", ++n))) { - lua_pop(L, n); /* pop metatable and tested metamethods */ - } - else - luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ - } -} - - -#if defined(LUA_COMPAT_MAXN) -static int maxn (lua_State *L) { - lua_Number max = 0; - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushnil(L); /* first key */ - while (lua_next(L, 1)) { - lua_pop(L, 1); /* remove value */ - if (lua_type(L, -1) == LUA_TNUMBER) { - lua_Number v = lua_tonumber(L, -1); - if (v > max) max = v; - } - } - lua_pushnumber(L, max); - return 1; -} -#endif - - -static int tinsert (lua_State *L) { - lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ - lua_Integer pos; /* where to insert new element */ - switch (lua_gettop(L)) { - case 2: { /* called with only 2 arguments */ - pos = e; /* insert new element at the end */ - break; - } - case 3: { - lua_Integer i; - pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ - luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); - for (i = e; i > pos; i--) { /* move up elements */ - lua_geti(L, 1, i - 1); - lua_seti(L, 1, i); /* t[i] = t[i - 1] */ - } - break; - } - default: { - return luaL_error(L, "wrong number of arguments to 'insert'"); - } - } - lua_seti(L, 1, pos); /* t[pos] = v */ - return 0; -} - - -static int tremove (lua_State *L) { - lua_Integer size = aux_getn(L, 1, TAB_RW); - lua_Integer pos = luaL_optinteger(L, 2, size); - if (pos != size) /* validate 'pos' if given */ - luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - lua_geti(L, 1, pos); /* result = t[pos] */ - for ( ; pos < size; pos++) { - lua_geti(L, 1, pos + 1); - lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ - } - lua_pushnil(L); - lua_seti(L, 1, pos); /* t[pos] = nil */ - return 1; -} - - -/* -** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever -** possible, copy in increasing order, which is better for rehashing. -** "possible" means destination after original range, or smaller -** than origin, or copying to another table. -*/ -static int tmove (lua_State *L) { - lua_Integer f = luaL_checkinteger(L, 2); - lua_Integer e = luaL_checkinteger(L, 3); - lua_Integer t = luaL_checkinteger(L, 4); - int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ - checktab(L, 1, TAB_R); - checktab(L, tt, TAB_W); - if (e >= f) { /* otherwise, nothing to move */ - lua_Integer n, i; - luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, - "too many elements to move"); - n = e - f + 1; /* number of elements to move */ - luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, - "destination wrap around"); - if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { - for (i = 0; i < n; i++) { - lua_geti(L, 1, f + i); - lua_seti(L, tt, t + i); - } - } - else { - for (i = n - 1; i >= 0; i--) { - lua_geti(L, 1, f + i); - lua_seti(L, tt, t + i); - } - } - } - lua_pushvalue(L, tt); /* return destination table */ - return 1; -} - - -static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { - lua_geti(L, 1, i); - if (!lua_isstring(L, -1)) - luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", - luaL_typename(L, -1), i); - luaL_addvalue(b); -} - - -static int tconcat (lua_State *L) { - luaL_Buffer b; - lua_Integer last = aux_getn(L, 1, TAB_R); - size_t lsep; - const char *sep = luaL_optlstring(L, 2, "", &lsep); - lua_Integer i = luaL_optinteger(L, 3, 1); - last = luaL_optinteger(L, 4, last); - luaL_buffinit(L, &b); - for (; i < last; i++) { - addfield(L, &b, i); - luaL_addlstring(&b, sep, lsep); - } - if (i == last) /* add last value (if interval was not empty) */ - addfield(L, &b, i); - luaL_pushresult(&b); - return 1; -} - - -/* -** {====================================================== -** Pack/unpack -** ======================================================= -*/ - -static int pack (lua_State *L) { - int i; - int n = lua_gettop(L); /* number of elements to pack */ - lua_createtable(L, n, 1); /* create result table */ - lua_insert(L, 1); /* put it at index 1 */ - for (i = n; i >= 1; i--) /* assign elements */ - lua_seti(L, 1, i); - lua_pushinteger(L, n); - lua_setfield(L, 1, "n"); /* t.n = number of elements */ - return 1; /* return table */ -} - - -static int unpack (lua_State *L) { - lua_Unsigned n; - lua_Integer i = luaL_optinteger(L, 2, 1); - lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); - if (i > e) return 0; /* empty range */ - n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ - if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) - return luaL_error(L, "too many results to unpack"); - for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ - lua_geti(L, 1, i); - } - lua_geti(L, 1, e); /* push last element */ - return (int)n; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Quicksort -** (based on 'Algorithms in MODULA-3', Robert Sedgewick; -** Addison-Wesley, 1993.) -** ======================================================= -*/ - - -/* type for array indices */ -typedef unsigned int IdxT; - - -/* -** Produce a "random" 'unsigned int' to randomize pivot choice. This -** macro is used only when 'sort' detects a big imbalance in the result -** of a partition. (If you don't want/need this "randomness", ~0 is a -** good choice.) -*/ -#if !defined(l_randomizePivot) /* { */ - -#include - -/* size of 'e' measured in number of 'unsigned int's */ -#define sof(e) (sizeof(e) / sizeof(unsigned int)) - -/* -** Use 'time' and 'clock' as sources of "randomness". Because we don't -** know the types 'clock_t' and 'time_t', we cannot cast them to -** anything without risking overflows. A safe way to use their values -** is to copy them to an array of a known type and use the array values. -*/ -static unsigned int l_randomizePivot (void) { - clock_t c = clock(); - time_t t = time(NULL); - unsigned int buff[sof(c) + sof(t)]; - unsigned int i, rnd = 0; - memcpy(buff, &c, sof(c) * sizeof(unsigned int)); - memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); - for (i = 0; i < sof(buff); i++) - rnd += buff[i]; - return rnd; -} - -#endif /* } */ - - -/* arrays larger than 'RANLIMIT' may use randomized pivots */ -#define RANLIMIT 100u - - -static void set2 (lua_State *L, IdxT i, IdxT j) { - lua_seti(L, 1, i); - lua_seti(L, 1, j); -} - - -/* -** Return true iff value at stack index 'a' is less than the value at -** index 'b' (according to the order of the sort). -*/ -static int sort_comp (lua_State *L, int a, int b) { - if (lua_isnil(L, 2)) /* no function? */ - return lua_compare(L, a, b, LUA_OPLT); /* a < b */ - else { /* function */ - int res; - lua_pushvalue(L, 2); /* push function */ - lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ - lua_call(L, 2, 1); /* call function */ - res = lua_toboolean(L, -1); /* get result */ - lua_pop(L, 1); /* pop result */ - return res; - } -} - - -/* -** Does the partition: Pivot P is at the top of the stack. -** precondition: a[lo] <= P == a[up-1] <= a[up], -** so it only needs to do the partition from lo + 1 to up - 2. -** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] -** returns 'i'. -*/ -static IdxT partition (lua_State *L, IdxT lo, IdxT up) { - IdxT i = lo; /* will be incremented before first use */ - IdxT j = up - 1; /* will be decremented before first use */ - /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ - for (;;) { - /* next loop: repeat ++i while a[i] < P */ - while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ - luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ - /* next loop: repeat --j while P < a[j] */ - while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j < i) /* j < i but a[j] > P ?? */ - luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ - if (j < i) { /* no elements out of place? */ - /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ - lua_pop(L, 1); /* pop a[j] */ - /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ - set2(L, up - 1, i); - return i; - } - /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ - set2(L, i, j); - } -} - - -/* -** Choose an element in the middle (2nd-3th quarters) of [lo,up] -** "randomized" by 'rnd' -*/ -static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { - IdxT r4 = (up - lo) / 4; /* range/4 */ - IdxT p = rnd % (r4 * 2) + (lo + r4); - lua_assert(lo + r4 <= p && p <= up - r4); - return p; -} - - -/* -** QuickSort algorithm (recursive function) -*/ -static void auxsort (lua_State *L, IdxT lo, IdxT up, - unsigned int rnd) { - while (lo < up) { /* loop for tail recursion */ - IdxT p; /* Pivot index */ - IdxT n; /* to be used later */ - /* sort elements 'lo', 'p', and 'up' */ - lua_geti(L, 1, lo); - lua_geti(L, 1, up); - if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ - set2(L, lo, up); /* swap a[lo] - a[up] */ - else - lua_pop(L, 2); /* remove both values */ - if (up - lo == 1) /* only 2 elements? */ - return; /* already sorted */ - if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ - p = (lo + up)/2; /* middle element is a good pivot */ - else /* for larger intervals, it is worth a random pivot */ - p = choosePivot(lo, up, rnd); - lua_geti(L, 1, p); - lua_geti(L, 1, lo); - if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ - set2(L, p, lo); /* swap a[p] - a[lo] */ - else { - lua_pop(L, 1); /* remove a[lo] */ - lua_geti(L, 1, up); - if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ - set2(L, p, up); /* swap a[up] - a[p] */ - else - lua_pop(L, 2); - } - if (up - lo == 2) /* only 3 elements? */ - return; /* already sorted */ - lua_geti(L, 1, p); /* get middle element (Pivot) */ - lua_pushvalue(L, -1); /* push Pivot */ - lua_geti(L, 1, up - 1); /* push a[up - 1] */ - set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ - p = partition(L, lo, up); - /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ - if (p - lo < up - p) { /* lower interval is smaller? */ - auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ - n = p - lo; /* size of smaller interval */ - lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ - } - else { - auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ - n = up - p; /* size of smaller interval */ - up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ - } - if ((up - lo) / 128 > n) /* partition too imbalanced? */ - rnd = l_randomizePivot(); /* try a new randomization */ - } /* tail call auxsort(L, lo, up, rnd) */ -} - - -static int sort (lua_State *L) { - lua_Integer n = aux_getn(L, 1, TAB_RW); - if (n > 1) { /* non-trivial interval? */ - luaL_argcheck(L, n < INT_MAX, 1, "array too big"); - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ - lua_settop(L, 2); /* make sure there are two arguments */ - auxsort(L, 1, (IdxT)n, 0); - } - return 0; -} - -/* }====================================================== */ - - -static const luaL_Reg tab_funcs[] = { - {"concat", tconcat}, -#if defined(LUA_COMPAT_MAXN) - {"maxn", maxn}, -#endif - {"insert", tinsert}, - {"pack", pack}, - {"unpack", unpack}, - {"remove", tremove}, - {"move", tmove}, - {"sort", sort}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_table (lua_State *L) { - luaL_newlib(L, tab_funcs); -#if defined(LUA_COMPAT_UNPACK) - /* _G.unpack = table.unpack */ - lua_getfield(L, -1, "unpack"); - lua_setglobal(L, "unpack"); -#endif - return 1; -} - diff --git a/lib/compat53/lutf8lib.c b/lib/compat53/lutf8lib.c deleted file mode 100644 index 10bd238..0000000 --- a/lib/compat53/lutf8lib.c +++ /dev/null @@ -1,256 +0,0 @@ -/* -** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ -** Standard library for UTF-8 manipulation -** See Copyright Notice in lua.h -*/ - -#define lutf8lib_c -#define LUA_LIB - -#include "lprefix.h" - - -#include -#include -#include -#include - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - -#define MAXUNICODE 0x10FFFF - -#define iscont(p) ((*(p) & 0xC0) == 0x80) - - -/* from strlib */ -/* translate a relative string position: negative means back from end */ -static lua_Integer u_posrelat (lua_Integer pos, size_t len) { - if (pos >= 0) return pos; - else if (0u - (size_t)pos > len) return 0; - else return (lua_Integer)len + pos + 1; -} - - -/* -** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. -*/ -static const char *utf8_decode (const char *o, int *val) { - static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; - const unsigned char *s = (const unsigned char *)o; - unsigned int c = s[0]; - unsigned int res = 0; /* final result */ - if (c < 0x80) /* ascii? */ - res = c; - else { - int count = 0; /* to count number of continuation bytes */ - while (c & 0x40) { /* still have continuation bytes? */ - int cc = s[++count]; /* read next byte */ - if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ - return NULL; /* invalid byte sequence */ - res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ - c <<= 1; /* to test next bit */ - } - res |= ((c & 0x7F) << (count * 5)); /* add first byte */ - if (count > 3 || res > MAXUNICODE || res <= limits[count]) - return NULL; /* invalid byte sequence */ - s += count; /* skip continuation bytes read */ - } - if (val) *val = res; - return (const char *)s + 1; /* +1 to include first byte */ -} - - -/* -** utf8len(s [, i [, j]]) --> number of characters that start in the -** range [i,j], or nil + current position if 's' is not well formed in -** that interval -*/ -static int utflen (lua_State *L) { - int n = 0; - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, - "initial position out of string"); - luaL_argcheck(L, --posj < (lua_Integer)len, 3, - "final position out of string"); - while (posi <= posj) { - const char *s1 = utf8_decode(s + posi, NULL); - if (s1 == NULL) { /* conversion error? */ - lua_pushnil(L); /* return nil ... */ - lua_pushinteger(L, posi + 1); /* ... and current position */ - return 2; - } - posi = s1 - s; - n++; - } - lua_pushinteger(L, n); - return 1; -} - - -/* -** codepoint(s, [i, [j]]) -> returns codepoints for all characters -** that start in the range [i,j] -*/ -static int codepoint (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); - lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); - int n; - const char *se; - luaL_argcheck(L, posi >= 1, 2, "out of range"); - luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); - if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ - return luaL_error(L, "string slice too long"); - n = (int)(pose - posi) + 1; - luaL_checkstack(L, n, "string slice too long"); - n = 0; - se = s + pose; - for (s += posi - 1; s < se;) { - int code; - s = utf8_decode(s, &code); - if (s == NULL) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, code); - n++; - } - return n; -} - - -static void pushutfchar (lua_State *L, int arg) { - lua_Integer code = luaL_checkinteger(L, arg); - luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); - lua_pushfstring(L, "%U", (long)code); -} - - -/* -** utfchar(n1, n2, ...) -> char(n1)..char(n2)... -*/ -static int utfchar (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - if (n == 1) /* optimize common case of single char */ - pushutfchar(L, 1); - else { - int i; - luaL_Buffer b; - luaL_buffinit(L, &b); - for (i = 1; i <= n; i++) { - pushutfchar(L, i); - luaL_addvalue(&b); - } - luaL_pushresult(&b); - } - return 1; -} - - -/* -** offset(s, n, [i]) -> index where n-th character counting from -** position 'i' starts; 0 means character at 'i'. -*/ -static int byteoffset (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = luaL_checkinteger(L, 2); - lua_Integer posi = (n >= 0) ? 1 : len + 1; - posi = u_posrelat(luaL_optinteger(L, 3, posi), len); - luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, - "position out of range"); - if (n == 0) { - /* find beginning of current byte sequence */ - while (posi > 0 && iscont(s + posi)) posi--; - } - else { - if (iscont(s + posi)) - return luaL_error(L, "initial position is a continuation byte"); - if (n < 0) { - while (n < 0 && posi > 0) { /* move back */ - do { /* find beginning of previous character */ - posi--; - } while (posi > 0 && iscont(s + posi)); - n++; - } - } - else { - n--; /* do not move for 1st character */ - while (n > 0 && posi < (lua_Integer)len) { - do { /* find beginning of next character */ - posi++; - } while (iscont(s + posi)); /* (cannot pass final '\0') */ - n--; - } - } - } - if (n == 0) /* did it find given character? */ - lua_pushinteger(L, posi + 1); - else /* no such character */ - lua_pushnil(L); - return 1; -} - - -static int iter_aux (lua_State *L) { - size_t len; - const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = lua_tointeger(L, 2) - 1; - if (n < 0) /* first iteration? */ - n = 0; /* start from here */ - else if (n < (lua_Integer)len) { - n++; /* skip current byte */ - while (iscont(s + n)) n++; /* and its continuations */ - } - if (n >= (lua_Integer)len) - return 0; /* no more codepoints */ - else { - int code; - const char *next = utf8_decode(s + n, &code); - if (next == NULL || iscont(next)) - return luaL_error(L, "invalid UTF-8 code"); - lua_pushinteger(L, n + 1); - lua_pushinteger(L, code); - return 2; - } -} - - -static int iter_codes (lua_State *L) { - luaL_checkstring(L, 1); - lua_pushcfunction(L, iter_aux); - lua_pushvalue(L, 1); - lua_pushinteger(L, 0); - return 3; -} - - -/* pattern to match a single UTF-8 character */ -#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" - - -static const luaL_Reg funcs[] = { - {"offset", byteoffset}, - {"codepoint", codepoint}, - {"char", utfchar}, - {"len", utflen}, - {"codes", iter_codes}, - /* placeholders */ - {"charpattern", NULL}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_utf8 (lua_State *L) { - luaL_newlib(L, funcs); - lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); - lua_setfield(L, -2, "charpattern"); - return 1; -} - diff --git a/lib/compat53/rockspecs/bit32-5.3.5-1.rockspec b/lib/compat53/rockspecs/bit32-5.3.5-1.rockspec deleted file mode 100644 index 353e19c..0000000 --- a/lib/compat53/rockspecs/bit32-5.3.5-1.rockspec +++ /dev/null @@ -1,28 +0,0 @@ -package = "bit32" -version = "5.3.5-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.9.zip", - dir = "lua-compat-5.3-0.9", -} -description = { - summary = "Lua 5.2 bit manipulation library", - detailed = [[ - bit32 is the native Lua 5.2 bit manipulation library, in the version - from Lua 5.3; it is compatible with Lua 5.1, 5.2 and 5.3. - ]], - homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" -} -build = { - type = "builtin", - modules = { - bit32 = { - sources = { "lbitlib.c" }, - defines = { "LUA_COMPAT_BITLIB" }, - incdirs = { "c-api" }, - } - } -} diff --git a/lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec b/lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec deleted file mode 100644 index 371f1ae..0000000 --- a/lib/compat53/rockspecs/bit32-5.3.5.1-1.rockspec +++ /dev/null @@ -1,28 +0,0 @@ -package = "bit32" -version = "5.3.5.1-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.10.zip", - dir = "lua-compat-5.3-0.10", -} -description = { - summary = "Lua 5.2 bit manipulation library", - detailed = [[ - bit32 is the native Lua 5.2 bit manipulation library, in the version - from Lua 5.3; it is compatible with Lua 5.1, 5.2, 5.3 and 5.4. - ]], - homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" -} -build = { - type = "builtin", - modules = { - bit32 = { - sources = { "lbitlib.c" }, - defines = { "LUA_COMPAT_BITLIB" }, - incdirs = { "c-api" }, - } - } -} diff --git a/lib/compat53/rockspecs/bit32-scm-1.rockspec b/lib/compat53/rockspecs/bit32-scm-1.rockspec deleted file mode 100644 index 78f9736..0000000 --- a/lib/compat53/rockspecs/bit32-scm-1.rockspec +++ /dev/null @@ -1,28 +0,0 @@ -package = "bit32" -version = "scm-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/master.zip", - dir = "lua-compat-5.3-master", -} -description = { - summary = "Lua 5.2 bit manipulation library", - detailed = [[ - bit32 is the native Lua 5.2 bit manipulation library, in the version - from Lua 5.3; it is compatible with Lua 5.1, 5.2 and 5.3. - ]], - homepage = "http://www.lua.org/manual/5.2/manual.html#6.7", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" -} -build = { - type = "builtin", - modules = { - bit32 = { - sources = { "lbitlib.c" }, - defines = { "LUA_COMPAT_BITLIB" }, - incdirs = { "c-api" }, - } - } -} diff --git a/lib/compat53/rockspecs/compat53-0.1-1.rockspec b/lib/compat53/rockspecs/compat53-0.1-1.rockspec deleted file mode 100644 index b9012fe..0000000 --- a/lib/compat53/rockspecs/compat53-0.1-1.rockspec +++ /dev/null @@ -1,31 +0,0 @@ -package = "compat53" -version = "0.1-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.1.zip", - dir = "lua-compat-5.3-0.1", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.4", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53"] = "compat53.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.11-1.rockspec b/lib/compat53/rockspecs/compat53-0.11-1.rockspec deleted file mode 100644 index 9608f0a..0000000 --- a/lib/compat53/rockspecs/compat53-0.11-1.rockspec +++ /dev/null @@ -1,33 +0,0 @@ -package = "compat53" -version = "0.11-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.11.zip", - dir = "lua-compat-5.3-0.11", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - ["compat53.io"] = "liolib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.12-1.rockspec b/lib/compat53/rockspecs/compat53-0.12-1.rockspec deleted file mode 100644 index 1b120ca..0000000 --- a/lib/compat53/rockspecs/compat53-0.12-1.rockspec +++ /dev/null @@ -1,33 +0,0 @@ -package = "compat53" -version = "0.12-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.12.zip", - dir = "lua-compat-5.3-0.12", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - ["compat53.io"] = "liolib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.13-1.rockspec b/lib/compat53/rockspecs/compat53-0.13-1.rockspec deleted file mode 100644 index f08dc66..0000000 --- a/lib/compat53/rockspecs/compat53-0.13-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.13-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13.zip", - dir = "lua-compat-5.3-0.13" -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.io"] = "liolib.c", - ["compat53.module"] = "compat53/module.lua", - ["compat53.string"] = "lstrlib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.utf8"] = "lutf8lib.c" - } -} diff --git a/lib/compat53/rockspecs/compat53-0.14-1.rockspec b/lib/compat53/rockspecs/compat53-0.14-1.rockspec deleted file mode 100644 index 54ad4a9..0000000 --- a/lib/compat53/rockspecs/compat53-0.14-1.rockspec +++ /dev/null @@ -1,33 +0,0 @@ -package = "compat53" -version = "0.14-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.zip", - dir = "lua-compat-5.3-0.14" -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.file_mt"] = "compat53/file_mt.lua", - ["compat53.init"] = "compat53/init.lua", - ["compat53.io"] = "liolib.c", - ["compat53.module"] = "compat53/module.lua", - ["compat53.string"] = "lstrlib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.utf8"] = "lutf8lib.c" - } -} diff --git a/lib/compat53/rockspecs/compat53-0.14.1-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.1-1.rockspec deleted file mode 100644 index ea35bb2..0000000 --- a/lib/compat53/rockspecs/compat53-0.14.1-1.rockspec +++ /dev/null @@ -1,33 +0,0 @@ -package = "compat53" -version = "0.14.1-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.1.zip", - dir = "lua-compat-5.3-0.14.1" -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.file_mt"] = "compat53/file_mt.lua", - ["compat53.init"] = "compat53/init.lua", - ["compat53.io"] = "liolib.c", - ["compat53.module"] = "compat53/module.lua", - ["compat53.string"] = "lstrlib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.utf8"] = "lutf8lib.c" - } -} diff --git a/lib/compat53/rockspecs/compat53-0.14.2-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.2-1.rockspec deleted file mode 100644 index 99236fe..0000000 --- a/lib/compat53/rockspecs/compat53-0.14.2-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.14.2-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.2.zip", - dir = "lua-compat-5.3-0.14.2" -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" -} -build = { - type = "builtin", - modules = { - ["compat53.file_mt"] = "compat53/file_mt.lua", - ["compat53.init"] = "compat53/init.lua", - ["compat53.io"] = "liolib.c", - ["compat53.module"] = "compat53/module.lua", - ["compat53.string"] = "lstrlib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.utf8"] = "lutf8lib.c" - } -} diff --git a/lib/compat53/rockspecs/compat53-0.14.3-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.3-1.rockspec deleted file mode 100644 index d6327d7..0000000 --- a/lib/compat53/rockspecs/compat53-0.14.3-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.14.3-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.3.zip", - dir = "lua-compat-5.3-0.14.3" -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" -} -build = { - type = "builtin", - modules = { - ["compat53.file_mt"] = "compat53/file_mt.lua", - ["compat53.init"] = "compat53/init.lua", - ["compat53.io"] = "liolib.c", - ["compat53.module"] = "compat53/module.lua", - ["compat53.string"] = "lstrlib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.utf8"] = "lutf8lib.c" - } -} diff --git a/lib/compat53/rockspecs/compat53-0.14.4-1.rockspec b/lib/compat53/rockspecs/compat53-0.14.4-1.rockspec deleted file mode 100644 index 804220f..0000000 --- a/lib/compat53/rockspecs/compat53-0.14.4-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.14.4-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.14.4.zip", - dir = "lua-compat-5.3-0.14.4" -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5" -} -build = { - type = "builtin", - modules = { - ["compat53.file_mt"] = "compat53/file_mt.lua", - ["compat53.init"] = "compat53/init.lua", - ["compat53.io"] = "liolib.c", - ["compat53.module"] = "compat53/module.lua", - ["compat53.string"] = "lstrlib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.utf8"] = "lutf8lib.c" - } -} diff --git a/lib/compat53/rockspecs/compat53-0.2-1.rockspec b/lib/compat53/rockspecs/compat53-0.2-1.rockspec deleted file mode 100644 index 47ddaf2..0000000 --- a/lib/compat53/rockspecs/compat53-0.2-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.2-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.2.zip", - dir = "lua-compat-5.3-0.2", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.4", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.3-1.rockspec b/lib/compat53/rockspecs/compat53-0.3-1.rockspec deleted file mode 100644 index d99099f..0000000 --- a/lib/compat53/rockspecs/compat53-0.3-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.3-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.3.zip", - dir = "lua-compat-5.3-0.3", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.4", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.4-1.rockspec b/lib/compat53/rockspecs/compat53-0.4-1.rockspec deleted file mode 100644 index bc33826..0000000 --- a/lib/compat53/rockspecs/compat53-0.4-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.4-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.4.zip", - dir = "lua-compat-5.3-0.4", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.4", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.5-1.rockspec b/lib/compat53/rockspecs/compat53-0.5-1.rockspec deleted file mode 100644 index 8d18b51..0000000 --- a/lib/compat53/rockspecs/compat53-0.5-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.5-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.5.zip", - dir = "lua-compat-5.3-0.5", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.4", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.7-1.rockspec b/lib/compat53/rockspecs/compat53-0.7-1.rockspec deleted file mode 100644 index fc5a0c8..0000000 --- a/lib/compat53/rockspecs/compat53-0.7-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.7-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.7.zip", - dir = "lua-compat-5.3-0.7", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.3, 5.2, and 5.1. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.4", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-0.8-1.rockspec b/lib/compat53/rockspecs/compat53-0.8-1.rockspec deleted file mode 100644 index 2fe47b9..0000000 --- a/lib/compat53/rockspecs/compat53-0.8-1.rockspec +++ /dev/null @@ -1,32 +0,0 @@ -package = "compat53" -version = "0.8-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.8.zip", - dir = "lua-compat-5.3-0.8", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - } -} - diff --git a/lib/compat53/rockspecs/compat53-scm-1.rockspec b/lib/compat53/rockspecs/compat53-scm-1.rockspec deleted file mode 100644 index b0581f9..0000000 --- a/lib/compat53/rockspecs/compat53-scm-1.rockspec +++ /dev/null @@ -1,34 +0,0 @@ -package = "compat53" -version = "scm-1" -source = { - url = "https://github.com/lunarmodules/lua-compat-5.3/archive/master.zip", - dir = "lua-compat-5.3-master", -} -description = { - summary = "Compatibility module providing Lua-5.3-style APIs for Lua 5.2 and 5.1", - detailed = [[ - This is a small module that aims to make it easier to write Lua - code in a Lua-5.3-style that runs on Lua 5.1+. - It does *not* make Lua 5.2 (or even 5.1) entirely compatible - with Lua 5.3, but it brings the API closer to that of Lua 5.3. - ]], - homepage = "https://github.com/lunarmodules/lua-compat-5.3", - license = "MIT" -} -dependencies = { - "lua >= 5.1, < 5.5", - --"struct" -- make Roberto's struct module optional -} -build = { - type = "builtin", - modules = { - ["compat53.init"] = "compat53/init.lua", - ["compat53.module"] = "compat53/module.lua", - ["compat53.file_mt"] = "compat53/file_mt.lua", - ["compat53.utf8"] = "lutf8lib.c", - ["compat53.table"] = "ltablib.c", - ["compat53.string"] = "lstrlib.c", - ["compat53.io"] = "liolib.c", - } -} - diff --git a/lib/compat53/tests/test-bit32.lua b/lib/compat53/tests/test-bit32.lua deleted file mode 100755 index a408b7d..0000000 --- a/lib/compat53/tests/test-bit32.lua +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env lua - -local bit32 = require("bit32") - - -assert(bit32.bnot(0) == 2^32-1) -assert(bit32.bnot(-1) == 0) -assert(bit32.band(1, 3, 5) == 1) -assert(bit32.bor(1, 3, 5) == 7) - diff --git a/lib/compat53/tests/test.lua b/lib/compat53/tests/test.lua deleted file mode 100755 index 503e3f4..0000000 --- a/lib/compat53/tests/test.lua +++ /dev/null @@ -1,866 +0,0 @@ -#!/usr/bin/env lua - -local F, tproxy, writefile, noprint, ___ -do - local type, unpack = type, table.unpack or unpack - local assert, io = assert, io - function F(...) - local args, n = { ... }, select('#', ...) - for i = 1, n do - local t = type(args[i]) - if t ~= "string" and t ~= "number" and t ~= "boolean" then - args[i] = t - end - end - return unpack(args, 1, n) - end - function tproxy(t) - return setmetatable({}, { - __index = t, - __newindex = t, - __len = function() return #t end, - }), t - end - function writefile(name, contents, bin) - local f = assert(io.open(name, bin and "wb" or "w")) - f:write(contents) - f:close() - end - function noprint() end - local sep = ("="):rep(70) - function ___() - print(sep) - end -end - -local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") -if jit then V = "jit" end - -local is_puclua51 = (_VERSION == "Lua 5.1" and not jit) - -local mode = "global" -if arg[1] == "module" then - mode = "module" -end -local self = arg[0] - -package.path = "../?.lua;../?/init.lua" -package.cpath = "./?-"..V..".so;./?-"..V..".dll;./?.so;./?.dll" -if mode == "module" then - print("testing Lua API using `compat53.module` ...") - _ENV = require("compat53.module") - if setfenv then setfenv(1, _ENV) end -else - print("testing Lua API using `compat53` ...") - require("compat53") -end - - -___'' -do - print("assert", F(pcall(assert, false))) - print("assert", F(pcall(assert, false, nil))) - print("assert", F(pcall(assert, false, "error msg"))) - print("assert", F(pcall(assert, nil, {}))) - print("assert", F(pcall(assert, 1, 2, 3))) -end - - -___'' -do - local t = setmetatable({}, { __index = { 1, false, "three" } }) - for i,v in ipairs(t) do - print("ipairs", i, v) - end -end - - -___'' -do - local p, t = tproxy{ "a", "b", "c" } - print("table.concat", table.concat(p)) - print("table.concat", table.concat(p, ",", 2)) - print("table.concat", table.concat(p, ".", 1, 2)) - print("table.concat", table.concat(t)) - print("table.concat", table.concat(t, ",", 2)) - print("table.concat", table.concat(t, ".", 1, 2)) -end - - -___'' -do - local p, t = tproxy{ "a", "b", "c" } - table.insert(p, "d") - print("table.insert", next(p), t[4]) - table.insert(p, 1, "z") - print("table.insert", next(p), t[1], t[2]) - table.insert(p, 2, "y") - print("table.insert", next(p), t[1], t[2], p[3]) - t = { "a", "b", "c" } - table.insert(t, "d") - print("table.insert", t[1], t[2], t[3], t[4]) - table.insert(t, 1, "z") - print("table.insert", t[1], t[2], t[3], t[4], t[5]) - table.insert(t, 2, "y") - print("table.insert", t[1], t[2], t[3], t[4], t[5]) -end - - -___'' -do - local ps, s = tproxy{ "a", "b", "c", "d" } - local pd, d = tproxy{ "A", "B", "C", "D" } - table.move(ps, 1, 4, 1, pd) - print("table.move", next(pd), d[1], d[2], d[3], d[4]) - pd, d = tproxy{ "A", "B", "C", "D" } - table.move(ps, 2, 4, 1, pd) - print("table.move", next(pd), d[1], d[2], d[3], d[4]) - pd, d = tproxy{ "A", "B", "C", "D" } - table.move(ps, 2, 3, 4, pd) - print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5]) - table.move(ps, 2, 4, 1) - print("table.move", next(ps), s[1], s[2], s[3], s[4]) - ps, s = tproxy{ "a", "b", "c", "d" } - table.move(ps, 2, 3, 4) - print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5]) - s = { "a", "b", "c", "d" } - d = { "A", "B", "C", "D" } - table.move(s, 1, 4, 1, d) - print("table.move", d[1], d[2], d[3], d[4]) - d = { "A", "B", "C", "D" } - table.move(s, 2, 4, 1, d) - print("table.move", d[1], d[2], d[3], d[4]) - d = { "A", "B", "C", "D" } - table.move(s, 2, 3, 4, d) - print("table.move", d[1], d[2], d[3], d[4], d[5]) - table.move(s, 2, 4, 1) - print("table.move", s[1], s[2], s[3], s[4]) - s = { "a", "b", "c", "d" } - table.move(s, 2, 3, 4) - print("table.move", s[1], s[2], s[3], s[4], s[5]) -end - - -___'' -do - local p, t = tproxy{ "a", "b", "c", "d", "e" } - print("table.remove", table.remove(p)) - print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5]) - print("table.remove", table.remove(p, 1)) - print("table.remove", next(p), t[1], t[2], t[3], t[4]) - print("table.remove", table.remove(p, 2)) - print("table.remove", next(p), t[1], t[2], t[3]) - print("table.remove", table.remove(p, 3)) - print("table.remove", next(p), t[1], t[2], t[3]) - p, t = tproxy{} - print("table.remove", table.remove(p)) - print("table.remove", next(p), next(t)) - t = { "a", "b", "c", "d", "e" } - print("table.remove", table.remove(t)) - print("table.remove", t[1], t[2], t[3], t[4], t[5]) - print("table.remove", table.remove(t, 1)) - print("table.remove", t[1], t[2], t[3], t[4]) - print("table.remove", table.remove(t, 2)) - print("table.remove", t[1], t[2], t[3]) - print("table.remove", table.remove(t, 3)) - print("table.remove", t[1], t[2], t[3]) - t = {} - print("table.remove", table.remove(t)) - print("table.remove", next(t)) -end - -___'' -do - local p, t = tproxy{ 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } - table.sort(p) - print("table.sort", next(p)) - for i,v in ipairs(t) do - print("table.sort", i, v) - end - table.sort(p) - print("table.sort", next(p)) - for i,v in ipairs(t) do - print("table.sort", i, v) - end - p, t = tproxy{ 9, 8, 7, 6, 5, 4, 3, 2, 1 } - table.sort(p) - print("table.sort", next(p)) - for i,v in ipairs(t) do - print("table.sort", i, v) - end - table.sort(p, function(a, b) return a > b end) - print("table.sort", next(p)) - for i,v in ipairs(t) do - print("table.sort", i, v) - end - p, t = tproxy{ 1, 1, 1, 1, 1 } - print("table.sort", next(p)) - for i,v in ipairs(t) do - print("table.sort", i, v) - end - t = { 3, 1, 5, 2, 8, 5, 2, 9, 7, 4 } - table.sort(t) - for i,v in ipairs(t) do - print("table.sort", i, v) - end - table.sort(t, function(a, b) return a > b end) - for i,v in ipairs(t) do - print("table.sort", i, v) - end -end - - -___'' -do - local p, t = tproxy{ "a", "b", "c" } - print("table.unpack", table.unpack(p)) - print("table.unpack", table.unpack(p, 2)) - print("table.unpack", table.unpack(p, 1, 2)) - print("table.unpack", table.unpack(t)) - print("table.unpack", table.unpack(t, 2)) - print("table.unpack", table.unpack(t, 1, 2)) -end - - -___'' -print("math.maxinteger", math.maxinteger+1 > math.maxinteger) -print("math.mininteger", math.mininteger-1 < math.mininteger) - - -___'' -print("math.tointeger", math.tointeger(0)) -print("math.tointeger", math.tointeger(math.pi)) -print("math.tointeger", math.tointeger("123")) -print("math.tointeger", math.tointeger("hello")) -print("math.tointeger", math.tointeger(math.maxinteger+2.0)) -print("math.tointeger", math.tointeger(math.mininteger*2.0)) - - -___'' -print("math.type", math.type(0)) -print("math.type", math.type(math.pi)) -print("math.type", math.type("hello")) - - -___'' -print("math.ult", math.ult(1, 2), math.ult(2, 1)) -print("math.ult", math.ult(-1, 2), math.ult(2, -1)) -print("math.ult", math.ult(-1, -2), math.ult(-2, -1)) -print("math.ult", pcall(math.ult, "x", 2)) -print("math.ult", pcall(math.ult, 1, 2.1)) -___'' - - -if utf8.len then - local unpack = table.unpack or unpack - local function utf8rt(s) - local t = { utf8.codepoint(s, 1, #s) } - local ps, cs = {}, {} - for p,c in utf8.codes(s) do - ps[#ps+1], cs[#cs+1] = p, c - end - print("utf8.codes", unpack(ps)) - print("utf8.codes", unpack(cs)) - print("utf8.codepoint", unpack(t)) - print("utf8.len", utf8.len(s), #t, #s) - print("utf8.char", utf8.char(unpack(t))) - end - utf8rt("äöüßÄÖÜ") - utf8rt("abcdefg") - ___'' - local s = "äöüßÄÖÜ" - print("utf8.offset", utf8.offset(s, 1, 1)) - print("utf8.offset", utf8.offset(s, 2, 1)) - print("utf8.offset", utf8.offset(s, 3, 1)) - print("utf8.offset", pcall(utf8.offset, s, 3, 2)) - print("utf8.offset", utf8.offset(s, 3, 3)) - print("utf8.offset", utf8.offset(s, -1, 7)) - print("utf8.offset", utf8.offset(s, -2, 7)) - print("utf8.offset", utf8.offset(s, -3, 7)) - print("utf8.offset", utf8.offset(s, -1)) - ___'' -else - print("XXX: utf8 module not available") -end - - -if string.pack then - local format = "bBhHlLjJdc3z" - local s = string.pack(format, -128, 255, -32768, 65535, -2147483648, 4294967295, -32768, 65536, 1.25, "abc", "defgh") - print("string.unpack", string.unpack(format, s)) - ___'' -else - print("XXX: string packing not available") -end - - -print("testing Lua API for Lua 5.1 ...") - -___'' -print("debug.getuservalue()", F(debug.getuservalue(false))) -print("debug.setuservalue()", pcall(function() - debug.setuservalue(false, {}) -end)) -print("debug.setmetatable()", F(debug.setmetatable({}, {}))) - - -___'' -do - local t = setmetatable({}, { - __pairs = function() return pairs({ a = "a" }) end, - }) - for k,v in pairs(t) do - print("pairs()", k, v) - end -end - - -___'' -do - local code = "print('hello world')\n" - local badcode = "print('blub\n" - print("load()", pcall(function() load(true) end)) - print("load()", F(load(badcode))) - print("load()", F(load(code))) - print("load()", F(load(code, "[L]"))) - print("load()", F(load(code, "[L]", "b"))) - print("load()", F(load(code, "[L]", "t"))) - print("load()", F(load(code, "[L]", "bt"))) - local f = load(code, "[L]", "bt", {}) - print("load()", pcall(f)) - f = load(code, "[L]", "bt", { print = noprint }) - print("load()", pcall(f)) - local bytecode = string.dump(f) - print("load()", F(load(bytecode))) - print("load()", F(load(bytecode, "[L]"))) - print("load()", F(load(bytecode, "[L]", "b"))) - print("load()", F(load(bytecode, "[L]", "t"))) - print("load()", F(load(bytecode, "[L]", "bt"))) - f = load(bytecode, "[L]", "bt", {}) - print("load()", pcall(f)) - f = load(bytecode, "[L]", "bt", { print = noprint }) - print("load()", pcall(f)) - local function make_loader(code) - local mid = math.floor( #code/2 ) - local array = { code:sub(1, mid), code:sub(mid+1) } - local i = 0 - return function() - i = i + 1 - return array[i] - end - end - print("load()", F(load(make_loader(badcode)))) - print("load()", F(load(make_loader(code)))) - print("load()", F(load(make_loader(code), "[L]"))) - print("load()", F(load(make_loader(code), "[L]", "b"))) - print("load()", F(load(make_loader(code), "[L]", "t"))) - print("load()", F(load(make_loader(code), "[L]", "bt"))) - f = load(make_loader(code), "[L]", "bt", {}) - print("load()", pcall(f)) - f = load(make_loader(code), "[L]", "bt", { print = noprint }) - print("load()", pcall(f)) - print("load()", F(load(make_loader(bytecode)))) - print("load()", F(load(make_loader(bytecode), "[L]"))) - print("load()", F(load(make_loader(bytecode), "[L]", "b"))) - print("load()", F(load(make_loader(bytecode), "[L]", "t"))) - print("load()", F(load(make_loader(bytecode), "[L]", "bt"))) - f = load(make_loader(bytecode), "[L]", "bt", {}) - print("load()", pcall(f)) - f = load(make_loader(bytecode), "[L]", "bt", { print = noprint }) - print("load()", pcall(f)) - writefile("good.lua", code) - writefile("bad.lua", badcode) - writefile("good.luac", bytecode, true) - print("loadfile()", F(loadfile("bad.lua"))) - print("loadfile()", F(loadfile("good.lua"))) - print("loadfile()", F(loadfile("good.lua", "b"))) - print("loadfile()", F(loadfile("good.lua", "t"))) - print("loadfile()", F(loadfile("good.lua", "bt"))) - f = loadfile("good.lua", "bt", {}) - print("loadfile()", pcall(f)) - f = loadfile("good.lua", "bt", { print = noprint }) - print("loadfile()", pcall(f)) - print("loadfile()", F(loadfile("good.luac"))) - print("loadfile()", F(loadfile("good.luac", "b"))) - print("loadfile()", F(loadfile("good.luac", "t"))) - print("loadfile()", F(loadfile("good.luac", "bt"))) - f = loadfile("good.luac", "bt", {}) - print("loadfile()", pcall(f)) - f = loadfile("good.luac", "bt", { print = noprint }) - print("loadfile()", pcall(f)) - os.remove("good.lua") - os.remove("bad.lua") - os.remove("good.luac") -end - - -___'' -do - local function func(throw) - if throw then - error("argh") - else - return 1, 2, 3 - end - end - local function tb(err) return "|"..err.."|" end - print("xpcall()", xpcall(func, debug.traceback, false)) - print("xpcall()", xpcall(func, debug.traceback, true)) - print("xpcall()", xpcall(func, tb, true)) - if mode ~= "module" then - local function func2(cb) - print("xpcall()", xpcall(cb, debug.traceback, "str")) - end - local function func3(cb) - print("pcall()", pcall(cb, "str")) - end - local function cb(arg) - coroutine.yield(2) - return arg - end - local c = coroutine.wrap(func2) - print("xpcall()", c(cb)) - print("xpcall()", c()) - local c = coroutine.wrap(func3) - print("pcall()", c(cb)) - print("pcall()", c()) - end -end - - -___'' -do - local t = setmetatable({ 1 }, { __len = function() return 5 end }) - print("rawlen()", rawlen(t), rawlen("123")) -end - - -___'' -print("os.execute()", os.execute("exit 1")) -io.flush() -print("os.execute()", os.execute("echo 'hello world!'")) -io.flush() -print("os.execute()", os.execute("no_such_file")) - - -___'' -do - local t = table.pack("a", nil, "b", nil) - print("table.(un)pack()", t.n, table.unpack(t, 1, t.n)) -end - - -___'' -do - print("coroutine.running()", F(coroutine.wrap(function() - return coroutine.running() - end)())) - print("coroutine.running()", F(coroutine.running())) - local main_co, co1, co2 = coroutine.running() - -- coroutine.yield - if mode ~= "module" then - print("coroutine.yield()", pcall(function() - coroutine.yield(1, 2, 3) - end)) - end - print("coroutine.yield()", coroutine.wrap(function() - coroutine.yield(1, 2, 3) - end)()) - print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3)) - co1 = coroutine.create(function(a, b, c) - print("coroutine.resume()", a, b, c) - return a, b, c - end) - print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3)) - co1 = coroutine.create(function() - print("coroutine.status()", "[co1] main is", coroutine.status(main_co)) - print("coroutine.status()", "[co1] co2 is", coroutine.status(co2)) - end) - co2 = coroutine.create(function() - print("coroutine.status()", "[co2] main is", coroutine.status(main_co)) - print("coroutine.status()", "[co2] co2 is", coroutine.status(co2)) - coroutine.yield() - coroutine.resume(co1) - end) - print("coroutine.status()", coroutine.status(main_co)) - print("coroutine.status()", coroutine.status(co2)) - coroutine.resume(co2) - print("coroutine.status()", F(coroutine.status(co2))) - coroutine.resume(co2) - print("coroutine.status()", F(coroutine.status(co2))) -end - - -___'' -print("math.log()", math.log(1000)) -print("math.log()", math.log(1000, 10)) - - -___'' -do - local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" - print(prefix, package.searchpath("no.such.module", path)) - print(prefix, package.searchpath("no.such.module", "")) - print(prefix, package.searchpath("compat53", path)) - print(prefix, package.searchpath("no:such:module", path, ":", "|")) -end - - -___'' -if mode ~= "module" then - local function mod_func() return {} end - local function my_searcher(name) - if name == "my.module" then - print("package.searchers", "my.module found") - return mod_func - end - end - local function my_searcher2(name) - if name == "my.module" then - print("package.searchers", "my.module found 2") - return mod_func - end - end - table.insert(package.searchers, my_searcher) - require("my.module") - package.loaded["my.module"] = nil - local new_s = { my_searcher2 } - for i,f in ipairs(package.searchers) do - new_s[i+1] = f - end - package.searchers = new_s - require("my.module") -end - - -___'' -do - print("string.find()", string.find("abc\0abc\0abc", "[^a\0]+")) - print("string.find()", string.find("abc\0abc\0abc", "%w+\0", 5)) - for x in string.gmatch("abc\0def\0ghi", "[^\0]+") do - print("string.gmatch()", x) - end - for x in string.gmatch("abc\0def\0ghi", "%w*\0") do - print("string.gmatch()", #x) - end - print("string.gsub()", string.gsub("abc\0def\0ghi", "[\0]", "X")) - print("string.gsub()", string.gsub("abc\0def\0ghi", "%w*\0", "X")) - print("string.gsub()", string.gsub("abc\0def\0ghi", "%A", "X")) - print("string.match()", string.match("abc\0abc\0abc", "([^\0a]+)")) - print("string.match()", #string.match("abc\0abc\0abc", ".*\0")) - print("string.rep()", string.rep("a", 0)) - print("string.rep()", string.rep("b", 1)) - print("string.rep()", string.rep("c", 4)) - print("string.rep()", string.rep("a", 0, "|")) - print("string.rep()", string.rep("b", 1, "|")) - print("string.rep()", string.rep("c", 4, "|")) - local _tostring = tostring - function tostring(v) - if type(v) == "number" then - return "(".._tostring(v)..")" - else - return _tostring(v) - end - end - print("string.format()", string.format("%q", "\"\\\0000\0010\002\r\n0\t0\"")) - print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {})) - print("string.format()", string.format("%-3f %%%s %%s", 3.1, true)) - print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil)) - print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout)) - print("string.format()", pcall(function() - print("string.format()", string.format("%d %%s", {})) - end)) - tostring = _tostring -end - - -___'' -do - print("io.write()", io.type(io.write("hello world\n"))) - local f = assert(io.tmpfile()) - print("io.tmpfile => file:write()", io.type(f:write("hello world\n"))) - f:close() -end - - -___'' -do - writefile("data.txt", "123 18.8 hello world\ni'm here\n") - io.input("data.txt") - print("io.read()", io.read("*n", "*number", "*l", "*a")) - io.input("data.txt") - print("io.read()", io.read("n", "number", "l", "a")) - io.input(io.stdin) - if not is_puclua51 then - local f = assert(io.open("data.txt", "r")) - print("file:read()", f:read("*n", "*number", "*l", "*a")) - f:close() - f = assert(io.open("data.txt", "r")) - print("file:read()", f:read("n", "number", "l", "a")) - f:close() - os.remove("data.txt") - - local g = assert(io.open("data.txt", "w")) - print("io.open => file:write()", type(g:write("hello"))) - g:close() - end - os.remove("data.txt") -end - - -___'' -do - writefile("data.txt", "123 18.8 hello world\ni'm here\n") - for a,b in io.lines(self, 2, "*l") do - print("io.lines()", a, b) - break - end - for l in io.lines(self) do - print("io.lines()", l) - break - end - for n1,n2,rest in io.lines("data.txt", "*n", "n", "*a") do - print("io.lines()", n1, n2, rest) - end - for l in io.lines("data.txt") do - print("io.lines()", l) - end - print("io.lines()", pcall(function() - for l in io.lines("data.txt", "*x") do print(l) end - end)) - print("io.lines()", pcall(function() - for l in io.lines("no_such_file.txt") do print(l) end - end)) - if mode ~= "module" then - local f = assert(io.open(self, "r")) - print("io.type()", io.type(f)) - for a,b in f:lines(2, "*l") do - print("file:lines()", a, b) - break - end - f:close() - print("io.type()", io.type(f)) - f = assert(io.open("data.txt", "r")) - for n1,n2,rest in f:lines("*n", "n", "*a") do - print("file:lines()", n1, n2, rest) - end - f:close() - f = assert(io.open("data.txt", "r")) - for l in f:lines() do - print("file:lines()", l) - end - f:close() - print("file:lines()", pcall(function() - for l in f:lines() do print(l) end - end)) - print("file:lines()", pcall(function() - local f = assert(io.open("data.txt", "r")) - for l in f:lines("*l", "*x") do print(l) end - f:close() - end)) - end - os.remove("data.txt") - print("io.popen()", pcall(function() - local f = assert(io.popen("echo 'hello' && exit 0", "r")) - print("io.popen()", f:read("*a")) - print("io.popen()", f:close()) - end)) - print("io.popen()", pcall(function() - local f = assert(io.popen("echo 'hello' && exit 5", "r")) - print("io.type()", io.type(f)) - print("io.popen()", f:read("*a")) - print("io.popen()", f:close()) - print("io.type()", io.type(f)) - end)) -end -___'' - - -print("testing C API ...") -local mod = require("testmod") -___'' -print("isinteger", mod.isinteger(1)) -print("isinteger", mod.isinteger(0)) -print("isinteger", mod.isinteger(1234567)) -print("isinteger", mod.isinteger(12.3)) -print("isinteger", mod.isinteger(math.huge)) -print("isinteger", mod.isinteger(math.sqrt(-1))) - -___'' -print("rotate", mod.rotate(1, 1, 2, 3, 4, 5, 6)) -print("rotate", mod.rotate(-1, 1, 2, 3, 4, 5, 6)) -print("rotate", mod.rotate(4, 1, 2, 3, 4, 5, 6)) -print("rotate", mod.rotate(-4, 1, 2, 3, 4, 5, 6)) - -___'' -print("strtonum", mod.strtonum("+123")) -print("strtonum", mod.strtonum(" 123 ")) -print("strtonum", mod.strtonum("-1.23")) -print("strtonum", mod.strtonum(" 123 abc")) -print("strtonum", mod.strtonum("jkl")) - -___'' -local a, b, c = mod.requiref() -print("requiref", type(a), type(b), type(c), - a.boolean, b.boolean, c.boolean, - type(requiref1), type(requiref2), type(requiref3)) - -___'' -local c = coroutine.wrap(function() - mod.extraspace("uvw") - print("getextraspace", mod.extraspace()) - coroutine.yield() - print("getextraspace", mod.extraspace()) - coroutine.yield() - print("getextraspace", mod.extraspace()) -end) -c() -mod.extraspace("abc") -print("getextraspace", mod.extraspace()) -c() -local d = coroutine.wrap(function() - print("getextraspace", mod.extraspace()) - mod.extraspace("xyz") - print("getextraspace", mod.extraspace()) - coroutine.yield() - print("getextraspace", mod.extraspace()) - coroutine.yield() - print("getextraspace", mod.extraspace()) -end) -d() -print("getextraspace", mod.extraspace()) -mod.extraspace("123") -c() -d() - -___'' -local proxy, backend = {}, {} -setmetatable(proxy, { __index = backend, __newindex = backend }) -print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) -print("geti/seti", mod.getseti(proxy, 1)) -print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) -print("geti/seti", mod.getseti(proxy, 1)) -print("geti/seti", rawget(proxy, 1), rawget(backend, 1)) - --- tests for Lua 5.1 -___'' -print("tonumber", mod.tonumber(12)) -print("tonumber", mod.tonumber("12")) -print("tonumber", mod.tonumber("0")) -print("tonumber", mod.tonumber(false)) -print("tonumber", mod.tonumber("error")) - -___'' -print("tointeger", mod.tointeger(12)) -print("tointeger", mod.tointeger(12)) -print("tointeger", mod.tointeger(12.1)) -print("tointeger", mod.tointeger(12.9)) -print("tointeger", mod.tointeger(-12.1)) -print("tointeger", mod.tointeger(-12.9)) -print("tointeger", mod.tointeger("12")) -print("tointeger", mod.tointeger("0")) -print("tointeger", mod.tointeger(math.pi)) -print("tointeger", mod.tointeger(false)) -print("tointeger", mod.tointeger("error")) - -___'' -print("len", mod.len("123")) -print("len", mod.len({ 1, 2, 3})) -print("len", pcall(mod.len, true)) -local ud, meta = mod.newproxy() -meta.__len = function() return 5 end -print("len", mod.len(ud)) -meta.__len = function() return true end -print("len", pcall(mod.len, ud)) - -___'' -print("copy", mod.copy(true, "string", {}, 1)) - -___'' -print("rawgetp/rawsetp", mod.rawxetp()) -print("rawgetp/rawsetp", mod.rawxetp("I'm back")) - -___'' -print("globals", F(mod.globals()), mod.globals() == _G) - -___'' -local t = {} -print("getsubtable", F(mod.subtable(t))) -local x, msg = mod.subtable(t) -print("getsubtable", F(x, msg, x == t.xxx)) - -___'' -print("udata", F(mod.udata())) -print("udata", mod.udata("nosuchtype")) - -___'' -print("uservalue", F(mod.uservalue())) - -___'' -print("upvalues", mod.getupvalues()) - -___'' -print("absindex", mod.absindex("hi", true)) - -___'' -print("arith", mod.arith(2, 1)) -print("arith", mod.arith(3, 5)) - -___'' -print("compare", mod.compare(1, 1)) -print("compare", mod.compare(2, 1)) -print("compare", mod.compare(1, 2)) - -___'' -print("tolstring", mod.tolstring("string")) -local t = setmetatable({}, { - __tostring = function(v) return "mytable" end -}) -print("tolstring", mod.tolstring(t)) -local t = setmetatable({}, { - __tostring = function(v) return nil end -}) -print("tolstring", pcall(mod.tolstring, t)) -local ud, meta = mod.newproxy() -meta.__name = "XXX" -print("tolstring", mod.tolstring(ud):gsub(":.*$", ": yyy")) - -___'' -print("pushstring", mod.pushstring()) - -___'' -print("Buffer", mod.buffer()) - -___'' -print("execresult", mod.exec("exit 0")) -print("execresult", mod.exec("exit 1")) -print("execresult", mod.exec("exit 25")) - -___'' -do - local bin = string.dump(function() end) - local modes = { "t", "b", "bt" } - local codes = { - "", "return true", bin, "invalidsource", "\27invalidbinary" - } - for _,m in ipairs(modes) do - for i,c in ipairs(codes) do - print("loadbufferx", m, i, F(mod.loadstring(c, m))) - end - end - - ___'' - local bom = "\239\187\191" - local shebang = "#!/usr/bin/env lua\n" - codes[#codes+1] = bom .. shebang .. "return true" - codes[#codes+1] = bom .. shebang .. bin - codes[#codes+1] = bom .. shebang .. "invalidsource" - codes[#codes+1] = bom .. shebang .. "\027invalidbinary" - for _,m in ipairs(modes) do - for i,c in ipairs(codes) do - print("loadfilex", m, i, F(mod.loadfile(c, m))) - end - end -end -___'' - diff --git a/lib/compat53/tests/testmod.c b/lib/compat53/tests/testmod.c deleted file mode 100644 index 0d73ed4..0000000 --- a/lib/compat53/tests/testmod.c +++ /dev/null @@ -1,370 +0,0 @@ -#include -#include -#include -#include "compat-5.3.h" - - -static int test_isinteger (lua_State *L) { - lua_pushboolean(L, lua_isinteger(L, 1)); - return 1; -} - - -static int test_rotate (lua_State *L) { - int r = (int)luaL_checkinteger(L, 1); - int n = lua_gettop(L)-1; - luaL_argcheck(L, (r < 0 ? -r : r) <= n, 1, "not enough arguments"); - lua_rotate(L, 2, r); - return n; -} - - -static int test_str2num (lua_State *L) { - const char *s = luaL_checkstring(L, 1); - size_t len = lua_stringtonumber(L, s); - if (len == 0) - lua_pushnumber(L, 0); - lua_pushinteger(L, (lua_Integer)len); - return 2; -} - - -static int my_mod (lua_State *L ) { - lua_newtable(L); - lua_pushboolean(L, 1); - lua_setfield(L, -2, "boolean"); - return 1; -} - -static int test_requiref (lua_State *L) { - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_newtable(L); - lua_pushboolean(L, 0); - lua_setfield(L, -2, "boolean"); - lua_setfield(L, -2, "requiref3"); - lua_pop(L, 1); - luaL_requiref(L, "requiref1", my_mod, 0); - luaL_requiref(L, "requiref2", my_mod, 1); - luaL_requiref(L, "requiref3", my_mod, 1); - return 3; -} - -static int test_getseti (lua_State *L) { - lua_Integer k = luaL_checkinteger(L, 2); - lua_Integer n = 0; - if (lua_geti(L, 1, k) == LUA_TNUMBER) { - n = lua_tointeger(L, -1); - } else { - lua_pop(L, 1); - lua_pushinteger(L, n); - } - lua_pushinteger(L, n+1); - lua_seti(L, 1, k); - return 1; -} - - -#ifndef LUA_EXTRASPACE -#define LUA_EXTRASPACE (sizeof(void*)) -#endif - -static int test_getextraspace (lua_State *L) { - size_t len = 0; - char const* s = luaL_optlstring(L, 1, NULL, &len); - char* p = (char*)lua_getextraspace(L); - lua_pushstring(L, p); - if (s) - memcpy(p, s, len > LUA_EXTRASPACE-1 ? LUA_EXTRASPACE-1 : len+1); - return 1; -} - - -/* additional tests for Lua5.1 */ -#define NUP 3 - -static int test_newproxy (lua_State *L) { - lua_settop(L, 0); - lua_newuserdata(L, 0); - lua_newtable(L); - lua_pushvalue(L, -1); - lua_pushboolean(L, 1); - lua_setfield(L, -2, "__gc"); - lua_setmetatable(L, -3); - return 2; -} - -static int test_absindex (lua_State *L) { - int i = 1; - for (i = 1; i <= NUP; ++i) - lua_pushvalue(L, lua_absindex(L, lua_upvalueindex(i))); - lua_pushvalue(L, lua_absindex(L, LUA_REGISTRYINDEX)); - lua_pushstring(L, lua_typename(L, lua_type(L, lua_absindex(L, -1)))); - lua_replace(L, lua_absindex(L, -2)); - lua_pushvalue(L, lua_absindex(L, -2)); - lua_pushvalue(L, lua_absindex(L, -4)); - lua_pushvalue(L, lua_absindex(L, -6)); - i += 3; - lua_pushvalue(L, lua_absindex(L, 1)); - lua_pushvalue(L, lua_absindex(L, 2)); - lua_pushvalue(L, lua_absindex(L, 3)); - i += 3; - return i; -} - -static int test_arith (lua_State *L) { - lua_settop(L, 2); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_arith(L, LUA_OPADD); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_arith(L, LUA_OPSUB); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_arith(L, LUA_OPMUL); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_arith(L, LUA_OPDIV); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_arith(L, LUA_OPMOD); - lua_pushvalue(L, 1); - lua_pushvalue(L, 2); - lua_arith(L, LUA_OPPOW); - lua_pushvalue(L, 1); - lua_arith(L, LUA_OPUNM); - return lua_gettop(L)-2; -} - -static int test_compare (lua_State *L) { - luaL_checknumber(L, 1); - luaL_checknumber(L, 2); - lua_settop(L, 2); - lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPEQ)); - lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLT)); - lua_pushboolean(L, lua_compare(L, 1, 2, LUA_OPLE)); - return 3; -} - -static int test_globals (lua_State *L) { - lua_pushglobaltable(L); - return 1; -} - -static int test_tonumber (lua_State *L) { - int isnum = 0; - lua_Number n = lua_tonumberx(L, 1, &isnum); - if (!isnum) - lua_pushnil(L); - else - lua_pushnumber(L, n); - return 1; -} - -static int test_tointeger (lua_State *L) { - int isnum = 0; - lua_Integer n = lua_tointegerx(L, 1, &isnum); - if (!isnum) - lua_pushnil(L); - else - lua_pushinteger(L, n); - lua_pushinteger(L, lua_tointeger(L, 1)); - return 2; -} - -static int test_len (lua_State *L) { - luaL_checkany(L, 1); - lua_len(L, 1); - lua_pushinteger(L, luaL_len(L, 1)); - return 2; -} - -static int test_copy (lua_State *L) { - int args = lua_gettop(L); - if (args >= 2) { - int i = 0; - for (i = args-1; i > 0; --i) - lua_copy(L, args, i); - } - return args; -} - -/* need an address */ -static char const dummy = 0; - -static int test_rawxetp (lua_State *L) { - if (lua_gettop(L) > 0) - lua_pushvalue(L, 1); - else - lua_pushliteral(L, "hello again"); - lua_rawsetp(L, LUA_REGISTRYINDEX, &dummy); - lua_settop(L, 0); - lua_rawgetp(L, LUA_REGISTRYINDEX, &dummy); - return 1; -} - -static int test_udata (lua_State *L) { - const char *tname = luaL_optstring(L, 1, "utype1"); - void *u1 = lua_newuserdata(L, 1); - int u1pos = lua_gettop(L); - void *u2 = lua_newuserdata(L, 1); - int u2pos = lua_gettop(L); - luaL_newmetatable(L, "utype1"); - luaL_newmetatable(L, "utype2"); - lua_pop(L, 2); - luaL_setmetatable(L, "utype2"); - lua_pushvalue(L, u1pos); - luaL_setmetatable(L, "utype1"); - lua_pop(L, 1); - (void)u1; - (void)u2; - lua_pushlightuserdata(L, luaL_testudata(L, u1pos, tname)); - lua_pushlightuserdata(L, luaL_testudata(L, u2pos, tname)); - luaL_getmetatable(L, "utype1"); - lua_getfield(L, -1, "__name"); - lua_replace(L, -2); - return 3; -} - -static int test_subtable (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); - if (luaL_getsubtable(L, 1, "xxx")) { - lua_pushliteral(L, "oldtable"); - } else { - lua_pushliteral(L, "newtable"); - } - return 2; -} - -static int test_uservalue (lua_State *L) { - void *udata = lua_newuserdata(L, 1); - int ui = lua_gettop(L); - lua_newtable(L); - lua_setuservalue(L, ui); - lua_pushinteger(L, lua_getuservalue(L, ui)); - (void)udata; - return 2; -} - -static int test_upvalues (lua_State *L) { - int i = 1; - for (i = 1; i <= NUP; ++i) - lua_pushvalue(L, lua_upvalueindex(i)); - return NUP; -} - -static int test_tolstring (lua_State *L) { - size_t len = 0; - luaL_tolstring(L, 1, &len); - lua_pushinteger(L, (int)len); - return 2; -} - -static int test_pushstring (lua_State *L) { - lua_pushstring(L, lua_pushliteral(L, "abc")); - lua_pushstring(L, lua_pushlstring(L, "abc", 2)); - lua_pushstring(L, lua_pushlstring(L, NULL, 0)); - lua_pushstring(L, lua_pushstring(L, "abc")); - lua_pushboolean(L, NULL == lua_pushstring(L, NULL)); - return 10; -} - -static int test_buffer (lua_State *L) { - luaL_Buffer b; - char *p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE+1); - p[0] = 'a'; - p[1] = 'b'; - luaL_addsize(&b, 2); - luaL_addstring(&b, "c"); - lua_pushliteral(L, "d"); - luaL_addvalue(&b); - luaL_addchar(&b, 'e'); - luaL_pushresult(&b); - return 1; -} - -static int test_exec (lua_State *L) { - const char *cmd = luaL_checkstring(L, 1); - errno = 0; - return luaL_execresult(L, system(cmd)); -} - -static int test_loadstring (lua_State *L) { - size_t len = 0; - char const* s = luaL_checklstring(L, 1, &len); - char const* mode = luaL_optstring(L, 2, "bt"); - lua_pushinteger(L, luaL_loadbufferx(L, s, len, s, mode)); - return 2; -} - -static int test_loadfile (lua_State *L) { - char filename[L_tmpnam+1] = { 0 }; - size_t len = 0; - char const* s = luaL_checklstring(L, 1, &len); - char const* mode = luaL_optstring(L, 2, "bt"); - if (tmpnam(filename)) { - FILE* f = fopen(filename, "wb"); - if (f) { - fwrite(s, 1, len, f); - fclose(f); - lua_pushinteger(L, luaL_loadfilex(L, filename, mode)); - remove(filename); - return 2; - } else - remove(filename); - } - return 0; -} - - -static const luaL_Reg funcs[] = { - { "isinteger", test_isinteger }, - { "rotate", test_rotate }, - { "strtonum", test_str2num }, - { "requiref", test_requiref }, - { "getseti", test_getseti }, - { "extraspace", test_getextraspace }, - { "newproxy", test_newproxy }, - { "arith", test_arith }, - { "compare", test_compare }, - { "tonumber", test_tonumber }, - { "tointeger", test_tointeger }, - { "len", test_len }, - { "copy", test_copy }, - { "rawxetp", test_rawxetp }, - { "subtable", test_subtable }, - { "udata", test_udata }, - { "uservalue", test_uservalue }, - { "globals", test_globals }, - { "tolstring", test_tolstring }, - { "pushstring", test_pushstring }, - { "buffer", test_buffer }, - { "exec", test_exec }, - { "loadstring", test_loadstring }, - { "loadfile", test_loadfile }, - { NULL, NULL } -}; - -static const luaL_Reg more_funcs[] = { - { "getupvalues", test_upvalues }, - { "absindex", test_absindex }, - { NULL, NULL } -}; - - -#ifdef __cplusplus -extern "C" { -#endif -int luaopen_testmod (lua_State *L) { - int i = 1; - luaL_newlib(L, funcs); - for (i = 1; i <= NUP; ++i) - lua_pushnumber(L, i); - luaL_setfuncs(L, more_funcs, NUP); - return 1; -} -#ifdef __cplusplus -} -#endif - diff --git a/lib/hashmap/hashmap.c b/lib/hashmap/hashmap.c deleted file mode 100644 index cfc112c..0000000 --- a/lib/hashmap/hashmap.c +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright (c) 2024, Lance Borden -All rights reserved. - -This software is licensed under the BSD 3-Clause License. -You may obtain a copy of the license at: -https://opensource.org/licenses/BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted under the conditions stated in the BSD 3-Clause -License. - -THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -*/ - -#include "hashmap.h" -#include -#include -#include - -hashmap_t *hm_new_hashmap() { - hashmap_t *this = malloc(sizeof(hashmap_t)); - this->cap = 8; - this->len = 0; - // null all pointers in list - this->list = calloc((this->cap), sizeof(map_pair_t *)); - return this; -} - -unsigned int hm_hashcode(hashmap_t *this, char *key) { - unsigned int code; - for (code = 0; *key != '\0'; key++) { - code = *key + 31 * code; - } - - return code % (this->cap); -} - -char *hm_get(hashmap_t *this, char *key) { - map_pair_t *current; - for (current = this->list[hm_hashcode(this, key)]; current; - current = current->next) { - if (strcmp(current->key, key) == 0) { - return current->val; - } - } - // the key is not found - return NULL; -} - -void hm_set(hashmap_t *this, char *key, char *val) { - unsigned int idx = hm_hashcode(this, key); - map_pair_t *current; - for (current = this->list[idx]; current; current = current->next) { - if (strcmp(current->key, key) == 0) { - current->val = val; - return; - } - } - - map_pair_t *p = malloc(sizeof(map_pair_t)); - p->key = key; - p->val = val; - p->next = this->list[idx]; - this->list[idx] = p; - this->len++; -} diff --git a/lib/hashmap/hashmap.h b/lib/hashmap/hashmap.h deleted file mode 100644 index d5775c5..0000000 --- a/lib/hashmap/hashmap.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright (c) 2024, Lance Borden -All rights reserved. - -This software is licensed under the BSD 3-Clause License. -You may obtain a copy of the license at: -https://opensource.org/licenses/BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted under the conditions stated in the BSD 3-Clause -License. - -THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -*/ - -#ifndef HASHMAP_H -#define HASHMAP_H - -typedef struct pair { - char *key; - char *val; - struct pair *next; -} map_pair_t; - -typedef struct { - map_pair_t **list; - unsigned int cap; - unsigned int len; -} hashmap_t; - -hashmap_t *hm_new_hashmap(); -unsigned int hm_hashcode(hashmap_t *this, char *key); -char *hm_get(hashmap_t *this, char *key); -void hm_set(hashmap_t *this, char *key, char *val); - -#endif // HASHMAP_H From da888fa1f401585c6d6bf41d5d46abb098b8cd48 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 02:22:29 -0500 Subject: [PATCH 25/33] Ignore Jenkins home directory --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6025dec..f5e685f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ obj .cache .vscode/ .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.dbjenkins_home/ From e5ddafc56624ee7851e3bd2402ea6039f3eacc6c Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 02:27:52 -0500 Subject: [PATCH 26/33] Re-added the lib/ directory: it is now empty --- lib/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/.gitkeep diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 0000000..e69de29 From 12a94cdb3c9f51d01513108cd8ca4edeb806d989 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 03:06:05 -0500 Subject: [PATCH 27/33] CRITICAL FOR TESTING: This copies the entire Jenkins workspace (including the populated lib/ directory from the submodules) into the running container, ensuring all the required source files are available for the build process. --- Dockerfile | 1 + Jenkinsfile | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index ac570c7..1b6ef69 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,7 @@ RUN apt-get update && apt-get install -y \ build-essential \ wget \ unzip \ + git \ lua5.4 \ liblua5.4-dev \ && rm -rf /var/lib/apt/lists/* diff --git a/Jenkinsfile b/Jenkinsfile index 51a46d8..6acbacd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,3 @@ -// Jenkinsfile - pipeline { agent any @@ -8,7 +6,6 @@ pipeline { steps { script { echo 'Initializing Git submodules...' - // Manually initialize and update the git submodules sh 'git submodule update --init --recursive' echo 'Building the Lush application Docker image...' @@ -19,7 +16,6 @@ pipeline { stage('Compile & Test Project') { steps { script { - // Define a unique name for our temporary build container def containerName = "lush-build-${BUILD_NUMBER}" try { @@ -65,21 +61,22 @@ EOF ''' echo 'Creating and starting the build container...' - // Create the container and keep it running in the background sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" + echo 'Copying complete workspace (with populated submodules) into container...' + // This ensures the populated lib/ directory gets into the container + sh "docker cp . ${containerName}:/app/" + echo 'Copying test script into the container...' sh "docker cp test_52.lua ${containerName}:/app/test_52.lua" echo 'Compiling and running tests inside the container...' - sh "docker exec ${containerName} /bin/bash -c 'premake5 gmake2 && make && ./bin/Debug/lush/lush test_52.lua'" + sh "docker exec ${containerName} /bin/bash -c 'cd /app && premake5 gmake2 && make && ./bin/Debug/lush/lush test_52.lua'" echo 'Extracting compiled binary from the container...' - // This is good practice for storing build artifacts sh "docker cp ${containerName}:/app/bin ./" } finally { - // This block ensures the build container is always stopped and removed echo "Cleaning up build container: ${containerName}" sh "docker stop ${containerName} >/dev/null 2>&1 || true" sh "docker rm ${containerName} >/dev/null 2>&1 || true" @@ -94,4 +91,4 @@ EOF sh 'docker rmi lush-app:latest || true' } } -} +} \ No newline at end of file From 8d9b53f254f8e925b988adbd63d882b13453de99 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 03:10:16 -0500 Subject: [PATCH 28/33] CRITICAL ISSUE: Deleting lib/ files has introduced the issue of actually automating the module initialization via jenkins: DEBUG VERSION: Jenkinsfile --- Jenkinsfile | 63 +++++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6acbacd..f3ffb15 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,6 +8,16 @@ pipeline { echo 'Initializing Git submodules...' sh 'git submodule update --init --recursive' + // Debug: Check if submodules are populated ON JENKINS AGENT + echo 'Checking submodule status on Jenkins agent...' + sh 'git submodule status' + + echo 'Checking lib directory contents on Jenkins agent...' + sh 'ls -la lib/ || echo "lib directory not found"' + sh 'find lib/ -name "*.c" -o -name "*.h" | head -10 || echo "No C files found in lib"' + sh 'ls -la lib/compat53/ || echo "compat53 not found"' + sh 'ls -la lib/compat53/c-api/ || echo "c-api directory not found"' + echo 'Building the Lush application Docker image...' sh 'docker build -t lush-app:latest .' } @@ -22,41 +32,9 @@ pipeline { echo 'Creating test script on Jenkins agent...' sh ''' cat <<'EOF' > test_52.lua --- Lua 5.2-specific features test print("--- Running Lua 5.2 Compatibility Test ---") - --- Test 1: Basic functionality print("Basic print test: Hello from Lush!") - --- Test 2: Bitwise operations using the preloaded bit32 library --- The lush host preloads compat modules, so we don't need to 'require' it. -local a, b = 5, 3 -print("Bitwise AND of", a, "and", b, "=", bit32.band(a, b)) -print("Bitwise OR of", a, "and", b, "=", bit32.bor(a, b)) - --- Test 3: load() function (replaces loadstring in Lua 5.2) -local f, err = load("return 10 + 20") -if f then - print("Loaded function result:", f()) -else - print("Failed to load function:", err) -end - --- Test 4: table.unpack -local t = {1, 2, 3} -print("Unpacked values:", table.unpack(t)) - --- Test 5: String operations -local str = "Hello, World!" -print("String length:", #str) -print("Substring:", string.sub(str, 1, 5)) - --- Test 6: Math operations -print("Math operations:") -print(" sqrt(16) =", math.sqrt(16)) -print(" max(10, 20, 5) =", math.max(10, 20, 5)) - -print("--- Test Complete: All basic features working ---") +print("--- Test Complete ---") EOF ''' @@ -64,17 +42,26 @@ EOF sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" echo 'Copying complete workspace (with populated submodules) into container...' - // This ensures the populated lib/ directory gets into the container sh "docker cp . ${containerName}:/app/" + // Debug: Check what's actually in the container AFTER copying + echo 'Debugging: Checking container contents AFTER workspace copy...' + sh "docker exec ${containerName} ls -la /app/lib/ || echo 'lib directory empty or missing in container'" + sh "docker exec ${containerName} ls -la /app/lib/compat53/ || echo 'compat53 not found in container'" + sh "docker exec ${containerName} ls -la /app/lib/compat53/c-api/ || echo 'c-api not found in container'" + sh "docker exec ${containerName} find /app/lib/ -name '*.c' | head -5 || echo 'No C files found in container lib'" + echo 'Copying test script into the container...' sh "docker cp test_52.lua ${containerName}:/app/test_52.lua" - echo 'Compiling and running tests inside the container...' - sh "docker exec ${containerName} /bin/bash -c 'cd /app && premake5 gmake2 && make && ./bin/Debug/lush/lush test_52.lua'" + echo 'Running premake5 to see what it generates...' + sh "docker exec ${containerName} /bin/bash -c 'cd /app && premake5 gmake2'" + + echo 'Checking generated Makefile...' + sh "docker exec ${containerName} /bin/bash -c 'cd /app && head -50 lush.make | grep -i compat || echo \"No compat references found\"'" - echo 'Extracting compiled binary from the container...' - sh "docker cp ${containerName}:/app/bin ./" + echo 'Attempting to compile...' + sh "docker exec ${containerName} /bin/bash -c 'cd /app && make'" } finally { echo "Cleaning up build container: ${containerName}" From 656a2e4ab90996ba2b77d81ad62379d276200709 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 03:18:05 -0500 Subject: [PATCH 29/33] Attempt to patch CI pipeline: Dockerfile will now be selfcontained, and thus, will init .gitmodules: ln:10 removed from original Jenkinsfile --- Dockerfile | 3 +++ Jenkinsfile | 72 +++++++++++++++++++++++++++++------------------------ 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1b6ef69..2577c04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,6 +24,9 @@ WORKDIR /app COPY . . +# Initialize git submodules inside the container +RUN git submodule update --init --recursive + # Creates the .lush config directory in the root user home directory as install.sh expects. RUN mkdir -p /root/.lush && cp -r ./.lush/* /root/.lush/ diff --git a/Jenkinsfile b/Jenkinsfile index f3ffb15..6512f35 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,5 @@ +// In Jenkinsfile + pipeline { agent any @@ -5,19 +7,7 @@ pipeline { stage('Build Application Image') { steps { script { - echo 'Initializing Git submodules...' - sh 'git submodule update --init --recursive' - - // Debug: Check if submodules are populated ON JENKINS AGENT - echo 'Checking submodule status on Jenkins agent...' - sh 'git submodule status' - - echo 'Checking lib directory contents on Jenkins agent...' - sh 'ls -la lib/ || echo "lib directory not found"' - sh 'find lib/ -name "*.c" -o -name "*.h" | head -10 || echo "No C files found in lib"' - sh 'ls -la lib/compat53/ || echo "compat53 not found"' - sh 'ls -la lib/compat53/c-api/ || echo "c-api directory not found"' - + // NOTE: Dockerfile handles submodule initialization echo 'Building the Lush application Docker image...' sh 'docker build -t lush-app:latest .' } @@ -32,36 +22,54 @@ pipeline { echo 'Creating test script on Jenkins agent...' sh ''' cat <<'EOF' > test_52.lua +-- Lua 5.2-specific features test print("--- Running Lua 5.2 Compatibility Test ---") + +-- Test 1: Basic functionality print("Basic print test: Hello from Lush!") -print("--- Test Complete ---") + +-- Test 2: Bitwise operations using the preloaded bit32 library +local a, b = 5, 3 +print("Bitwise AND of", a, "and", b, "=", bit32.band(a, b)) +print("Bitwise OR of", a, "and", b, "=", bit32.bor(a, b)) + +-- Test 3: load() function (replaces loadstring in Lua 5.2) +local f, err = load("return 10 + 20") +if f then + print("Loaded function result:", f()) +else + print("Failed to load function:", err) +end + +-- Test 4: table.unpack +local t = {1, 2, 3} +print("Unpacked values:", table.unpack(t)) + +-- Test 5: String operations +local str = "Hello, World!" +print("String length:", #str) +print("Substring:", string.sub(str, 1, 5)) + +-- Test 6: Math operations +print("Math operations:") +print(" sqrt(16) =", math.sqrt(16)) +print(" max(10, 20, 5) =", math.max(10, 20, 5)) + +print("--- Test Complete: All basic features working ---") EOF ''' echo 'Creating and starting the build container...' sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" - echo 'Copying complete workspace (with populated submodules) into container...' - sh "docker cp . ${containerName}:/app/" - - // Debug: Check what's actually in the container AFTER copying - echo 'Debugging: Checking container contents AFTER workspace copy...' - sh "docker exec ${containerName} ls -la /app/lib/ || echo 'lib directory empty or missing in container'" - sh "docker exec ${containerName} ls -la /app/lib/compat53/ || echo 'compat53 not found in container'" - sh "docker exec ${containerName} ls -la /app/lib/compat53/c-api/ || echo 'c-api not found in container'" - sh "docker exec ${containerName} find /app/lib/ -name '*.c' | head -5 || echo 'No C files found in container lib'" - echo 'Copying test script into the container...' sh "docker cp test_52.lua ${containerName}:/app/test_52.lua" - echo 'Running premake5 to see what it generates...' - sh "docker exec ${containerName} /bin/bash -c 'cd /app && premake5 gmake2'" - - echo 'Checking generated Makefile...' - sh "docker exec ${containerName} /bin/bash -c 'cd /app && head -50 lush.make | grep -i compat || echo \"No compat references found\"'" + echo 'Compiling and running tests inside the container...' + sh "docker exec ${containerName} /bin/bash -c 'premake5 gmake2 && make && ./bin/Debug/lush/lush test_52.lua'" - echo 'Attempting to compile...' - sh "docker exec ${containerName} /bin/bash -c 'cd /app && make'" + echo 'Extracting compiled binary from the container...' + sh "docker cp ${containerName}:/app/bin ./" } finally { echo "Cleaning up build container: ${containerName}" @@ -78,4 +86,4 @@ EOF sh 'docker rmi lush-app:latest || true' } } -} \ No newline at end of file +} From 3f4e2c5ada1050555775661f850e3a20d2933046 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 03:33:49 -0500 Subject: [PATCH 30/33] make was improperly being called inside the container on a project that is missing its dependencies in the lib/ directory, leading to a 'No rule to make target' error: updated Dockerfile to remove the submodule command at: ln:29: and: Jenkinsfile will use the git submodule sync command. This will ensure the agent's repository is correctly configured before fetching the submodule code: at: ln:9-17 --- Dockerfile | 6 ++---- Jenkinsfile | 8 +++++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2577c04..e6dc2a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,5 @@ +# In Dockerfile + # Use a base image with build tools FROM ubuntu:22.04 @@ -24,11 +26,7 @@ WORKDIR /app COPY . . -# Initialize git submodules inside the container -RUN git submodule update --init --recursive - # Creates the .lush config directory in the root user home directory as install.sh expects. RUN mkdir -p /root/.lush && cp -r ./.lush/* /root/.lush/ CMD ["premake5", "gmake2"] - diff --git a/Jenkinsfile b/Jenkinsfile index 6512f35..dccf6b9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,12 @@ pipeline { stage('Build Application Image') { steps { script { - // NOTE: Dockerfile handles submodule initialization + echo 'Initializing Git submodules...' + // First, sync the submodule URLs from .gitmodules to .git/config + sh 'git submodule sync --recursive' + // Then, initialize and update the submodules + sh 'git submodule update --init --recursive' + echo 'Building the Lush application Docker image...' sh 'docker build -t lush-app:latest .' } @@ -62,6 +67,7 @@ EOF echo 'Creating and starting the build container...' sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" + // Since the Docker image now has the full source, we only need to copy the test script. echo 'Copying test script into the container...' sh "docker cp test_52.lua ${containerName}:/app/test_52.lua" From e152028f6ea5dfe1bcdea51bd2efbc6fdebb8b87 Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 03:52:40 -0500 Subject: [PATCH 31/33] Remove CI/CD pipeline files - moving to separate PR --- Dockerfile | 32 ---------------- Dockerfile.jenkins | 40 ------------------- Jenkinsfile | 95 ---------------------------------------------- docker-compose.yml | 18 --------- 4 files changed, 185 deletions(-) delete mode 100644 Dockerfile delete mode 100644 Dockerfile.jenkins delete mode 100644 Jenkinsfile delete mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e6dc2a7..0000000 --- a/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -# In Dockerfile - -# Use a base image with build tools -FROM ubuntu:22.04 - -# Avoid interactive prompts during package installation -ENV DEBIAN_FRONTEND=noninteractive - -# Install necessary build tools for your C project -RUN apt-get update && apt-get install -y \ - build-essential \ - wget \ - unzip \ - git \ - lua5.4 \ - liblua5.4-dev \ - && rm -rf /var/lib/apt/lists/* - -# Download and install Premake5 -RUN wget https://github.com/premake/premake-core/releases/download/v5.0.0-beta2/premake-5.0.0-beta2-linux.tar.gz -O premake.tar.gz && \ - tar -xvf premake.tar.gz && \ - mv premake5 /usr/local/bin/ - -# Set the working directory inside the container -WORKDIR /app - -COPY . . - -# Creates the .lush config directory in the root user home directory as install.sh expects. -RUN mkdir -p /root/.lush && cp -r ./.lush/* /root/.lush/ - -CMD ["premake5", "gmake2"] diff --git a/Dockerfile.jenkins b/Dockerfile.jenkins deleted file mode 100644 index 23a95f1..0000000 --- a/Dockerfile.jenkins +++ /dev/null @@ -1,40 +0,0 @@ -# Dockerfile.jenkins -# Use the official Jenkins image as a base -FROM jenkins/jenkins:lts-jdk17 - -# Pass Host User, Group, and Docker Group IDs as build arguments -ARG UID -ARG GID -ARG DOCKER_GID - -# Switch to root user to install dependencies and manage users -USER root - -# Install Docker CLI so Jenkins can interact with the host's Docker daemon -RUN apt-get update && apt-get install -y lsb-release sudo -RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \ - https://download.docker.com/linux/debian/gpg -RUN echo "deb [arch=$(dpkg --print-architecture) \ - signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \ - https://download.docker.com/linux/debian \ - $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list -RUN apt-get update && apt-get install -y docker-ce-cli - -# Create a docker group with the host's GID to match permissions -# and add the jenkins user to it. -RUN if [ -n "$DOCKER_GID" ]; then \ - groupadd -g $DOCKER_GID docker && \ - usermod -aG docker jenkins; \ - fi - -# Change the jenkins user and group to match the host. -# This should ensure file permissions for the jenkins_home volume are correct. -RUN if [ -n "$GID" ] && [ "$(getent group jenkins | cut -d: -f3)" != "$GID" ]; then \ - groupmod -g $GID jenkins; \ - fi -RUN if [ -n "$UID" ] && [ "$(id -u jenkins)" != "$UID" ]; then \ - usermod -u $UID jenkins; \ - fi - -# Switch to the newly configured jenkins user -USER jenkins diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index dccf6b9..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,95 +0,0 @@ -// In Jenkinsfile - -pipeline { - agent any - - stages { - stage('Build Application Image') { - steps { - script { - echo 'Initializing Git submodules...' - // First, sync the submodule URLs from .gitmodules to .git/config - sh 'git submodule sync --recursive' - // Then, initialize and update the submodules - sh 'git submodule update --init --recursive' - - echo 'Building the Lush application Docker image...' - sh 'docker build -t lush-app:latest .' - } - } - } - stage('Compile & Test Project') { - steps { - script { - def containerName = "lush-build-${BUILD_NUMBER}" - - try { - echo 'Creating test script on Jenkins agent...' - sh ''' - cat <<'EOF' > test_52.lua --- Lua 5.2-specific features test -print("--- Running Lua 5.2 Compatibility Test ---") - --- Test 1: Basic functionality -print("Basic print test: Hello from Lush!") - --- Test 2: Bitwise operations using the preloaded bit32 library -local a, b = 5, 3 -print("Bitwise AND of", a, "and", b, "=", bit32.band(a, b)) -print("Bitwise OR of", a, "and", b, "=", bit32.bor(a, b)) - --- Test 3: load() function (replaces loadstring in Lua 5.2) -local f, err = load("return 10 + 20") -if f then - print("Loaded function result:", f()) -else - print("Failed to load function:", err) -end - --- Test 4: table.unpack -local t = {1, 2, 3} -print("Unpacked values:", table.unpack(t)) - --- Test 5: String operations -local str = "Hello, World!" -print("String length:", #str) -print("Substring:", string.sub(str, 1, 5)) - --- Test 6: Math operations -print("Math operations:") -print(" sqrt(16) =", math.sqrt(16)) -print(" max(10, 20, 5) =", math.max(10, 20, 5)) - -print("--- Test Complete: All basic features working ---") -EOF - ''' - - echo 'Creating and starting the build container...' - sh "docker run -d --name ${containerName} lush-app:latest sleep infinity" - - // Since the Docker image now has the full source, we only need to copy the test script. - echo 'Copying test script into the container...' - sh "docker cp test_52.lua ${containerName}:/app/test_52.lua" - - echo 'Compiling and running tests inside the container...' - sh "docker exec ${containerName} /bin/bash -c 'premake5 gmake2 && make && ./bin/Debug/lush/lush test_52.lua'" - - echo 'Extracting compiled binary from the container...' - sh "docker cp ${containerName}:/app/bin ./" - - } finally { - echo "Cleaning up build container: ${containerName}" - sh "docker stop ${containerName} >/dev/null 2>&1 || true" - sh "docker rm ${containerName} >/dev/null 2>&1 || true" - } - } - } - } - } - post { - always { - echo 'Pipeline finished.' - sh 'docker rmi lush-app:latest || true' - } - } -} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 0cccadc..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,18 +0,0 @@ -# docker-compose.yml -services: - jenkins: - build: - context: . - dockerfile: Dockerfile.jenkins - args: - # Pass all necessary host IDs to the build - UID: ${UID} - GID: ${GID} - DOCKER_GID: ${DOCKER_GID} - ports: - - "8080:8080" - - "50000:50000" - container_name: jenkins - volumes: - - ./jenkins_home:/var/jenkins_home - - /var/run/docker.sock:/var/run/docker.sock \ No newline at end of file From 49f3d153ac2dc17ff81ad44b204be3e360e529bd Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 04:12:05 -0500 Subject: [PATCH 32/33] build: Remove broken submodule configuration --- .gitmodules | 1 - lib/compat53 | 1 + lib/hashmap | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) create mode 160000 lib/compat53 create mode 160000 lib/hashmap diff --git a/.gitmodules b/.gitmodules index 8e625f2..7b39498 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,4 +4,3 @@ [submodule "lib/hashmap"] path = lib/hashmap url = https://github.com/tidwall/hashmap.c.git - diff --git a/lib/compat53 b/lib/compat53 new file mode 160000 index 0000000..dfd83b4 --- /dev/null +++ b/lib/compat53 @@ -0,0 +1 @@ +Subproject commit dfd83b4930c8b85fd39d208523f7293cf469b205 diff --git a/lib/hashmap b/lib/hashmap new file mode 160000 index 0000000..1c13992 --- /dev/null +++ b/lib/hashmap @@ -0,0 +1 @@ +Subproject commit 1c139923fe08f36143ecc0ba37cd674684f87f9c From 4ac55835610f41c412d4abb1d8a113dcfe3140dd Mon Sep 17 00:00:00 2001 From: "Andrew D. France" Date: Wed, 23 Jul 2025 04:31:13 -0500 Subject: [PATCH 33/33] Revert to old hashmap: fixed gitmodule index --- .gitmodules | 3 -- lib/hashmap | 1 - lib/hashmap/hashmap.c | 69 +++++++++++++++++++++++++++++++++++++++++++ lib/hashmap/hashmap.h | 38 ++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) delete mode 160000 lib/hashmap create mode 100644 lib/hashmap/hashmap.c create mode 100644 lib/hashmap/hashmap.h diff --git a/.gitmodules b/.gitmodules index 7b39498..03c2dcd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "lib/compat53"] path = lib/compat53 url = https://github.com/lunarmodules/lua-compat-5.3.git -[submodule "lib/hashmap"] - path = lib/hashmap - url = https://github.com/tidwall/hashmap.c.git diff --git a/lib/hashmap b/lib/hashmap deleted file mode 160000 index 1c13992..0000000 --- a/lib/hashmap +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1c139923fe08f36143ecc0ba37cd674684f87f9c diff --git a/lib/hashmap/hashmap.c b/lib/hashmap/hashmap.c new file mode 100644 index 0000000..cfc112c --- /dev/null +++ b/lib/hashmap/hashmap.c @@ -0,0 +1,69 @@ +/* +Copyright (c) 2024, Lance Borden +All rights reserved. + +This software is licensed under the BSD 3-Clause License. +You may obtain a copy of the license at: +https://opensource.org/licenses/BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted under the conditions stated in the BSD 3-Clause +License. + +THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#include "hashmap.h" +#include +#include +#include + +hashmap_t *hm_new_hashmap() { + hashmap_t *this = malloc(sizeof(hashmap_t)); + this->cap = 8; + this->len = 0; + // null all pointers in list + this->list = calloc((this->cap), sizeof(map_pair_t *)); + return this; +} + +unsigned int hm_hashcode(hashmap_t *this, char *key) { + unsigned int code; + for (code = 0; *key != '\0'; key++) { + code = *key + 31 * code; + } + + return code % (this->cap); +} + +char *hm_get(hashmap_t *this, char *key) { + map_pair_t *current; + for (current = this->list[hm_hashcode(this, key)]; current; + current = current->next) { + if (strcmp(current->key, key) == 0) { + return current->val; + } + } + // the key is not found + return NULL; +} + +void hm_set(hashmap_t *this, char *key, char *val) { + unsigned int idx = hm_hashcode(this, key); + map_pair_t *current; + for (current = this->list[idx]; current; current = current->next) { + if (strcmp(current->key, key) == 0) { + current->val = val; + return; + } + } + + map_pair_t *p = malloc(sizeof(map_pair_t)); + p->key = key; + p->val = val; + p->next = this->list[idx]; + this->list[idx] = p; + this->len++; +} diff --git a/lib/hashmap/hashmap.h b/lib/hashmap/hashmap.h new file mode 100644 index 0000000..d5775c5 --- /dev/null +++ b/lib/hashmap/hashmap.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 2024, Lance Borden +All rights reserved. + +This software is licensed under the BSD 3-Clause License. +You may obtain a copy of the license at: +https://opensource.org/licenses/BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted under the conditions stated in the BSD 3-Clause +License. + +THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#ifndef HASHMAP_H +#define HASHMAP_H + +typedef struct pair { + char *key; + char *val; + struct pair *next; +} map_pair_t; + +typedef struct { + map_pair_t **list; + unsigned int cap; + unsigned int len; +} hashmap_t; + +hashmap_t *hm_new_hashmap(); +unsigned int hm_hashcode(hashmap_t *this, char *key); +char *hm_get(hashmap_t *this, char *key); +void hm_set(hashmap_t *this, char *key, char *val); + +#endif // HASHMAP_H