luametatex-2.11.08/0000775000175000017500000000000015077444255013027 5ustar hillehilleluametatex-2.11.08/CMakeSettings.json0000644000175000017500000000526715063273560016425 0ustar hillehille{ "configurations": [ { "name": "msvc-x64-debug", "generator": "Ninja", "configurationType": "Debug", "inheritEnvironments": [ "msvc_x64_x64" ], "buildRoot": "${projectDir}\\build\\${name}", "installRoot": "${projectDir}\\..\\install\\${name}", "cmakeCommandArgs": "", "buildCommandArgs": "-v", "ctestCommandArgs": "" }, { "name": "msvc-x64-release", "generator": "Ninja", "configurationType": "Release", "buildRoot": "${projectDir}\\build\\${name}", "installRoot": "${projectDir}\\..\\install\\${name}", "cmakeCommandArgs": "", "buildCommandArgs": "-v", "ctestCommandArgs": "", "inheritEnvironments": [ "msvc_x64_x64" ] }, { "name": "msvc-x64-clang", "generator": "Ninja", "configurationType": "Release", "buildRoot": "${projectDir}\\build\\${name}", "installRoot": "${projectDir}\\..\\install\\${name}", "cmakeCommandArgs": "", "buildCommandArgs": "-v", "ctestCommandArgs": "", "inheritEnvironments": [ "clang_cl_x64" ] }, { "name": "msvc-arm64-release", "generator": "Ninja", "configurationType": "Debug", "inheritEnvironments": [ "msvc_arm64_x64" ], "buildRoot": "${projectDir}\\build\\${name}", "installRoot": "${projectDir}\\..\\install\\${name}", "cmakeCommandArgs": "", "buildCommandArgs": "-v", "ctestCommandArgs": "" }, { "name": "wsl-gcc-release", "generator": "Ninja", "configurationType": "RelWithDebInfo", "buildRoot": "${projectDir}\\out\\build\\${name}", "installRoot": "${projectDir}\\out\\install\\${name}", "cmakeExecutable": "cmake", "cmakeCommandArgs": "", "buildCommandArgs": "", "ctestCommandArgs": "", "inheritEnvironments": [ "linux_x64" ], "wslPath": "${defaultWSLPath}", "addressSanitizerRuntimeFlags": "detect_leaks=0" }, { "name": "msvc-x86-release", "generator": "Ninja", "configurationType": "Release", "buildRoot": "${projectDir}\\build\\${name}", "installRoot": "${projectDir}\\..\\install\\${name}", "cmakeCommandArgs": "", "buildCommandArgs": "-v", "ctestCommandArgs": "", "inheritEnvironments": [ "msvc_x86_x64" ] } ] }luametatex-2.11.08/build.sh0000644000175000017500000001037215063273560014455 0ustar hillehille# The official designated locations are: # # luametatex[.exe] # mtxrun[.exe] -> luametatex[.exe] # mtxrun.lua (latest version) # context.lua (latest version) # This test is not yet okay but I have no time (or motivation) to look into it now, so for now we don't # use ninja (not that critical). #NINJA=$(which ninja); #if (NINJA) then # NINJA="-G Ninja" #else NINJA="" #fi if [ "$1" = "mingw-64" ] || [ "$1" = "mingw64" ] || [ "$1" = "mingw" ] || [ "$1" == "--mingw64" ] then PLATFORM="win64" SUFFIX=".exe" mkdir -p build/mingw-64 cd build/mingw-64 cmake $NINJA -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-64.cmake ../.. elif [ "$1" = "mingw-32" ] || [ "$1" = "mingw32" ] || [ "$1" == "--mingw32" ] then PLATFORM="mswin" SUFFIX=".exe" mkdir -p build/mingw-32 cd build/mingw-32 cmake $NINJA -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-32.cmake ../.. elif [ "$1" = "mingw-64-ucrt" ] || [ "$1" = "mingw64ucrt" ] || [ "$1" = "--mingw64ucrt" ] || [ "$1" = "ucrt" ] || [ "$1" = "--ucrt" ] then PLATFORM="win64" SUFFIX=".exe" mkdir -p build/mingw-64-ucrt cd build/mingw-64-ucrt cmake $NINJA -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-64-ucrt.cmake ../.. elif [ "$1" = "cygwin" ] || [ "$1" = "--cygwin" ] then PLATFORM="cygwin" SUFFIX=".exe" mkdir -p build/cygwin cd build/cygwin cmake $NINJA ../.. elif [ "$1" = "osx-arm" ] || [ "$1" = "osxarm" ] || [ "$1" = "--osx-arm" ] || [ "$1" = "--osxarm" ] then PLATFORM="osx-arm" SUFFIX=" " mkdir -p build/osx-arm cd build/osx-arm cmake $NINJA -DCMAKE_OSX_ARCHITECTURES="arm64" ../.. elif [ "$1" = "osx-intel" ] || [ "$1" = "osxintel" ] || [ "$1" = "--osx-intel" ] || [ "$1" = "--osxintel" ] then PLATFORM="osx-intel" SUFFIX=" " mkdir -p build/osx-intel cd build/osx-intel cmake $NINJA -DCMAKE_OSX_ARCHITECTURES="x86_64" ../.. elif [ "$1" = "osx-universal" ] || [ "$1" = "osxuniversal" ] || [ "$1" = "--osx-universal" ] || [ "$1" = "--osxuniversal" ] then PLATFORM="osx" SUFFIX=" " mkdir -p build/osx cd build/osx cmake $NINJA -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" ../.. elif [ "$1" = "help" ] || [ "$1" = "--help" ] then echo "" echo "platforms, optionally passed as argument:" echo "" echo "mingw-64" echo "mingw-32" echo "mingw-64-ucrt" echo "cygwin" echo "osx-arm" echo "osx-intel" echo "osx-universal" echo "" echo "default platform: native" echo "" exit 0 else PLATFORM="native" SUFFIX=" " mkdir -p build/native cd build/native cmake $NINJA ../.. fi #~ make -j8 cmake --build . --parallel 8 echo "" echo "tex trees" echo "" echo "resources like public fonts : tex/texmf/...." echo "the context macro package : tex/texmf-context/...." echo "the luametatex binary : tex/texmf-$PLATFORM/bin/..." echo "optional third party modules : tex/texmf-context/...." echo "fonts installed by the user : tex/texmf-fonts/fonts/data/...." echo "styles made by the user : tex/texmf-projects/tex/context/user/...." echo "" echo "binaries:" echo "" echo "tex/texmf-/bin/luametatex$SUFFIX : the compiled binary (some 3-4MB)" echo "tex/texmf-/bin/mtxrun$SUFFIX : copy of or link to luametatex" echo "tex/texmf-/bin/context$SUFFIX : copy of or link to luametatex" echo "tex/texmf-/bin/mtxrun.lua : copy of tex/texmf-context/scripts/context/lua/mtxrun.lua" echo "tex/texmf-/bin/context.lua : copy of tex/texmf-context/scripts/context/lua/context.lua" echo "" echo "commands:" echo "" echo "mtxrun --generate : create file database" echo "mtxrun --script fonts --reload : create font database" echo "mtxrun --autogenerate context ... : run tex file (e.g. from editor)" echo "" luametatex-2.11.08/build.cmd0000755000175000017500000000521315063273560014607 0ustar hillehillerem When something fails, make sure to remove the cmake cache. When compile from rem the Visual Studio environment mixed with compiling from the command line rem some confusion can occur. setlocal @echo . @echo supported flags : --arm64 --x64 --x86 --intel64 --intel86 @echo . set luametatexsources=%~dp0 set luametatexplatform=x64 set msvcplatform=x64 for %%G in (%*) do ( if [%%G] == [--arm64] ( set luametatexplatform=arm64 set msvcplatform=x86_arm64 ) if [%%G] == [--intel64] ( set luametatexplatform=x64 set msvcplatform=amd64 ) if [%%G] == [--intel86] ( set luametatexplatform=x86 set msvcplatform=x86_amd64 ) if [%%G] == [--x64] ( set luametatexplatform=x64 set msvcplatform=amd64 ) if [%%G] == [--x86] ( set luametatexplatform=x86 set msvcplatform=x86_amd64 ) ) set visualstudiopath=c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build set luametatexbuildpath=msvc-cmd-%luametatexplatform%-release @echo . @echo luametatexplatform : %luametatexplatform% @echo msvcplatform : %msvcplatform% @echo visualstudiopath : %visualstudiopath% @echo luametatexbuildpath : %luametatexbuildpath% @echo . mkdir build chdir build rmdir /S /Q %luametatexbuildpath% mkdir %luametatexbuildpath% chdir %luametatexbuildpath% call "%visualstudiopath%\vcvarsall.bat" %msvcplatform% cmake ../.. cmake --build . --config Release --parallel 8 cd .. cd .. dir build\%luametatexbuildpath%\Release\luametatex.exe @echo . @echo tex trees: @echo . @echo resources like public fonts : tex/texmf/.... @echo the context macro package : tex/texmf-context/.... @echo the luametatex binary : tex/texmf-win64/bin/... @echo optional third party modules : tex/texmf-context/.... @echo fonts installed by the user : tex/texmf-fonts/fonts/data/.... @echo styles made by the user : tex/texmf-projects/tex/context/user/.... @echo . @echo binaries: @echo . @echo tex/texmf-win64/bin/luametatex.exe : the compiled binary (some 2-3MB) @echo tex/texmf-win64/bin/mtxrun.exe : copy of or link to luametatex.exe @echo tex/texmf-win64/bin/context.exe : copy of or link to luametatex.exe @echo tex/texmf-win64/bin/mtxrun.lua : copy of tex/texmf-context/scripts/context/lua/mtxrun.lua @echo tex/texmf-win64/bin/context.lua : copy of tex/texmf-context/scripts/context/lua/context.lua @echo . @echo commands: @echo . @echo mtxrun --generate : create file database @echo mtxrun --script fonts --reload : create font database @echo mtxrun --autogenerate context ... : run tex file (e.g. from editor) @echo . endlocal luametatex-2.11.08/build.txt0000644000175000017500000000404315063273560014660 0ustar hillehilleHi, The build script produce efficient static binaries with only a couple of system libraries as dependency. ConTeXt will not depend on anything else than provided here. Lua is the extension language to be used and that has worked well for quite a while now. The build script that is provided will compile under ./build so you might want to make a copy of the source tree to a suitable place that you can wipe after the job is done. The script accepts only a few command line arguments. build.sh : --native build/native meant for unix (linux, freebsd, openbsd, osx, arm) --mingw-32 build/mingw-32 meant for 32 bit windows (crosscompiled) --mingw-64 build/mingw-64 meant for 64 bit windows (crosscompiled) I develop LuaMetaTeX on Windows and use WLS (with OpenSuse) for cross compilation as well as native Linux binaries. Editing is done in Visual Studio with the exception of the MetaPost CWeb files for which I use SciTE. Because we use CMake, you can compile using the MSVC compiler as well as CLang. Currently the MingW crosscompiled binaries are slightly faster, next come the native ones, but till now CLang lags behind. The native compiler produces the smallest binaries and compiles fastest. build.cmd : --x64 build/msvc-cmd-x64 meant for 64 bit windows using intel/amd chips --x32 build/msvc-cmd-x86 meant for 32 bit windows using intel/amd chips --arm64 build/msvc-cmd-arm64 meant for 64 bit windows using arm chips Alternatively you can run a build job from Visual Studio. Of course it only works well if you have the right compilers installed which is easy to do from the user interface. All settings happen in CMakeLists.txt so you have to load that one. Support for LuaMetaTeX and ConTeXt is provided at the (dev-)context mailing lists and at the ConTeXt Wiki. Binaries are available at: https://build.contextgarden.net/#/waterfall?tags=c.luametatex https://dl.contextgarden.net/build/luametatex The first link shows the status, the second link is where the binaries can be downloaded. Hans Hagen luametatex-2.11.08/CMakeLists.txt0000644000175000017500000002346015063273560015564 0ustar hillehille# We use CMake but I bet we can also provide a simple make file for linux just because # when I look what gets compiled into CMake we need very little of that (and it # has a lot of dependencies - ssh related, compression, security, xml, etc), but maybe # there is a lightweight version of CMake. cmake_minimum_required(VERSION 3.9..3.28) project(luametatex VERSION 2.11 LANGUAGES C) # I need to check with Mojca of the compile farm can handle this. set(CMAKE_C_STANDARD 11) # set(CMAKE_C_STANDARD 17) # set(CMAKE_C_STANDARD 23) # https://sourceforge.net/p/predef/wiki/OperatingSystems/ # https://sourceforge.net/p/predef/wiki/Architectures/ include(GNUInstallDirs) # Optionals (maybe have a LMT_*_TOO for each of them). We might start out with only a very few # optionals at some time, but for now we enable them (there is not not much code involved). The # idea behind these optionals is that we have very simple (!) interfaces, delegating as much as # possible to Lua. We will *not* add interfaces with many bindings because that will introduce # dependencies (and looking at e.g. LuaTeX build updates shows that clearly: a no-go). set(LMT_KPSE_TOO 1) # In case we want to manage MKII scripts (etc) with mtxrun. set(LMT_HB_TOO 1) # Maybe handy for Idris' font development (old converted ffi stuff) # This triggere link time optimization, which adds to compile time and gains (at most) a few # percent on runtime. When set, because we're sparse, we also strip the binary. # set(LMT_OPTIMIZE 1) # This makes the binary some 135K smaller so it might become the default at some point which is # nice (the smaller as runner the better). After all, we don't load external (Lua) libraries # anyway. set(LMT_STRIP 1) # When one wants to use Lua libraries, this is needed. But keep in mind that it's not supported, # so we won't look into issues that could result from that. Getting a matching library is upto # the user. Keep in mind that we might have set a different bytecode (luac) version during the # alpha/beta stages of a Lua development version. if (EXISTS "${CMAKE_SOURCE_DIR}/source/lua/lmthelperlib.c") set(luametatex_use_helpers 1) add_definitions(-DLUAMETATEX_USE_HELPERS=1) endif() # set(LMT_PERMIT_LUA_LIBRARIES 1) if (DEFINED LMT_PERMIT_LUA_LIBRARIES) unset(LMT_STRIP) unset(LMT_OPTIMIZE) add_definitions(-DLMT_PERMIT_LUA_LIBRARIES="yes") endif () if (MSVC) if (CMAKE_C_COMPILER_ID MATCHES "Clang") add_compile_options( -Wall -O2 -Wcast-align -Wcast-qual -Wno-unknown-pragmas -fno-strict-aliasing -Wno-pedantic -Wno-deprecated-declarations -Wno-missing-noreturn -Wno-shadow ) add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-DLMT_COMPILER_USED="clang") else() add_compile_options( /Wall /wd4127 # constant conditional expression /wd4131 # old style declarator /wd4152 # function pointer cast /wd4201 # nonstandard extension used: nameless struct/union /wd4244 # assignment in conditional expression /wd4456 # local vars with same name as outer variable /wd4457 # local vars with same function parameter /wd4464 # relative include path /wd4668 # missing defines /wd4702 # unreachable code /wd4710 # inlining /wd4711 # inlining /wd4774 # sprint argument 2 warning /wd4777 # format argument 2 warning /wd4820 # local vars with same name as outer variable /wd4996 # strdup etc warnings /wd5045 # spectre # /GL # whole program link optimization # /Gw # whole program data optimization (a little smaller bin) # /Ob3 # more agressive inline, much larger bin, no gain /wd4061 # enumerator * in switch * is not explicitly handled (mp) /wd4701 # potentially unitialized local variable (lua) /wd4255 # no function prototype given /wd5105 # macro expansion producing 'defined' has undefined behavior /wd4548 # expression before comma has no effect; expected expression with side-effect # indeed a bit faster but also a much larger binary: # /fp:fast # okay for amd processors too but no difference in size so probably no gain: # /favor:INTEL64 # /fsanitize:address # /std:c17 ) # We always optimize ... symbols are not in the binary anyway so there is no advantage # (like when accessing Lua api functions). We could have an additional luametatex-lua.dll # but that also creates a dependency (possible conflict). So just don't expect using # Lua libraries in luametatex. # if (DEFINED LMT_OPTIMIZE) add_compile_options( /GL # whole program link optimization /Gw # whole program data optimization (a little smaller bin) ) # endif() add_definitions(-DLMT_COMPILER_USED="msvc") endif() else() if (CMAKE_C_COMPILER_ID MATCHES "Clang") # why not -03 add_compile_options( -O2 ) add_definitions(-DLMT_COMPILER_USED="clang") else() add_compile_options( -O3 # -g0 # -mtune=nocona # fails on arm so more testing needed ) add_definitions(-DLMT_COMPILER_USED="gcc") # add_compile_options(-pg) # add_link_options(-pg) # e.g. mp crashes when we have > 4K currentpicture clips in a row # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,stack-size=1000000") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,stack-size=2621440") endif() add_compile_options( -Wall -Wcast-align -Wcast-qual # we need to check for zeros anyway as not all compiles have this # -fno-signed-zeros # -fno-trapping-math # -fno-math-errno -Wno-unknown-pragmas -Wno-unused-result -fno-strict-aliasing ) # for c17 # # add_definitions(-D__STDC_WANT_LIB_EXT2__=1) if ((DEFINED LMT_OPTIMIZE) OR (DEFINED LMT_STRIP)) if (NOT (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")) set(CMAKE_EXE_LINKER_FLAGS "-s") endif() endif() endif() if (CMAKE_C_COMPILER_ID MATCHES "Clang") add_compile_options( -Wno-unknown-warning-option -Wno-nonportable-include-path -Wno-nonportable-system-include-path -Wno-newline-eof -Wno-extra-semi-stmt -Wno-sign-conversion -Wno-unused-macros -Wno-reserved-id-macro -Wno-comma -Wno-switch-enum -Wno-shadow -Wno-missing-noreturn -Wno-implicit-fallthrough # -Wno-format -Wno-reserved-identifier -Wno-date-time -Wno-format-nonliteral -Wno-float-equal # too noisy, we just look at what gcc reports -Wno-unsafe-buffer-usage -Wno-macro-redefined -Wno-undef -Wno-switch-default -Wno-class-varargs ) endif() # Not that tested (converted ffi originals): if ((DEFINED LMT_KPSE_TOO)) add_definitions(-DLMT_KPSE_TOO=1) endif() if ((DEFINED LMT_HB_TOO)) add_definitions(-DLMT_HB_TOO=1) endif() # This needs cmake >= 3.9 and produces a 60K smaller mingw binary but it take quite a bit of # runtime to get there so it should become an option (apart from testing on all builders). if (DEFINED LMT_OPTIMIZE) include(CheckIPOSupported) check_ipo_supported(RESULT ipo_supported OUTPUT ipo_message) if (ipo_supported) # # We only have one program so we do it global (can become an -- option) # # set_property(TARGET luametatex PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) # # mingw64: 2865664, nocona: 2819584, lto: 2835968 (around 1% gain on manual) # set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # else() # No message needed, just accept the fact. endif() endif() # Mimalloc is still under development, so we only support it on a few platforms. By the time it is # stable we can probably remove some of the following tests. A bit of a hack: # # When the old osx version is dropped and armhf is upgraded we can enable unix except solaris which # fails. So, only osx 10.6 and rpi 32 fail. But we will probably drop 32 bit in the future anyway. # # At the beginning of 2025 on Windows 10 the gain is some 5 percent on the 650 page luametatex # manual over the default memory allocator. # CMAKE_HOST_SYSTEM_PROCESSOR arm64 x86_64 # if (APPLE) # set(MI_OSX_ZONE 1) # endif() if (CMAKE_HOST_SOLARIS) # fails elseif (MSVC) set(luametatex_use_mimalloc 1) elseif (CMAKE_HOST_APPLE AND NOT (${CMAKE_C_COMPILER} MATCHES "arm")) # fails on the osx intel elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv7l") # fails on the rpi 32 bit elseif (CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") # no motivation to figure specifics out else() set(luametatex_use_mimalloc 1) endif() include_directories(${CMAKE_ROOT}/source) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/source) if ((DEFINED luametatex_use_mimalloc)) add_definitions(-DLUAMETATEX_USE_MIMALLOC=1) # add_definitions(-DMIMALLOC_RESET_DELAY=250) # set(luametatex_use_mimalloc 1) include(cmake/mimalloc.cmake) endif() include(cmake/tex.cmake) include(cmake/lua.cmake) include(cmake/mp.cmake) include(cmake/luarest.cmake) include(cmake/luasocket.cmake) include(cmake/luaoptional.cmake) include(cmake/pplib.cmake) include(cmake/miniz.cmake) include(cmake/softposit.cmake) include(cmake/potrace.cmake) include(cmake/qrcodegen.cmake) include(cmake/triangles.cmake) include(cmake/luametatex.cmake) luametatex-2.11.08/source/0000775000175000017500000000000015077444116014323 5ustar hillehilleluametatex-2.11.08/source/luarest/0000775000175000017500000000000015077444116016002 5ustar hillehilleluametatex-2.11.08/source/luarest/lmtoslibext.c0000644000175000017500000003320215063273560020510 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" # if defined (_WIN32) # define MKDIR(a,b) mkdir(a) # else # define MKDIR(a,b) mkdir(a,b) # endif /*tex An attempt to figure out the basic platform, does not care about niceties like version numbers yet, and ignores platforms where \LUATEX\ is unlikely to successfully compile without major porting effort (amiga,mac,os2,vms). We dropped solaris, cygwin, hpux, iris, sysv, dos, djgpp etc. Basically we have either a windows or some kind of unix brand. */ # ifdef _WIN32 # define OSLIB_PLATTYPE "windows" # define OSLIB_PLATNAME "windows" # else # include # include # if defined(__linux__) || defined (__gnu_linux__) # define OSLIB_PLATNAME "linux" # elif defined(__MACH__) && defined(__APPLE__) # define OSLIB_PLATNAME "macosx" # elif defined(__FreeBSD__) # define OSLIB_PLATNAME "freebsd" # elif defined(__OpenBSD__) # define OSLIB_PLATNAME "openbsd" # elif defined(__BSD__) # define OSLIB_PLATNAME "bsd" # elif defined(__GNU__) # define OSLIB_PLATNAME "gnu" # else # define OSLIB_PLATNAME "generic" # endif # define OSLIB_PLATTYPE "unix" # endif static int oslib_gettypevalues(lua_State *L) { lua_createtable(L, 2, 0); lua_set_string_by_index(L, 1, "windows"); lua_set_string_by_index(L, 2, "unix"); return 1; } static int oslib_getnamevalues(lua_State *L) { lua_createtable(L, 7, 0); lua_set_string_by_index(L, 1, "windows"); lua_set_string_by_index(L, 2, "linux"); lua_set_string_by_index(L, 3, "macosx"); lua_set_string_by_index(L, 4, "freebsd"); lua_set_string_by_index(L, 5, "bsd"); lua_set_string_by_index(L, 6, "gnu"); lua_set_string_by_index(L, 7, "generic"); return 1; } /*tex There could be more platforms that don't have these two, but win32 and sunos are for sure. |gettimeofday()| for win32 is using an alternative definition */ # ifndef _WIN32 # include /*tex for |gettimeofday()| */ # include /*tex for |times()| */ # include # endif static int oslib_sleep(lua_State *L) { lua_Number interval = luaL_checknumber(L, 1); lua_Number units = luaL_optnumber(L, 2, 1); # ifdef _WIN32 Sleep((DWORD) (1e3 * interval / units)); # else /* assumes posix or bsd */ usleep((unsigned) (1e6 * interval / units)); # endif return 0; } # ifdef _WIN32 # define _UTSNAME_LENGTH 65 /*tex Structure describing the system and machine. */ typedef struct utsname { char sysname [_UTSNAME_LENGTH]; char nodename[_UTSNAME_LENGTH]; char release [_UTSNAME_LENGTH]; char version [_UTSNAME_LENGTH]; char machine [_UTSNAME_LENGTH]; } utsname; /*tex Get name and information about current kernel. */ /*tex \starttabulate[|T|r|] \NC Windows 10 \NC 10.0 \NC \NR \NC Windows Server 2016 \NC 10.0 \NC \NR \NC Windows 8.1 \NC 6.3 \NC \NR \NC Windows Server 2012 R2 \NC 6.3 \NC \NR \NC Windows 8 \NC 6.2 \NC \NR \NC Windows Server 2012 \NC 6.2 \NC \NR \NC Windows 7 \NC 6.1 \NC \NR \NC Windows Server 2008 R2 \NC 6.1 \NC \NR \NC Windows Server 2008 \NC 6.0 \NC \NR \NC Windows Vista \NC 6.0 \NC \NR \NC Windows Server 2003 R2 \NC 5.2 \NC \NR \NC Windows Server 2003 \NC 5.2 \NC \NR \NC Windows XP 64-Bit Edition \NC 5.2 \NC \NR \NC Windows XP \NC 5.1 \NC \NR \NC Windows 2000 \NC 5.0 \NC \NR \stoptabulate */ static int uname(struct utsname *uts) { OSVERSIONINFO osver; SYSTEM_INFO sysinfo; DWORD sLength; memset(uts, 0, sizeof(*uts)); osver.dwOSVersionInfoSize = sizeof(osver); GetSystemInfo(&sysinfo); strcpy(uts->sysname, "Windows"); /*tex When |GetVersionEx| becomes obsolete the version and release fields will be set to "". */ // if (0) { // GetVersionEx(&osver); // sprintf(uts->version, "%ld.%02ld", osver.dwMajorVersion, osver.dwMinorVersion); // if (osver.szCSDVersion[0] != '\0' && (strlen(osver.szCSDVersion) + strlen(uts->version) + 1) < sizeof(uts->version)) { // strcat(uts->version, " "); // strcat(uts->version, osver.szCSDVersion); // } // sprintf(uts->release, "build %ld", osver.dwBuildNumber & 0xFFFF); // } else { /*tex I can't motivate myself to figure this out. */ strcpy(uts->version, ""); strcpy(uts->release, ""); // } /*tex So far for the fragile and actually not that relevant part of |uts|. */ switch (sysinfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: strcpy(uts->machine, "x86_64"); break; # ifdef PROCESSOR_ARCHITECTURE_ARM64 case PROCESSOR_ARCHITECTURE_ARM64: strcpy(uts->machine, "arm64"); break; # endif case PROCESSOR_ARCHITECTURE_INTEL: strcpy(uts->machine, "i386"); break; default: strcpy(uts->machine, "unknown"); break; } sLength = sizeof(uts->nodename) - 1; GetComputerName(uts->nodename, &sLength); return 0; } # endif static int oslib_getunamefields(lua_State *L) { lua_createtable(L, 5, 0); lua_set_string_by_index(L, 1, "sysname"); lua_set_string_by_index(L, 2, "machine"); lua_set_string_by_index(L, 3, "release"); lua_set_string_by_index(L, 4, "version"); lua_set_string_by_index(L, 5, "nodename"); return 1; } static int oslib_uname(lua_State *L) { struct utsname uts; if (uname(&uts) >= 0) { lua_createtable(L,0,5); lua_pushstring(L, uts.sysname); lua_setfield(L, -2, "sysname"); lua_pushstring(L, uts.machine); lua_setfield(L, -2, "machine"); lua_pushstring(L, uts.release); lua_setfield(L, -2, "release"); lua_pushstring(L, uts.version); lua_setfield(L, -2, "version"); lua_pushstring(L, uts.nodename); lua_setfield(L, -2, "nodename"); } else { lua_pushnil(L); } return 1; } # if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) # define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 # else # define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL # endif # ifdef _WIN32 # ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x04 # endif static int oslib_gettimeofday(lua_State *L) { FILETIME ft; __int64 tmpres = 0; GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; tmpres /= 10; /*tex Convert file time to unix epoch: */ tmpres -= DELTA_EPOCH_IN_MICROSECS; /*tex Float: */ lua_pushnumber(L, (double) tmpres / 1000000.0); return 1; } static int oslib_enableansi(lua_State *L) { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode = 0; int done = 0; if (GetConsoleMode(handle, &mode)) { mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; if (SetConsoleMode(handle, mode)) { done = 1; } else { /* bad */ } } lua_pushboolean(L, done); return 1; } # else static int oslib_gettimeofday(lua_State *L) { double v; struct timeval tv; gettimeofday(&tv, NULL); v = (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; /*tex Float: */ lua_pushnumber(L, v); return 1; } static int oslib_enableansi(lua_State *L) { lua_pushboolean(L, 1); return 1; } # endif /*tex Historically we have a different os.execute than Lua! */ static int oslib_execute(lua_State *L) { const char *cmd = luaL_optstring(L, 1, NULL); if (cmd) { lua_pushinteger(L, aux_utf8_system(cmd) || lmt_error_state.default_exit_code); } else { lua_pushinteger(L, 0); } return 1; } # ifdef _WIN32 static int oslib_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return luaL_fileresult(L, aux_utf8_remove(filename) == 0, filename); } static int oslib_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return luaL_fileresult(L, aux_utf8_rename(fromname, toname) == 0, NULL); } static int oslib_getcodepage(lua_State *L) { lua_pushinteger(L, (int) GetOEMCP()); lua_pushinteger(L, (int) GetACP()); return 2; } /* static int oslib_getenv(lua_State *L) { LPWSTR wkey = utf8_to_wide(luaL_checkstring(L, 1)); char * val = wide_to_utf8(_wgetenv(wkey)); lmt_memory_free(wkey); lua_pushstring(L, val); lmt_memory_free(val); return 1; } */ static int oslib_getenv(lua_State *L) { const char *key = luaL_checkstring(L, 1); char *val = NULL; if (key) { size_t wlen = 0; LPWSTR wkey = aux_utf8_to_wide(key); _wgetenv_s(&wlen, NULL, 0, wkey); if (wlen) { LPWSTR wval = (LPWSTR) lmt_memory_malloc(wlen * sizeof(WCHAR)); if (! _wgetenv_s(&wlen, wval, wlen, wkey)) { val = aux_utf8_from_wide(wval); } } } if (val) { lua_pushstring(L, val); } else { lua_pushnil(L); } return 1; } static int oslib_setenv(lua_State *L) { const char *key = luaL_optstring(L, 1, NULL); if (key) { const char *val = luaL_optstring(L, 2, NULL); LPWSTR wkey = aux_utf8_to_wide(key); LPWSTR wval = aux_utf8_to_wide(val ? val : ""); int bad = _wputenv_s(wkey, wval); lmt_memory_free(wval); lmt_memory_free(wkey); if (bad) { return luaL_error(L, "unable to change environment"); } } lua_pushboolean(L, 1); return 1; } # else static int oslib_getcodepage(lua_State *L) { lua_pushboolean(L,0); lua_pushboolean(L,0); return 2; } static int oslib_setenv(lua_State *L) { const char *key = luaL_optstring(L, 1, NULL); if (key) { const char *val = luaL_optstring(L, 2, NULL); if (val) { char *value = lmt_memory_malloc((unsigned) (strlen(key) + strlen(val) + 2)); sprintf(value, "%s=%s", key, val); if (putenv(value)) { /* lmt_memory_free(value); */ /* valgrind reports some issue otherwise */ return luaL_error(L, "unable to change environment"); } else { /* lmt_memory_free(value); */ /* valgrind reports some issue otherwise */ } } else { (void) unsetenv(key); } } lua_pushboolean(L, 1); return 1; } # endif static const luaL_Reg oslib_function_list[] = { { "sleep", oslib_sleep }, { "uname", oslib_uname }, { "gettimeofday", oslib_gettimeofday }, { "setenv", oslib_setenv }, { "execute", oslib_execute }, # ifdef _WIN32 { "rename", oslib_rename }, { "remove", oslib_remove }, { "getenv", oslib_getenv }, # endif { "enableansi", oslib_enableansi }, { "getcodepage", oslib_getcodepage }, { "getnamevalues", oslib_getnamevalues }, { "gettypevalues", oslib_gettypevalues }, { "getunamefields", oslib_getunamefields }, /* */ { NULL, NULL }, }; /*tex The |environ| variable is deprecated on windows so it made sense to just drop this old \LUATEX\ feature. */ # ifndef _WIN32 extern char **environ; # else # define environ _environ # endif int luaextend_os(lua_State *L) { /*tex We locate the library: */ lua_getglobal(L, "os"); /*tex A few constant strings: */ lua_pushliteral(L, OSLIB_PLATTYPE); lua_setfield(L, -2, "type"); lua_pushliteral(L, OSLIB_PLATNAME); lua_setfield(L, -2, "name"); /*tex The extra functions: */ for (const luaL_Reg *lib = oslib_function_list; lib->name; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); } /*tex Environment variables: */ if (0) { char **envpointer = environ; /*tex Provided by the standard library. */ if (envpointer) { lua_pushstring(L, "env"); lua_newtable(L); while (*envpointer) { /* TODO: perhaps a memory leak here */ char *envitem = lmt_memory_strdup(*envpointer); char *envitem_orig = envitem; char *envkey = envitem; while (*envitem != '=') { envitem++; } *envitem = 0; envitem++; lua_pushstring(L, envkey); lua_pushstring(L, envitem); lua_rawset(L, -3); envpointer++; lmt_memory_free(envitem_orig); } lua_rawset(L, -3); } } /*tex Done. */ lua_pop(L, 1); return 1; } luametatex-2.11.08/source/luarest/lmtbasexxlib.c0000644000175000017500000001231115063273560020636 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" /* # define BASEXX_PDF 1 */ # include # include # include /*tex First I had a mix of own code and LHF code (base64 and base85) but in the end I decided to reuse some of pplibs code. Performance is ok, although we can speed up the base16 coders. When needed, we can have a few more but normally pure \LUA\ is quite ok for our purpose. */ # define encode_nl(L) \ (lua_type(L, 2) == LUA_TNUMBER) ? (lmt_tointeger(L, 2)) : ( (lua_isboolean(L, 2)) ? 80 : 0 ) # define lua_iof_push(L,out) \ lua_pushlstring(L,(const char *) out->buf, iof_size(out)) static int basexxlib_encode_16(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = 2 * l; size_t nl = encode_nl(L); iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); if (nl) { base16_encode_ln(inp, out, 0, nl); } else { base16_encode(inp, out); } lua_iof_push(L, out); iof_close(out); return 1; } static int basexxlib_decode_16(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = l / 2; iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); base16_decode(inp, out); lua_iof_push(L, out); iof_close(out); return 1; } static int basexxlib_encode_64(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L,1,&l); size_t n = 4 * l; size_t nl = encode_nl(L); iof *inp = iof_filter_string_reader(s,l); iof *out = iof_filter_buffer_writer(n); if (nl) { base64_encode_ln(inp,out,0,nl); } else { base64_encode(inp,out); } lua_iof_push(L,out); iof_close(out); return 1; } static int basexxlib_decode_64(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = l; iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); base64_decode(inp, out); lua_iof_push(L, out); iof_close(out); return 1; } static int basexxlib_encode_85(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = 5 * l; size_t nl = encode_nl(L); iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); if (nl) { base85_encode_ln(inp, out, 0, 80); } else { base85_encode(inp, out); } lua_iof_push(L,out); iof_close(out); return 1; } static int basexxlib_decode_85(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = l; iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); base85_decode(inp, out); lua_iof_push(L, out); iof_close(out); return 1; } static int basexxlib_encode_RL(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = 2 * l; iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); runlength_encode(inp, out); lua_iof_push(L, out); iof_close(out); return 1; } static int basexxlib_decode_RL(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = 2 * l; iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); runlength_decode(inp, out); lua_iof_push(L, out); iof_close(out); return 1; } static int basexxlib_encode_LZW(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = 2 * l; char *t = lmt_memory_malloc(n); int flags = lmt_optinteger(L, 2, LZW_ENCODER_DEFAULTS); iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_string_writer(t, n); lzw_encode(inp, out, flags); lua_pushlstring(L, t, iof_size(out)); lmt_memory_free(t); return 1; } static int basexxlib_decode_LZW(lua_State *L) { size_t l; const unsigned char *s = (const unsigned char*) luaL_checklstring(L, 1, &l); size_t n = 2 * l; iof *inp = iof_filter_string_reader(s, l); iof *out = iof_filter_buffer_writer(n); int flags = lmt_optinteger(L, 2, LZW_DECODER_DEFAULTS); lzw_decode(inp, out, flags); lua_iof_push(L, out); iof_close(out); return 1; } static struct luaL_Reg basexxlib_function_list[] = { { "encode16", basexxlib_encode_16 }, { "decode16", basexxlib_decode_16 }, { "encode64", basexxlib_encode_64 }, { "decode64", basexxlib_decode_64 }, { "encode85", basexxlib_encode_85 }, { "decode85", basexxlib_decode_85 }, { "encodeRL", basexxlib_encode_RL }, { "decodeRL", basexxlib_decode_RL }, { "encodeLZW", basexxlib_encode_LZW }, { "decodeLZW", basexxlib_decode_LZW }, { NULL, NULL }, }; int luaopen_basexx(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, basexxlib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtxdecimallib.c0000644000175000017500000003421215063273560021136 0ustar hillehille/* See license.txt in the root of this project. */ /* decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *); decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *); decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *); # define decNumberIsCanonical(dn) # define decNumberIsFinite(dn) # define decNumberIsInfinite(dn) # define decNumberIsNaN(dn) # define decNumberIsNegative(dn) # define decNumberIsQNaN(dn) # define decNumberIsSNaN(dn) # define decNumberIsSpecial(dn) # define decNumberIsZero(dn) # define decNumberRadix(dn) The main reason why we have this module is that we already load the library in \METAPOST\ so it was a trivial extension to make. Because it is likely that we keep decimal support there, it is also quite likely that we keep this module, even if it's rarely used. The binary number system used in \METAPOST\ is not included. It is even less likely to be used and adds much to the binary. Some more functions might be added here so that we become more compatible with the other math libraries that are present. */ # include # include # include # define DECIMAL_METATABLE "decimal number" typedef decNumber *decimal; static decContext context; # define min_precision 25 # define default_precision 50 # define max_precision 2500 static void xdecimallib_initialize(void) { decContextDefault(&context, DEC_INIT_BASE); context.traps = 0; context.emax = 999999; context.emin = -999999; context.digits = default_precision; } /*tex Todo: Use metatable at the top. But we're not going to crunch numbers anyway so for now there is no need for it. Anyway, the overhead of calculations is much larger than that of locating a metatable. */ /* todo: check p return values */ static inline decimal xdecimallib_push(lua_State *L) { decimal p = lua_newuserdatauv(L, sizeof(decNumber), 0); luaL_setmetatable(L, DECIMAL_METATABLE); return p; } static void decNumberFromDouble(decNumber *A, double B, decContext *C) /* from mplib, extra arg */ { char buf[1000]; char *c; snprintf(buf, 1000, "%-650.325lf", B); c = buf; while (*c++) { if (*c == ' ') { *c = '\0'; break; } } decNumberFromString(A, buf, C); } static inline int xdecimallib_new(lua_State *L) { decimal p = xdecimallib_push(L); switch (lua_type(L, 1)) { case LUA_TSTRING: decNumberFromString(p, lua_tostring(L, 1), &context); break; case LUA_TNUMBER: if (lua_isinteger(L, 1)) { decNumberFromInt32(p, (int32_t) lua_tointeger(L, 1)); } else { decNumberFromDouble(p, lua_tonumber(L, 1), &context); } break; default: decNumberZero(p); break; } return 1; } /* This is nicer for the user. Beware, we create a userdata object on the stack so we need to replace the original non userdata. */ static decimal xdecimallib_get(lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TUSERDATA: return (decimal) luaL_checkudata(L, i, DECIMAL_METATABLE); case LUA_TSTRING: { decimal p = xdecimallib_push(L); decNumberFromString(p, lua_tostring(L, i), &context); lua_replace(L, i); return p; } case LUA_TNUMBER: { decimal p = xdecimallib_push(L); if (lua_isinteger(L, i)) { decNumberFromInt32(p, (int32_t) lua_tointeger(L, i)); } else { decNumberFromDouble(p, lua_tonumber(L, i), &context); } lua_replace(L, i); return p; } default: { decimal p = xdecimallib_push(L); decNumberZero(p); lua_replace(L, i); return p; } } } static int xdecimallib_tostring(lua_State *L) { decimal a = xdecimallib_get(L, 1); luaL_Buffer buffer; char *b = luaL_buffinitsize(L, &buffer, (size_t) a->digits + 14); decNumberToString(a, b); luaL_addsize(&buffer, strlen(b)); luaL_pushresult(&buffer); return 1; } static int xdecimallib_toengstring(lua_State *L) { decimal a = xdecimallib_get(L, 1); luaL_Buffer buffer; char *b = luaL_buffinitsize(L, &buffer, (size_t) a->digits + 14); decNumberToEngString(a, b); luaL_addsize(&buffer, strlen(b)); luaL_pushresult(&buffer); return 1; } static int xdecimallib_tonumber(lua_State *L) { decimal a = xdecimallib_get(L, 1); char *buffer = lmt_memory_malloc((size_t) a->digits + 14); /* could be shared */ if (buffer) { double result = 0.0; decNumberToString(a, buffer); if (sscanf(buffer, "%lf", &result)) { lua_pushnumber(L, result); } else { lua_pushnil(L); } lmt_memory_free(buffer); return 1; } else { return 0; } } static int xdecimallib_copy(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberCopy(p, a); return 1; } static int xdecimallib_eq(lua_State *L) { decNumber result; decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decNumberCompare(&result, a, b, &context); lua_pushboolean(L, decNumberIsZero(&result)); return 1; } static int xdecimallib_le(lua_State *L) { decNumber result; decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); /* todo: also number or string */ decNumberCompare(&result, a, b, &context); lua_pushboolean(L, decNumberIsNegative(&result) || decNumberIsZero(&result)); return 1; } static int xdecimallib_lt(lua_State *L) { decNumber result; decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); /* todo: also number or string */ decNumberCompare(&result, a, b, &context); lua_pushboolean(L, decNumberIsNegative(&result)); return 1; } static int xdecimallib_add(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberAdd(p, a, b, &context); return 1; } static int xdecimallib_sub(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberSubtract(p, a, b, &context); return 1; } static int xdecimallib_mul(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberMultiply(p, a, b, &context); return 1; } static int xdecimallib_div(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberDivide(p, a, b, &context); return 1; } static int xdecimallib_idiv(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberDivideInteger(p, a, b, &context); return 1; } static int xdecimallib_mod(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberRemainder(p, a, b, &context); return 1; } static int xdecimallib_neg(lua_State* L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberCopyNegate(p, a); return 1; } static int xdecimallib_min(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberMin(p, a, b, &context); return 1; } static int xdecimallib_max(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberMax(p, a, b, &context); return 1; } static int xdecimallib_minus(lua_State* L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberNextMinus(p, a, &context); return 1; } static int xdecimallib_plus(lua_State* L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberNextPlus(p, a, &context); return 1; } static int xdecimallib_trim(lua_State* L) { decimal a = xdecimallib_get(L, 1); decNumberTrim(a); return 0; } static int xdecimallib_pow(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberPower(p, a, b, &context); return 1; } static int xdecimallib_abs(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberCopyAbs(p, a); return 1; } static int xdecimallib_sqrt(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberSquareRoot(p, a, &context); return 1; } static int xdecimallib_ln(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberLn(p, a, &context); return 1; } static int xdecimallib_log10(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberLog10(p, a, &context); return 1; } static int xdecimallib_exp(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal p = xdecimallib_push(L); decNumberExp(p, a, &context); return 1; } static int xdecimallib_rotate(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberRotate(p, a, b, &context); return 1; } static int xdecimallib_shift(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberShift(p, a, b, &context); return 1; } static int xdecimallib_left(lua_State *L) { decimal a = xdecimallib_get(L, 1); lua_Integer shift = luaL_optinteger(L, 2, 1); decimal p = xdecimallib_push(L); decNumber s; decNumberFromInt32(&s, (int32_t) shift); decNumberShift(p, a, &s, &context); return 1; } static int xdecimallib_right(lua_State *L) { decimal a = xdecimallib_get(L, 1); lua_Integer shift = - luaL_optinteger(L, 2, 1); decimal p = xdecimallib_push(L); decNumber s; decNumberFromInt32(&s, (int32_t) shift); decNumberShift(p, a, &s, &context); return 1; } static int xdecimallib_and(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberAnd(p, a, b, &context); return 1; } static int xdecimallib_or(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberOr(p, a, b, &context); return 1; } static int xdecimallib_xor(lua_State *L) { decimal a = xdecimallib_get(L, 1); decimal b = xdecimallib_get(L, 2); decimal p = xdecimallib_push(L); decNumberXor(p, a, b, &context); return 1; } static int xdecimallib_setp(lua_State *L) { int i = (int) luaL_optinteger(L, 1, default_precision); if (i < min_precision) { context.digits = min_precision; } else if (i > max_precision) { context.digits = max_precision; } else { context.digits = i; } lua_pushinteger(L, context.digits); return 1; } static int xdecimallib_getp(lua_State *L) { lua_pushinteger(L, context.digits); return 1; } static const luaL_Reg xdecimallib_function_list[] = { /* management */ { "new", xdecimallib_new }, { "copy", xdecimallib_copy }, { "trim", xdecimallib_trim }, { "tostring", xdecimallib_tostring }, { "toengstring", xdecimallib_toengstring }, { "tonumber", xdecimallib_tonumber }, { "setprecision", xdecimallib_setp }, { "getprecision", xdecimallib_getp }, /* operators */ { "__add", xdecimallib_add }, { "__idiv", xdecimallib_idiv }, { "__div", xdecimallib_div }, { "__mod", xdecimallib_mod }, { "__eq", xdecimallib_eq }, { "__le", xdecimallib_le }, { "__lt", xdecimallib_lt }, { "__mul", xdecimallib_mul }, { "__sub", xdecimallib_sub }, { "__unm", xdecimallib_neg }, { "__pow", xdecimallib_pow }, { "__bor", xdecimallib_or }, { "__bxor", xdecimallib_xor }, { "__band", xdecimallib_and }, { "__shl", xdecimallib_left }, { "__shr", xdecimallib_right }, /* functions */ { "conj", xdecimallib_neg }, { "abs", xdecimallib_abs }, { "pow", xdecimallib_pow }, { "sqrt", xdecimallib_sqrt }, { "ln", xdecimallib_ln }, { "log", xdecimallib_log10 }, { "exp", xdecimallib_exp }, { "bor", xdecimallib_or }, { "bxor", xdecimallib_xor }, { "band", xdecimallib_and }, { "shift", xdecimallib_shift }, { "rotate", xdecimallib_rotate }, { "minus", xdecimallib_minus }, { "plus", xdecimallib_plus }, { "min", xdecimallib_min }, { "max", xdecimallib_max }, /* */ { NULL, NULL }, }; int luaopen_xdecimal(lua_State *L) { xdecimallib_initialize(); luaL_newmetatable(L, DECIMAL_METATABLE); luaL_setfuncs(L, xdecimallib_function_list, 0); lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); lua_pushliteral(L, "__tostring"); lua_pushliteral(L, "tostring"); lua_gettable(L, -3); lua_settable(L, -3); lua_pushliteral(L, "__name"); lua_pushliteral(L, "decimal"); lua_settable(L, -3); return 1; } luametatex-2.11.08/source/luarest/lmtiolibext.c0000644000175000017500000013142615063273560020505 0ustar hillehille/* See license.txt in the root of this project. */ /*tex Lua doesn't have cardinals so basically we could stick to integers and accept that we have a limited range. */ /*tex Maybe also make a string reader with a user data string, after all we can now store a position in the userdata directly. */ # include "luametatex.h" # ifdef _WIN32 # define lua_popen(L,c,m) ((void)L, _popen(c,m)) # define lua_pclose(L,file) ((void)L, _pclose(file)) # else # define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) # define lua_pclose(L,file) ((void)L, pclose(file)) # endif /* Mojca: we need to sort this out! */ # ifdef LUA_USE_POSIX # define l_fseek(f,o,w) fseeko(f,o,w) # define l_ftell(f) ftello(f) # define l_seeknum off_t # elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) && defined(_MSC_VER) && (_MSC_VER >= 1400) # define l_fseek(f,o,w) _fseeki64(f,o,w) # define l_ftell(f) _ftelli64(f) # define l_seeknum __int64 # elif defined(__MINGW32__) # define l_fseek(f,o,w) fseeko64(f,o,w) # define l_ftell(f) ftello64(f) # define l_seeknum int64_t # else # define l_fseek(f,o,w) fseek(f,o,w) # define l_ftell(f) ftell(f) # define l_seeknum long # endif # define uchar(c) ((unsigned char)(c)) /*tex A few helpers to avoid reading numbers as strings. For now we put them in their own namespace. We also have a few helpers that can make \IO\ functions \TEX\ friendly. */ static int fiolib_readcardinal1(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else { lua_pushinteger(L, a); } return 1; } else { return 0; } } static int siolib_readcardinal1(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if (p >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p]); lua_pushinteger(L, a); } return 1; } static int fiolib_readcardinal2(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); lua_Integer b = getc(f); if (b == EOF) { lua_pushnil(L); } else { /* (a<<8) | b */ lua_pushinteger(L, 0x100 * a + b); } return 1; } else { return 0; } } static int fiolib_readcardinal2_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer b = getc(f); lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else { /* (a<<8) | b */ lua_pushinteger(L, 0x100 * a + b); } return 1; } else { return 0; } } static int siolib_readcardinal2(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 1) >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p]); lua_pushinteger(L, 0x100 * a + b); } return 1; } static int siolib_readcardinal2_le(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 1) >= l) { lua_pushnil(L); } else { lua_Integer b = uchar(s[p++]); lua_Integer a = uchar(s[p]); lua_pushinteger(L, 0x100 * a + b); } return 1; } static int fiolib_readcardinal3(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); if (c == EOF) { lua_pushnil(L); } else { /* (a<<16) | (b<<8) | c */ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } return 1; } else { return 0; } } static int fiolib_readcardinal3_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer c = getc(f); lua_Integer b = getc(f); lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else { /* (a<<16) | (b<<8) | c */ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } return 1; } else { return 0; } } static int siolib_readcardinal3(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 2) >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p]); lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } return 1; } static int siolib_readcardinal3_le(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 2) >= l) { lua_pushnil(L); } else { lua_Integer c = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer a = uchar(s[p]); lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } return 1; } static int fiolib_readcardinal4(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); lua_Integer d = getc(f); if (d == EOF) { lua_pushnil(L); } else { /* (a<<24) | (b<<16) | (c<<8) | d */ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } return 1; } else { return 0; } } static int fiolib_readcardinal4_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer d = getc(f); lua_Integer c = getc(f); lua_Integer b = getc(f); lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else { /* (a<<24) | (b<<16) | (c<<8) | d */ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } return 1; } else { return 0; } } static int siolib_readcardinal4(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 3) >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_Integer d = uchar(s[p]); lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } return 1; } static int siolib_readcardinal4_le(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 3) >= l) { lua_pushnil(L); } else { lua_Integer d = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer a = uchar(s[p]); lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } return 1; } static int fiolib_readcardinaltable(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); lua_Integer m = lua_tointeger(L, 3); lua_createtable(L, (int) n, 0); switch (m) { case 1: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); if (a == EOF) { break; } else { lua_pushinteger(L, a); lua_rawseti(L, -2, i); } } break; case 2: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); lua_Integer b = getc(f); if (b == EOF) { break; } else { /* (a<<8) | b */ lua_pushinteger(L, 0x100 * a + b); lua_rawseti(L, -2, i); } } break; case 3: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); if (c == EOF) { break; } else { /* (a<<16) | (b<<8) | c */ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); lua_rawseti(L, -2, i); } } break; case 4: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); lua_Integer d = getc(f); if (d == EOF) { break; } else { /* (a<<24) | (b<<16) | (c<<8) | d */ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); lua_rawseti(L, -2, i); } } break; default: break; } return 1; } else { return 0; } } static int siolib_readcardinaltable(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer n = lua_tointeger(L, 3); lua_Integer m = lua_tointeger(L, 4); lua_Integer l = (lua_Integer) ls; lua_createtable(L, (int) n, 0); switch (m) { case 1: for (lua_Integer i = 1; i <= n; i++) { if (p >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_pushinteger(L, a); lua_rawseti(L, -2, i); } } break; case 2: for (lua_Integer i = 1; i <= n; i++) { if ((p + 1) >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_pushinteger(L, 0x100 * a + b); lua_rawseti(L, -2, i); } } break; case 3: for (lua_Integer i = 1; i <= n; i++) { if ((p + 2) >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); lua_rawseti(L, -2, i); } } break; case 4: for (lua_Integer i = 1; i <= n; i++) { if ((p + 3) >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_Integer d = uchar(s[p++]); lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); lua_rawseti(L, -2, i); } } break; default: break; } return 1; } static int fiolib_readinteger1(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, a - 0x100); } else { lua_pushinteger(L, a); } return 1; } else { return 0; } } static int siolib_readinteger1(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if (p >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, a - 0x100); } else { lua_pushinteger(L, a); } } return 1; } static int fiolib_readinteger2(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); lua_Integer b = getc(f); if (b == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, 0x100 * a + b - 0x10000); } else { lua_pushinteger(L, 0x100 * a + b); } return 1; } else { return 0; } } static int fiolib_readinteger2_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer b = getc(f); lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, 0x100 * a + b - 0x10000); } else { lua_pushinteger(L, 0x100 * a + b); } return 1; } else { return 0; } } static int siolib_readinteger2(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 1) >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, 0x100 * a + b - 0x10000); } else { lua_pushinteger(L, 0x100 * a + b); } } return 1; } static int siolib_readinteger2_le(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 1) >= l) { lua_pushnil(L); } else { lua_Integer b = uchar(s[p++]); lua_Integer a = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, 0x100 * a + b - 0x10000); } else { lua_pushinteger(L, 0x100 * a + b); } } return 1; } static int fiolib_readinteger3(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); if (c == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); } else { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } return 1; } else { return 0; } } static int fiolib_readinteger3_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer c = getc(f); lua_Integer b = getc(f); lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); } else { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } return 1; } else { return 0; } } static int siolib_readinteger3(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 2) >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); } else { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } } return 1; } static int siolib_readinteger3_le(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 2) >= l) { lua_pushnil(L); } else { lua_Integer c = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer a = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); } else { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } } return 1; } static int fiolib_readinteger4(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); lua_Integer d = getc(f); if (d == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); } else { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } return 1; } else { return 0; } } static int fiolib_readinteger4_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer d = getc(f); lua_Integer c = getc(f); lua_Integer b = getc(f); lua_Integer a = getc(f); if (a == EOF) { lua_pushnil(L); } else if (a >= 0x80) { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); } else { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } return 1; } else { return 0; } } static int siolib_readinteger4(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 3) >= l) { lua_pushnil(L); } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_Integer d = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); } else { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } } return 1; } static int siolib_readinteger4_le(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 3) >= l) { lua_pushnil(L); } else { lua_Integer d = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer a = uchar(s[p]); if (a >= 0x80) { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); } else { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } } return 1; } static int fiolib_readintegertable(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); lua_Integer m = lua_tointeger(L, 3); lua_createtable(L, (int) n, 0); switch (m) { case 1: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); if (a == EOF) { break; } else if (a >= 0x80) { lua_pushinteger(L, a - 0x100); } else { lua_pushinteger(L, a); } lua_rawseti(L, -2, i); } break; case 2: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); lua_Integer b = getc(f); if (b == EOF) { break; } else if (a >= 0x80) { lua_pushinteger(L, 0x100 * a + b - 0x10000); } else { lua_pushinteger(L, 0x100 * a + b); } lua_rawseti(L, -2, i); } break; case 3: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); if (c == EOF) { break; } else if (a >= 0x80) { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); } else { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } lua_rawseti(L, -2, i); } break; case 4: for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); lua_Integer b = getc(f); lua_Integer c = getc(f); lua_Integer d = getc(f); if (d == EOF) { break; } else if (a >= 0x80) { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); } else { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } lua_rawseti(L, -2, i); } break; default: break; } return 1; } else { return 0; } } static int siolib_readintegertable(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer n = lua_tointeger(L, 3); lua_Integer m = lua_tointeger(L, 4); lua_Integer l = (lua_Integer) ls; lua_createtable(L, (int) n, 0); switch (m) { case 1: for (lua_Integer i = 1; i <= n; i++) { if (p >= l) { break; } else { lua_Integer a = uchar(s[p++]); if (a >= 0x80) { lua_pushinteger(L, a - 0x100); } else { lua_pushinteger(L, a); } lua_rawseti(L, -2, i); } } break; case 2: for (lua_Integer i = 1; i <= n; i++) { if ((p + 1) >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); if (a >= 0x80) { lua_pushinteger(L, 0x100 * a + b - 0x10000); } else { lua_pushinteger(L, 0x100 * a + b); } lua_rawseti(L, -2, i); } } break; case 3: for (lua_Integer i = 1; i <= n; i++) { if ((p + 2) >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p++]); if (a >= 0x80) { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); } else { lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); } lua_rawseti(L, -2, i); } } break; case 4: for (lua_Integer i = 1; i <= n; i++) { if ((p + 3) >= l) { break; } else { lua_Integer a = uchar(s[p++]); lua_Integer b = uchar(s[p++]); lua_Integer c = uchar(s[p++]); lua_Integer d = uchar(s[p++]); if (a >= 0x80) { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); } else { lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); } lua_rawseti(L, -2, i); } } break; default: break; } return 1; } /* from ff */ static int fiolib_readfixed2(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { int a = getc(f); int b = getc(f); if (b == EOF) { lua_pushnil(L); } else { int n = 0x100 * a + b; /* really an int because we shift */ lua_pushnumber(L, (double) ((n>>8) + ((n&0xff)/256.0))); } return 1; } else { return 0; } } static int siolib_readfixed2(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 3) >= l) { lua_pushnil(L); } else { int a = uchar(s[p++]); int b = uchar(s[p]); int n = 0x100 * a + b; /* really an int because we shift */ lua_pushnumber(L, (double) ((n>>8) + ((n&0xff)/256.0))); } return 1; } static int fiolib_readfixed4(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { int a = getc(f); int b = getc(f); int c = getc(f); int d = getc(f); if (d == EOF) { lua_pushnil(L); } else { int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d; /* really an int because we shift */ lua_pushnumber(L, (double) ((n>>16) + ((n&0xffff)/65536.0))); } return 1; } else { return 0; } } static int siolib_readfixed4(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 3) >= l) { lua_pushnil(L); } else { int a = uchar(s[p++]); int b = uchar(s[p++]); int c = uchar(s[p++]); int d = uchar(s[p]); int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d; /* really an int because we shift */ lua_pushnumber(L, (double) ((n>>16) + ((n&0xffff)/65536.0))); } return 1; } static int fiolib_read2dot14(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { int a = getc(f); int b = getc(f); if (b == EOF) { lua_pushnil(L); } else { int n = 0x100 * a + b; /* really an int because we shift */ /* from ff */ lua_pushnumber(L, (double) (((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0))); } return 1; } else { return 0; } } static int siolib_read2dot14(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if ((p + 1) >= l) { lua_pushnil(L); } else { int a = uchar(s[p++]); int b = uchar(s[p]); int n = 0x100 * a + b; /* really an int because we shift */ lua_pushnumber(L, (double) (((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0))); } return 1; } static int fiolib_getposition(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { long p = ftell(f); if (p < 0) { lua_pushnil(L); } else { lua_pushinteger(L, p); } return 1; } else { return 0; } } static int fiolib_setposition(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { long p = lmt_tolong(L, 2); p = fseek(f, p, SEEK_SET); if (p < 0) { lua_pushnil(L); } else { lua_pushinteger(L, p); } return 1; } else { return 0; } } static int fiolib_skipposition(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { long p = lmt_tolong(L, 2); p = fseek(f, ftell(f) + p, SEEK_SET); if (p < 0) { lua_pushnil(L); } else { lua_pushinteger(L, p); } return 1; } else { return 0; } } static int fiolib_readbytetable(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); lua_createtable(L, (int) n, 0); for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); if (a == EOF) { break; } else { /* lua_pushinteger(L, i); lua_pushinteger(L, a); lua_rawset(L, -3); */ lua_pushinteger(L, a); lua_rawseti(L, -2, i); } } return 1; } else { return 0; } } static int siolib_readbytetable(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer n = lua_tointeger(L, 3); lua_Integer l = (lua_Integer) ls; if (p >= l) { lua_pushnil(L); } else { if (p + n >= l) { n = l - p ; } lua_createtable(L, (int) n, 0); for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = uchar(s[p++]); lua_pushinteger(L, a); lua_rawseti(L, -2, i); } } return 1; } static int fiolib_readbytes(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = getc(f); if (a == EOF) { return (int) (i - 1); } else { lua_pushinteger(L, a); } } return (int) n; } else { return 0; } } static int siolib_readbytes(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer n = lua_tointeger(L, 3); lua_Integer l = (lua_Integer) ls; if (p >= l) { return 0; } else { if (p + n >= l) { n = l - p ; } lua_createtable(L, (int) n, 0); for (lua_Integer i = 1; i <= n; i++) { lua_Integer a = uchar(s[p++]); lua_pushinteger(L, a); } return (int) n; } } static int fiolib_readcline(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { luaL_Buffer buf; int c = 0; int n = 0; luaL_buffinit(L, &buf); do { char *b = luaL_prepbuffer(&buf); int i = 0; while (i < LUAL_BUFFERSIZE) { c = fgetc(f); if (c == '\n') { goto GOOD; } else if (c == '\r') { c = fgetc(f); if (c != EOF && c != '\n') { ungetc((int) c, f); } goto GOOD; } else { n++; b[i++] = (char) c; } } } while (c != EOF); goto BAD; GOOD: if (n > 0) { luaL_addsize(&buf, n); luaL_pushresult(&buf); } else { lua_pushnil(L); } lua_pushinteger(L, ftell(f)); return 2; } BAD: lua_pushnil(L); return 1; } static int siolib_readcline(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if (p < l) { lua_Integer i = p; int n = 0; while (p < l) { int c = uchar(s[p++]); if (c == '\n') { goto GOOD; } else if (c == '\r') { if (p < l) { c = uchar(s[p++]); if (c != EOF && c != '\n') { --p; } } goto GOOD; } else { n++; } } goto BAD; GOOD: if (n > 0) { lua_pushlstring(L, &s[i], n); lua_pushinteger(L, p); return 2; } } BAD: lua_pushnil(L); lua_pushinteger(L, p + 1); return 2; } static int fiolib_readcstring(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { luaL_Buffer buf; int c = 0; int n = 0; luaL_buffinit(L, &buf); do { char *b = luaL_prepbuffer(&buf); int i = 0; while (i < LUAL_BUFFERSIZE) { c = fgetc(f); if (c == '\0') { goto GOOD; } else { n++; b[i++] = (char) c; } } } while (c != EOF); goto BAD; GOOD: if (n > 0) { luaL_addsize(&buf, n); luaL_pushresult(&buf); } else { lua_pushliteral(L,""); } lua_pushinteger(L, ftell(f)); return 2; } BAD: lua_pushnil(L); return 1; } static int siolib_readcstring(lua_State *L) { size_t ls = 0; const char *s = luaL_checklstring(L, 1, &ls); lua_Integer p = luaL_checkinteger(L, 2) - 1; lua_Integer l = (lua_Integer) ls; if (p < l) { lua_Integer i = p; int n = 0; while (p < l) { int c = uchar(s[p++]); if (c == '\0') { goto GOOD; } else { n++; } }; goto BAD; GOOD: if (n > 0) { lua_pushlstring(L, &s[i], n); } else { lua_pushliteral(L,""); } lua_pushinteger(L, p + 1); return 2; } BAD: lua_pushnil(L); lua_pushinteger(L, p + 1); return 2; } /* will be completed */ static int fiolib_writecardinal1(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc(n & 0xFF, f); } return 0; } static int siolib_tocardinal1(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[1] = { n & 0xFF }; lua_pushlstring(L, buffer, 1); return 1; } static int fiolib_writecardinal2(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc((n >> 8) & 0xFF, f); putc( n & 0xFF, f); } return 0; } static int siolib_tocardinal2(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[2] = { (n >> 8) & 0xFF, n & 0xFF }; lua_pushlstring(L, buffer, 2); return 1; } static int fiolib_writecardinal2_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc( n & 0xFF, f); putc((n >> 8) & 0xFF, f); } return 0; } static int siolib_tocardinal2_le(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[2] = { n & 0xFF, (n >> 8) & 0xFF }; lua_pushlstring(L, buffer, 2); return 1; } static int fiolib_writecardinal3(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc((n >> 16) & 0xFF, f); putc((n >> 8) & 0xFF, f); putc( n & 0xFF, f); } return 0; } static int siolib_tocardinal3(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[3] = { (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF }; lua_pushlstring(L, buffer, 3); return 1; } static int fiolib_writecardinal3_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc( n & 0xFF, f); putc((n >> 8) & 0xFF, f); putc((n >> 16) & 0xFF, f); } return 0; } static int siolib_tocardinal3_le(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[3] = { n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF }; lua_pushlstring(L, buffer, 3); return 1; } static int fiolib_writecardinal4(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc((n >> 24) & 0xFF, f); putc((n >> 16) & 0xFF, f); putc((n >> 8) & 0xFF, f); putc( n & 0xFF, f); } return 0; } static int siolib_tocardinal4(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[4] = { (n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF }; lua_pushlstring(L, buffer, 4); return 1; } static int fiolib_writecardinal4_le(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { lua_Integer n = lua_tointeger(L, 2); putc( n & 0xFF, f); putc((n >> 8) & 0xFF, f); putc((n >> 16) & 0xFF, f); putc((n >> 24) & 0xFF, f); } return 0; } static int siolib_tocardinal4_le(lua_State *L) { lua_Integer n = lua_tointeger(L, 1); char buffer[4] = { n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF, (n >> 24) & 0xFF }; lua_pushlstring(L, buffer, 4); return 1; } /* */ static const luaL_Reg fiolib_function_list[] = { /* helpers */ { "readcardinal1", fiolib_readcardinal1 }, { "readcardinal2", fiolib_readcardinal2 }, { "readcardinal3", fiolib_readcardinal3 }, { "readcardinal4", fiolib_readcardinal4 }, { "readcardinal1le", fiolib_readcardinal1 }, { "readcardinal2le", fiolib_readcardinal2_le }, { "readcardinal3le", fiolib_readcardinal3_le }, { "readcardinal4le", fiolib_readcardinal4_le }, { "readcardinaltable", fiolib_readcardinaltable }, { "readinteger1", fiolib_readinteger1 }, { "readinteger2", fiolib_readinteger2 }, { "readinteger3", fiolib_readinteger3 }, { "readinteger4", fiolib_readinteger4 }, { "readinteger1le", fiolib_readinteger1 }, { "readinteger2le", fiolib_readinteger2_le }, { "readinteger3le", fiolib_readinteger3_le }, { "readinteger4le", fiolib_readinteger4_le }, { "readintegertable", fiolib_readintegertable }, { "readfixed2", fiolib_readfixed2 }, { "readfixed4", fiolib_readfixed4 }, { "read2dot14", fiolib_read2dot14 }, { "setposition", fiolib_setposition }, { "getposition", fiolib_getposition }, { "skipposition", fiolib_skipposition }, { "readbytes", fiolib_readbytes }, { "readbytetable", fiolib_readbytetable }, { "readcline", fiolib_readcline }, { "readcstring", fiolib_readcstring }, { "writecardinal1", fiolib_writecardinal1 }, { "writecardinal2", fiolib_writecardinal2 }, { "writecardinal3", fiolib_writecardinal3 }, { "writecardinal4", fiolib_writecardinal4 }, { "writecardinal1le", fiolib_writecardinal1 }, { "writecardinal2le", fiolib_writecardinal2_le }, { "writecardinal3le", fiolib_writecardinal3_le }, { "writecardinal4le", fiolib_writecardinal4_le }, { NULL, NULL } }; static const luaL_Reg siolib_function_list[] = { { "readcardinal1", siolib_readcardinal1 }, { "readcardinal2", siolib_readcardinal2 }, { "readcardinal3", siolib_readcardinal3 }, { "readcardinal4", siolib_readcardinal4 }, { "readcardinal1le", siolib_readcardinal1 }, { "readcardinal2le", siolib_readcardinal2_le }, { "readcardinal3le", siolib_readcardinal3_le }, { "readcardinal4le", siolib_readcardinal4_le }, { "readcardinaltable", siolib_readcardinaltable }, { "readinteger1", siolib_readinteger1 }, { "readinteger2", siolib_readinteger2 }, { "readinteger3", siolib_readinteger3 }, { "readinteger4", siolib_readinteger4 }, { "readinteger1le", siolib_readinteger1 }, { "readinteger2le", siolib_readinteger2_le }, { "readinteger3le", siolib_readinteger3_le }, { "readinteger4le", siolib_readinteger4_le }, { "readintegertable", siolib_readintegertable }, { "readfixed2", siolib_readfixed2 }, { "readfixed4", siolib_readfixed4 }, { "read2dot14", siolib_read2dot14 }, { "readbytes", siolib_readbytes }, { "readbytetable", siolib_readbytetable }, { "readcline", siolib_readcline }, { "readcstring", siolib_readcstring }, { "tocardinal1", siolib_tocardinal1 }, { "tocardinal2", siolib_tocardinal2 }, { "tocardinal3", siolib_tocardinal3 }, { "tocardinal4", siolib_tocardinal4 }, { "tocardinal1le", siolib_tocardinal1 }, { "tocardinal2le", siolib_tocardinal2_le }, { "tocardinal3le", siolib_tocardinal3_le }, { "tocardinal4le", siolib_tocardinal4_le }, { NULL, NULL } }; /*tex The sio helpers might be handy at some point. Speed-wise there is no gain over file access because with ssd and caching we basically operate in memory too. We keep them as complement to the file ones. I did consider using an userdata object for the position etc but some simple tests demonstrated that there is no real gain and the current ones permits to wrap up whatever interface one likes. */ int luaopen_fio(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, fiolib_function_list, 0); return 1; } int luaopen_sio(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, siolib_function_list, 0); return 1; } /* We patch a function in the standard |io| library. */ /*tex The following code overloads the |io.open| function to deal with so called wide characters on windows. */ /* a variant on read_line but with nothing catched */ static int io_gobble(lua_State *L) { FILE *f = lmt_valid_file(L); if (f) { int c; int n = 0; while ((c = getc(f)) != EOF && c != '\n') { n = 1; } lua_pushboolean(L, ((c == '\n') || n)); } else { lua_pushnil(L); } return 1; } # if _WIN32 # define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) static int l_checkmode(const char *mode) { return ( mode && *mode != '\0' && strchr("rwa", *(mode++)) && (*mode != '+' || ((void)(++mode), 1)) && (strspn(mode, "b") == strlen(mode)) ); } typedef luaL_Stream LStream; static LStream *newprefile(lua_State *L) { LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0); p->closef = NULL; luaL_setmetatable(L, LUA_FILEHANDLE); return p; } 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) { /*tex Watch out: lua 5.4 has different closers. */ LStream *p = newprefile(L); p->f = NULL; p->closef = &io_fclose; return p; } 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 = aux_utf8_fopen(filename, mode); return (p->f) ? 1 : luaL_fileresult(L, 0, filename); } static int io_pclose(lua_State *L) { LStream *p = tolstream(L); return luaL_execresult(L, _pclose(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 = aux_utf8_popen(filename, mode); p->closef = &io_pclose; return (p->f) ? 1 : luaL_fileresult(L, 0, filename); } int luaextend_io(lua_State *L) { lua_getglobal(L, "io"); lua_pushcfunction(L, io_open); lua_setfield(L, -2, "open"); lua_pushcfunction(L, io_popen); lua_setfield(L, -2, "popen"); lua_pushcfunction(L, io_gobble); lua_setfield(L, -2, "gobble"); lua_pop(L, 1); /*tex Larger doesn't work and limits to 512 but then no amount is okay as there's always more to demand. */ _setmaxstdio(2048); return 1; } # else // int luaextend_io(lua_State *L) // { // (void) L; // return 1; // } int luaextend_io(lua_State *L) { lua_getglobal(L, "io"); lua_pushcfunction(L, io_gobble); lua_setfield(L, -2, "gobble"); lua_pop(L, 1); return 1; } # endif luametatex-2.11.08/source/luarest/lmtsha2lib.c0000644000175000017500000000506415063273560020210 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" # include # define SHA256_RESULT_LENGTH (SHA256_STRING_LENGTH-1) # define SHA384_RESULT_LENGTH (SHA384_STRING_LENGTH-1) # define SHA512_RESULT_LENGTH (SHA512_STRING_LENGTH-1) # define sha2_body(SHA_DIGEST_LENGTH, SHA_CALCULATE, CONVERSION, SHA_RESULT_LENGTH) do { \ if (lua_type(L, 1) == LUA_TSTRING) { \ uint8_t result[SHA_DIGEST_LENGTH]; \ size_t size = 0; \ const char *data = lua_tolstring(L, 1, &size); \ SHA_CALCULATE(data, size, result, CONVERSION); \ lua_pushlstring(L, (const char *) result, SHA_RESULT_LENGTH); \ return 1; \ } \ return 0; \ } while (0) static int sha2lib_256_sum(lua_State *L) { sha2_body(SHA256_DIGEST_LENGTH, sha256_digest, SHA_BYTES, SHA256_DIGEST_LENGTH); } static int sha2lib_384_sum(lua_State *L) { sha2_body(SHA384_DIGEST_LENGTH, sha384_digest, SHA_BYTES, SHA384_DIGEST_LENGTH); } static int sha2lib_512_sum(lua_State *L) { sha2_body(SHA512_DIGEST_LENGTH, sha512_digest, SHA_BYTES, SHA512_DIGEST_LENGTH); } static int sha2lib_256_hex(lua_State *L) { sha2_body(SHA256_STRING_LENGTH, sha256_digest, SHA_LCHEX, SHA256_RESULT_LENGTH); } static int sha2lib_384_hex(lua_State *L) { sha2_body(SHA384_STRING_LENGTH, sha384_digest, SHA_LCHEX, SHA384_RESULT_LENGTH); } static int sha2lib_512_hex(lua_State *L) { sha2_body(SHA512_STRING_LENGTH, sha512_digest, SHA_LCHEX, SHA512_RESULT_LENGTH); } static int sha2lib_256_HEX(lua_State *L) { sha2_body(SHA256_STRING_LENGTH, sha256_digest, SHA_UCHEX, SHA256_RESULT_LENGTH); } static int sha2lib_384_HEX(lua_State *L) { sha2_body(SHA384_STRING_LENGTH, sha384_digest, SHA_UCHEX, SHA384_RESULT_LENGTH); } static int sha2lib_512_HEX(lua_State *L) { sha2_body(SHA512_STRING_LENGTH, sha512_digest, SHA_UCHEX, SHA512_RESULT_LENGTH); } static struct luaL_Reg sha2lib_function_list[] = { /*tex We started out with this: */ { "digest256", sha2lib_256_sum }, { "digest384", sha2lib_384_sum }, { "digest512", sha2lib_512_sum }, /*tex The next is consistent with |md5lib|: */ { "sum256", sha2lib_256_sum }, { "sum384", sha2lib_384_sum }, { "sum512", sha2lib_512_sum }, { "hex256", sha2lib_256_hex }, { "hex384", sha2lib_384_hex }, { "hex512", sha2lib_512_hex }, { "HEX256", sha2lib_256_HEX }, { "HEX384", sha2lib_384_HEX }, { "HEX512", sha2lib_512_HEX }, { NULL, NULL }, }; int luaopen_sha2(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, sha2lib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtstrlibext.c0000644000175000017500000011232515063273560020703 0ustar hillehille/* See license.txt in the root of this project. */ /* todo: byteconcat and utf concat (no separator) */ # include "luametatex.h" /*tex Helpers */ static inline int strlib_aux_tounicode(const char *s, size_t l, size_t *p) { unsigned char i = s[*p]; *p += 1; if (i < 0x80) { return i; } else if (i >= 0xF0) { if ((*p + 2) < l) { unsigned char j = s[*p]; unsigned char k = s[*p + 1]; unsigned char l = s[*p + 2]; if (j >= 0x80 && k >= 0x80 && l >= 0x80) { *p += 3; return (((((i - 0xF0) * 0x40) + (j - 0x80)) * 0x40) + (k - 0x80)) * 0x40 + (l - 0x80); } } } else if (i >= 0xE0) { if ((*p + 1) < l) { unsigned char j = s[*p]; unsigned char k = s[*p + 1]; if (j >= 0x80 && k >= 0x80) { *p += 2; return (((i - 0xE0) * 0x40) + (j - 0x80)) * 0x40 + (k - 0x80); } } } else if (i >= 0xC0) { if (*p < l) { unsigned char j = s[*p]; if (j >= 0x80) { *p += 1; return ((i - 0xC0) * 0x40) + (j - 0x80); } } } return 0xFFFD; } static inline int strlib_aux_tounichar(const char *s, size_t l, size_t p) { unsigned char i = s[p++]; if (i < 0x80) { return 1; } else if (i >= 0xF0) { if ((p + 2) < l) { unsigned char j = s[p]; unsigned char k = s[p + 1]; unsigned char l = s[p + 2]; if (j >= 0x80 && k >= 0x80 && l >= 0x80) { return 4; } } } else if (i >= 0xE0) { if ((p + 1) < l) { unsigned char j = s[p]; unsigned char k = s[p + 1]; if (j >= 0x80 && k >= 0x80) { return 3; } } } else if (i >= 0xC0) { if (p < l) { unsigned char j = s[p]; if (j >= 0x80) { return 2; } } } return 0; } static inline size_t strlib_aux_toline(const char *s, size_t l, size_t p, size_t *b) { size_t i = p; while (i < l) { if (s[i] == 13) { if ((i + 1) < l) { if (s[i + 1] == 10) { *b = 2; /* cr lf */ } else { *b = 1; /* cr */ } } return i - p; } else if (s[i] == 10) { *b = 1; /* lf */ return i - p; } else { /* other */ i += 1; } } return i - p ; } /*tex End of helpers. */ static int strlib_aux_bytepairs(lua_State *L) { size_t ls = 0; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); size_t ind = lmt_tointeger(L, lua_upvalueindex(2)); if (ind < ls) { unsigned char i; /*tex iterator */ if (ind + 1 < ls) { lua_pushinteger(L, ind + 2); } else { lua_pushinteger(L, ind + 1); } lua_replace(L, lua_upvalueindex(2)); i = (unsigned char)*(s + ind); /*tex byte one */ lua_pushinteger(L, i); if (ind + 1 < ls) { /*tex byte two */ i = (unsigned char)*(s + ind + 1); lua_pushinteger(L, i); } else { /*tex odd string length */ lua_pushnil(L); } return 2; } else { return 0; } } static int strlib_bytepairs(lua_State *L) { luaL_checkstring(L, 1); lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, strlib_aux_bytepairs, 2); return 1; } static int strlib_aux_bytes(lua_State *L) { size_t ls = 0; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); size_t ind = lmt_tointeger(L, lua_upvalueindex(2)); if (ind < ls) { /*tex iterator */ lua_pushinteger(L, ind + 1); lua_replace(L, lua_upvalueindex(2)); /*tex byte */ lua_pushinteger(L, (unsigned char)*(s + ind)); return 1; } else { return 0; } } static int strlib_bytes(lua_State *L) { luaL_checkstring(L, 1); lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, strlib_aux_bytes, 2); return 1; } static int strlib_aux_utf_failed(lua_State *L, int new_ind) { lua_pushinteger(L, new_ind); lua_replace(L, lua_upvalueindex(2)); lua_pushliteral(L, utf_fffd_string); return 1; } /* kind of complex ... these masks */ static int strlib_aux_utfcharacters(lua_State *L) { static const unsigned char mask[4] = { 0x80, 0xE0, 0xF0, 0xF8 }; static const unsigned char mequ[4] = { 0x00, 0xC0, 0xE0, 0xF0 }; size_t ls = 0; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); size_t ind = lmt_tointeger(L, lua_upvalueindex(2)); size_t l = ls; if (ind >= l) { return 0; } else { unsigned char c = (unsigned char) s[ind]; for (size_t j = 0; j < 4; j++) { if ((c & mask[j]) == mequ[j]) { if (ind + 1 + j > l) { /*tex The result will not fit. */ return strlib_aux_utf_failed(L, (int) l); } for (size_t k = 1; k <= j; k++) { c = (unsigned char) s[ind + k]; if ((c & 0xC0) != 0x80) { /*tex We have a bad follow byte. */ return strlib_aux_utf_failed(L, (int) (ind + k)); } } /*tex The iterator. */ lua_pushinteger(L, ind + j + 1); lua_replace(L, lua_upvalueindex(2)); lua_pushlstring(L, ind + s, j + 1); return 1; } } return strlib_aux_utf_failed(L, (int) (ind + 1)); /* we found a follow byte! */ } } static int strlib_utfcharacters(lua_State *L) { luaL_checkstring(L, 1); lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, strlib_aux_utfcharacters, 2); return 1; } static int strlib_aux_utfvalues(lua_State *L) { size_t l = 0; const char *s = lua_tolstring(L, lua_upvalueindex(1), &l); size_t ind = lmt_tointeger(L, lua_upvalueindex(2)); if (ind < l) { int v = strlib_aux_tounicode(s, l, &ind); lua_pushinteger(L, ind); lua_replace(L, lua_upvalueindex(2)); lua_pushinteger(L, v); return 1; } else { return 0; } } static int strlib_utfvalues(lua_State *L) { luaL_checkstring(L, 1); lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, strlib_aux_utfvalues, 2); return 1; } static int strlib_aux_characterpairs(lua_State *L) { size_t ls = 0; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); size_t ind = lmt_tointeger(L, lua_upvalueindex(2)); if (ind < ls) { char b[1]; lua_pushinteger(L, ind + 2); /*tex So we can overshoot ls here. */ lua_replace(L, lua_upvalueindex(2)); b[0] = s[ind]; lua_pushlstring(L, b, 1); if ((ind + 1) < ls) { b[0] = s[ind + 1]; lua_pushlstring(L, b, 1); } else { lua_pushliteral(L, ""); } return 2; } else { return 0; /* string ended */ } } static int strlib_characterpairs(lua_State *L) { luaL_checkstring(L, 1); lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, strlib_aux_characterpairs, 2); return 1; } static int strlib_aux_characters(lua_State *L) { size_t ls = 0; const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); size_t ind = lmt_tointeger(L, lua_upvalueindex(2)); if (ind < ls) { char b[1]; lua_pushinteger(L, ind + 1); /* iterator */ lua_replace(L, lua_upvalueindex(2)); b[0] = *(s + ind); lua_pushlstring(L, b, 1); return 1; } else { return 0; /* string ended */ } } static int strlib_characters(lua_State *L) { luaL_checkstring(L, 1); lua_settop(L, 1); lua_pushinteger(L, 0); lua_pushcclosure(L, strlib_aux_characters, 2); return 1; } static int strlib_bytetable(lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); lua_createtable(L, (int) l, 0); for (size_t i = 0; i < l; i++) { lua_pushinteger(L, (unsigned char)*(s + i)); lua_rawseti(L, -2, i + 1); } return 1; } static int strlib_utfvaluetable(lua_State *L) { size_t n = 1; size_t l = 0; size_t p = 0; const char *s = luaL_checklstring(L, 1, &l); lua_createtable(L, (int) l, 0); while (p < l) { lua_pushinteger(L, strlib_aux_tounicode(s, l, &p)); lua_rawseti(L, -2, n++); } return 1; } static int strlib_utfcharactertable(lua_State *L) { size_t n = 1; size_t l = 0; size_t p = 0; const char *s = luaL_checklstring(L, 1, &l); lua_createtable(L, (int) l, 0); while (p < l) { int b = strlib_aux_tounichar(s, l, p); if (b) { lua_pushlstring(L, s + p, b); p += b; } else { lua_pushliteral(L, utf_fffd_string); p += 1; } lua_rawseti(L, -2, n++); } return 1; } static int strlib_linetable(lua_State *L) { size_t n = 1; size_t l = 0; size_t p = 0; const char *s = luaL_checklstring(L, 1, &l); lua_createtable(L, (int) l, 0); while (p < l) { size_t b = 0; size_t m = strlib_aux_toline(s, l, p, &b); if (m) { lua_pushlstring(L, s + p, m); } else { lua_pushliteral(L, ""); } p += m + b; lua_rawseti(L, -2, n++); } return 1; } /*tex We provide a few helpers that we derived from the lua utf8 module and slunicode. That way we're sort of covering a decent mix. */ # define MAXUNICODE 0x10FFFF /*tex This is a combination of slunicode and utf8 converters but without mode and a bit faster on the average than the utf8 one. The one character branch is a bit more efficient, as is preallocating the buffer size. */ static inline void strlib_aux_add_utfchar(luaL_Buffer *b, unsigned u) { if (u <= MAXUNICODE) { if (0x80 > u) { luaL_addchar(b, (unsigned char) u); } else { if (0x800 > u) luaL_addchar(b, (unsigned char) (0xC0 | (u >> 6))); else { if (0x10000 > u) luaL_addchar(b, (unsigned char) (0xE0 | (u >> 12))); else { luaL_addchar(b, (unsigned char) (0xF0 | (u >> 18))); luaL_addchar(b, (unsigned char) (0x80 | (0x3F & (u >> 12)))); } luaL_addchar(b, 0x80 | (0x3F & (u >> 6))); } luaL_addchar(b, 0x80 | (0x3F & u)); } } } static inline void strlib_aux_add_utfnumber(lua_State *L, luaL_Buffer *b, int index) { strlib_aux_add_utfchar(b, (unsigned) lmt_tounsigned(L, index)); } static inline void strlib_aux_add_utfstring(lua_State *L, luaL_Buffer *b, int index) { size_t ls = 0; const char *s = lua_tolstring(L, index, &ls); luaL_addlstring(b, s, ls); } static inline void strlib_aux_add_utftable(lua_State *L, luaL_Buffer *b, int index) { lua_Unsigned n = lua_rawlen(L, index); if (n > 0) { for (lua_Unsigned i = 1; i <= n; i++) { lua_rawgeti(L, index, i); switch (lua_type(L, -1)) { case LUA_TNUMBER: strlib_aux_add_utfnumber(L, b, -1); break; case LUA_TTABLE: strlib_aux_add_utftable(L, b, -1); break; case LUA_TSTRING: strlib_aux_add_utfstring(L, b, -1); break; } lua_pop(L, 1); } } } static int strlib_utfcharacter(lua_State *L) { int n = lua_gettop(L); if (n == 1 && lua_type(L, 1) == LUA_TNUMBER) { char u[6]; char *c = aux_uni2string(&u[0], (unsigned) lua_tointeger(L, 1)); *c = '\0'; lua_pushstring(L, u); return 1; } else { luaL_Buffer b; luaL_buffinitsize(L, &b, (size_t) n * 4); for (int i = 1; i <= n; i++) { switch (lua_type(L, i)) { case LUA_TNUMBER: strlib_aux_add_utfnumber(L, &b, i); break; case LUA_TTABLE: strlib_aux_add_utftable(L, &b, i); break; case LUA_TSTRING: strlib_aux_add_utfstring(L, &b, i); break; } } luaL_pushresult(&b); return 1; } } /*tex The \UTF8 codepoint function takes two arguments, being positions in the string, while slunicode byte takes two arguments representing the number of utf characters. The variant below always returns all codepoints. */ static int strlib_utfvalue(lua_State *L) { size_t l = 0; size_t p = 0; int i = 0; const char *s = luaL_checklstring(L, 1, &l); while (p < l) { lua_pushinteger(L, strlib_aux_tounicode(s, l, &p)); i++; } return i; } /*tex This is a simplified version of utf8.len but without range. */ static int strlib_utflength(lua_State *L) { size_t ls = 0; size_t ind = 0; size_t n = 0; const char *s = lua_tolstring(L, 1, &ls); while (ind < ls) { unsigned char i = (unsigned char) *(s + ind); if (i < 0x80) { ind += 1; } else if (i >= 0xF0) { ind += 4; } else if (i >= 0xE0) { ind += 3; } else if (i >= 0xC0) { ind += 2; } else { /*tex bad news, stupid recovery */ ind += 1; } n++; } lua_pushinteger(L, n); return 1; } /*tex A handy one that formats a float but also strips trailing zeros. */ static int strlib_format_f6(lua_State *L) { double n = luaL_optnumber(L, 1, 0.0); if (n == 0.0) { lua_pushliteral(L, "0"); } else if (n == 1.0) { lua_pushliteral(L, "1"); } else { char s[128]; int i, l; /* we could use sprintf here */ if (fmod(n, 1) == 0) { i = snprintf(s, 128, "%i", (int) n); } else { if (lua_type(L, 2) == LUA_TSTRING) { const char *f = lua_tostring(L, 2); i = snprintf(s, 128, f, n); } else { i = snprintf(s, 128, "%0.6f", n) ; } l = i - 1; while (l > 1) { if (s[l - 1] == '.') { break; } else if (s[l] == '0') { // s[l] = '\0'; /* redundant */ --i; } else { break; } l--; } } lua_pushlstring(L, s, i); } return 1; } /*tex The next one is mostly provided as check because doing it in pure \LUA\ is not slower and it's not a bottleneck anyway. There are soms subtle side effects when we don't check for these ranges, especially the trigger bytes (|0xD7FF| etc.) because we can get negative numbers which means wrapping around and such. */ static inline unsigned char strlib_aux_hexdigit(unsigned char n) { return (n < 10 ? '0' : 'A' - 10) + n; } # define invalid_unicode(u) ( \ (u >= 0x00E000 && u <= 0x00F8FF) || \ (u >= 0x0F0000 && u <= 0x0FFFFF) || \ (u >= 0x100000 && u <= 0x10FFFF) || \ /* (u >= 0x00D800 && u <= 0x00DFFF)) { */ \ (u >= 0x00D7FF && u <= 0x00DFFF) \ ) static int strlib_format_tounicode16(lua_State *L) { lua_Integer u = lua_tointeger(L, 1); if (invalid_unicode(u)) { lua_pushliteral(L, "FFFD"); } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { char s[4] ; s[3] = strlib_aux_hexdigit((unsigned char) ((u & 0x000F) >> 0)); s[2] = strlib_aux_hexdigit((unsigned char) ((u & 0x00F0) >> 4)); s[1] = strlib_aux_hexdigit((unsigned char) ((u & 0x0F00) >> 8)); s[0] = strlib_aux_hexdigit((unsigned char) ((u & 0xF000) >> 12)); lua_pushlstring(L, s, 4); } else { unsigned u1, u2; char s[8] ; u = u - 0x10000; /* negative when invalid range */ u1 = (unsigned) (u >> 10) + 0xD800; u2 = (unsigned) (u % 0x400) + 0xDC00; s[3] = strlib_aux_hexdigit((unsigned char) ((u1 & 0x000F) >> 0)); s[2] = strlib_aux_hexdigit((unsigned char) ((u1 & 0x00F0) >> 4)); s[1] = strlib_aux_hexdigit((unsigned char) ((u1 & 0x0F00) >> 8)); s[0] = strlib_aux_hexdigit((unsigned char) ((u1 & 0xF000) >> 12)); s[7] = strlib_aux_hexdigit((unsigned char) ((u2 & 0x000F) >> 0)); s[6] = strlib_aux_hexdigit((unsigned char) ((u2 & 0x00F0) >> 4)); s[5] = strlib_aux_hexdigit((unsigned char) ((u2 & 0x0F00) >> 8)); s[4] = strlib_aux_hexdigit((unsigned char) ((u2 & 0xF000) >> 12)); lua_pushlstring(L, s, 8); } return 1; } static int strlib_format_toutf8(lua_State *L) /* could be integrated into utfcharacter */ { if (lua_type(L, 1) == LUA_TTABLE) { lua_Integer n = lua_rawlen(L, 1); if (n > 0) { luaL_Buffer b; luaL_buffinitsize(L, &b, (n + 1) * 4); for (lua_Integer i = 0; i <= n; i++) { /* there should be one operation for getting a number from a table */ if (lua_rawgeti(L, 1, i) == LUA_TNUMBER) { unsigned u = (unsigned) lua_tointeger(L, -1); if (0x80 > u) { luaL_addchar(&b, (unsigned char) u); } else if (invalid_unicode(u)) { luaL_addchar(&b, 0xFF); luaL_addchar(&b, 0xFD); } else { if (0x800 > u) luaL_addchar(&b, (unsigned char) (0xC0 | (u >> 6))); else { if (0x10000 > u) luaL_addchar(&b, (unsigned char) (0xE0 | (u >> 12))); else { luaL_addchar(&b, (unsigned char) (0xF0 | (u >>18))); luaL_addchar(&b, (unsigned char) (0x80 | (0x3F & (u >> 12)))); } luaL_addchar(&b, 0x80 | (0x3F & (u >> 6))); } luaL_addchar(&b, 0x80 | (0x3F & u)); } } lua_pop(L, 1); } luaL_pushresult(&b); } else { lua_pushliteral(L, ""); } return 1; } return 0; } /* static int strlib_format_toutf16(lua_State* L) { if (lua_type(L, 1) == LUA_TTABLE) { lua_Integer n = lua_rawlen(L, 1); if (n > 0) { luaL_Buffer b; luaL_buffinitsize(L, &b, (n + 2) * 4); for (lua_Integer i = 0; i <= n; i++) { if (lua_rawgeti(L, 1, i) == LUA_TNUMBER) { unsigned u = (unsigned) lua_tointeger(L, -1); if (invalid_unicode(u)) { luaL_addchar(&b, 0xFF); luaL_addchar(&b, 0xFD); } else if (u < 0x10000) { luaL_addchar(&b, (unsigned char) ((u & 0x00FF) )); luaL_addchar(&b, (unsigned char) ((u & 0xFF00) >> 8)); } else { u = u - 0x10000; luaL_addchar(&b, (unsigned char) ((((u>>10)+0xD800) & 0x00FF) )); luaL_addchar(&b, (unsigned char) ((((u>>10)+0xD800) & 0xFF00) >> 8)); luaL_addchar(&b, (unsigned char) (( (u%1024+0xDC00) & 0x00FF) )); luaL_addchar(&b, (unsigned char) (( (u%1024+0xDC00) & 0xFF00) >> 8)); } } lua_pop(L, 1); } luaL_addchar(&b, 0); luaL_addchar(&b, 0); luaL_pushresult(&b); } else { lua_pushliteral(L, ""); } return 1; } return 0; } */ static int strlib_format_toutf32(lua_State *L) { if (lua_type(L, 1) == LUA_TTABLE) { lua_Integer n = lua_rawlen(L, 1); if (n > 0) { luaL_Buffer b; luaL_buffinitsize(L, &b, (n + 2) * 4); for (lua_Integer i = 0; i <= n; i++) { /* there should be one operation for getting a number from a table */ if (lua_rawgeti(L, 1, i) == LUA_TNUMBER) { unsigned u = (unsigned) lua_tointeger(L, -1); if (invalid_unicode(u)) { luaL_addchar(&b, 0x00); luaL_addchar(&b, 0x00); luaL_addchar(&b, 0xFF); luaL_addchar(&b, 0xFD); } else { luaL_addchar(&b, (unsigned char) ((u & 0x000000FF) )); luaL_addchar(&b, (unsigned char) ((u & 0x0000FF00) >> 8)); luaL_addchar(&b, (unsigned char) ((u & 0x00FF0000) >> 16)); luaL_addchar(&b, (unsigned char) ((u & 0xFF000000) >> 24)); } } lua_pop(L, 1); } for (int i = 0; i <= 3; i++) { luaL_addchar(&b, 0); } luaL_pushresult(&b); } else { lua_pushliteral(L, ""); } return 1; } return 0; } /* str, true : big endian str, false : little endian str, nil, true : check bom, default to big endian str, nil, false : check bom, default to little endian str, nil, nil : check bom, default to little endian */ static int strlib_utf16toutf8(lua_State *L) { size_t ls = 0; const char *s = lua_tolstring(L, 1, &ls); if (ls % 2) { --ls; } if (ls) { luaL_Buffer b; int more = 0; int be = 1; size_t i = 0; luaL_buffinitsize(L, &b, ls); /* unlikely to be larger if we have latin */ if (lua_type(L, 2) == LUA_TBOOLEAN) { be = lua_toboolean(L, 2); } else if (s[0] == '\xFE' && s[1] == '\xFF') { be = 1; i += 2; } else if (s[0] == '\xFF' && s[1] == '\xEF') { be = 0; i += 2; } else { be = lua_toboolean(L, 3); } while (i < ls) { unsigned char l = (unsigned char) s[i++]; unsigned char r = (unsigned char) s[i++]; unsigned now = be ? 256 * l + r : l + 256 * r; if (more) { now = (more - 0xD800) * 0x400 + (now - 0xDC00) + 0x10000; more = 0; strlib_aux_add_utfchar(&b, now); } else if (now >= 0xD800 && now <= 0xDBFF) { more = now; } else { strlib_aux_add_utfchar(&b, now); } } luaL_pushresult(&b); } else { lua_pushliteral(L, ""); } return 1; } // static char map[] = { // '0', '1', '2', '3', // '4', '5', '6', '7', // '8', '9', 'A', 'B', // 'C', 'D', 'E', 'F', // }; static int strlib_pack_rows_columns(lua_State* L) { if (lua_type(L, 1) == LUA_TTABLE) { lua_Integer rows = lua_rawlen(L, 1); if (lua_rawgeti(L, 1, 1) == LUA_TTABLE) { lua_Integer columns = lua_rawlen(L, -1); switch (lua_rawgeti(L, -1, 1)) { case LUA_TNUMBER: { lua_Integer size = rows * columns; unsigned char *result = lmt_memory_malloc(size); lua_pop(L, 2); /* row and cell */ if (result) { unsigned char *first = result; for (lua_Integer r = 1; r <= rows; r++) { if (lua_rawgeti(L, -1, r) == LUA_TTABLE) { for (lua_Integer c = 1; c <= columns; c++) { if (lua_rawgeti(L, -1, c) == LUA_TNUMBER) { lua_Integer v = lua_tointeger(L, -1); *result++ = v < 0 ? 0 : v > 255 ? 255 : (unsigned char) v; } else { *result++ = 0; } lua_pop(L, 1); } } lua_pop(L, 1); } lua_pushlstring(L, (char *) first, result - first); return 1; } } case LUA_TTABLE: { lua_Integer mode = lua_rawlen(L, -1); lua_Integer size = rows * columns * mode; unsigned char *result = lmt_memory_malloc(size); lua_pop(L, 2); /* row and cell */ if (result) { unsigned char *first = result; for (lua_Integer r = 1; r <= rows; r++) { if (lua_rawgeti(L, -1, r) == LUA_TTABLE) { for (lua_Integer c = 1; c <= columns; c++) { if (lua_rawgeti(L, -1, c) == LUA_TTABLE) { for (int i = 1; i <= mode; i++) { if (lua_rawgeti(L, -1, i) == LUA_TNUMBER) { lua_Integer v = lua_tointeger(L, -1); *result++ = v < 0 ? 0 : v > 255 ? 255 : (unsigned char) v; } else { *result++ = 0; } lua_pop(L, 1); } } lua_pop(L, 1); } } lua_pop(L, 1); } lua_pushlstring(L, (char *) first, result - first); return 1; } } } } } lua_pushnil(L); return 1; } /*tex This converts a hex string to characters. Spacing is ignored and invalid characters result in a false result. Empty strings are okay. */ static int strlib_hextocharacters(lua_State *L) { size_t ls = 0; const char *s = lua_tolstring(L, 1, &ls); if (ls > 0) { luaL_Buffer b; luaL_buffinitsize(L, &b, ls/2); while (1) { unsigned char first = *s++; switch (first) { case ' ': case '\n': case '\r': case '\t': continue; case '\0': goto DONE; default: { unsigned char second = *s++; switch (second) { case ' ': case '\n': case '\r': case '\t': continue; case '\0': goto BAD; default: { unsigned char chr; if (first >= '0' && first <= '9') { chr = 16 * (first - '0'); } else if (first>= 'A' && first <= 'F') { chr = 16 * (first - 'A' + 10); } else if (first >= 'a' && first <= 'f') { chr = 16 * (first - 'a' + 10); } else { goto BAD; } if (second >= '0' && second <= '9') { chr += second - '0'; } else if (second >= 'A' && second <= 'F') { chr += second - 'A' + 10; } else if (second >= 'a' && second <= 'f') { chr += second - 'a' + 10; } else { goto BAD; } luaL_addchar(&b, chr); break; } } break; } } } DONE: luaL_pushresult(&b); return 1; BAD: lua_pushboolean(L, 0); return 1; } else { lua_pushliteral(L, ""); return 1; } } static int strlib_octtointeger(lua_State *L) { const char *s = lua_tostring(L, 1); // lua_Integer n = 0; // int negate = *s == '-'; // if (negate) { // s++; // } // while (*s && n < 0xFFFFFFFF) { /* large enough */ // if (*s >= '0' && *s <= '7') { // n = n * 8 + *s - '0'; // } else { // break; // } // s++; // } // lua_pushinteger(L, negate ? -n : n); lua_pushinteger(L, strtoul(s, NULL, 8)); return 1; } static int strlib_dectointeger(lua_State *L) { const char *s = lua_tostring(L, 1); // lua_Integer n = 0; // int negate = *s == '-'; // if (negate) { // s++; // } // while (*s && n < 0xFFFFFFFF) { /* large enough */ // if (*s >= '0' && *s <= '9') { // n = n * 10 + *s - '0'; // } else { // break; // } // s++; // } // lua_pushinteger(L, negate ? -n : n); // lua_pushinteger(L, atol(s)); lua_pushinteger(L, strtoul(s, NULL, 10)); return 1; } static int strlib_hextointeger(lua_State *L) { const char *s = lua_tostring(L, 1); // lua_Integer n = 0; // int negate = *s == '-'; // if (negate) { // s++; // } // while (*s && n < 0xFFFFFFFF) { /* large enough */ // if (*s >= '0' && *s <= '9') { // n = n * 16 + *s - '0'; // } else if (*s >= 'A' && *s <= 'F') { // n = n * 16 + *s - 'A' + 10; // } else if (*s >= 'a' && *s <= 'f') { // n = n * 16 + *s - 'a' + 10; // } else { // break; // } // s++; // } // lua_pushinteger(L, negate ? -n : n); lua_pushinteger(L, strtoul(s, NULL, 16)); return 1; } static int strlib_chrtointeger(lua_State *L) { lua_Integer n = 0; size_t l = 0; const char *s = lua_tolstring(L, 1, &l); if (l > 0) { size_t p = 0; while (p < l && n < 0xFFFFFFFF) { /* large enough */ n = n * 255 + (unsigned char) s[p]; p++; } lua_pushinteger(L, n); } return 1; } static const luaL_Reg strlib_function_list[] = { { "characters", strlib_characters }, { "characterpairs", strlib_characterpairs }, { "bytes", strlib_bytes }, { "bytepairs", strlib_bytepairs }, { "bytetable", strlib_bytetable }, { "linetable", strlib_linetable }, { "utfvalues", strlib_utfvalues }, { "utfcharacters", strlib_utfcharacters }, { "utfcharacter", strlib_utfcharacter }, { "utfvalue", strlib_utfvalue }, { "utflength", strlib_utflength }, { "utfvaluetable", strlib_utfvaluetable }, { "utfcharactertable", strlib_utfcharactertable }, { "f6", strlib_format_f6 }, { "tounicode16", strlib_format_tounicode16 }, { "toutf8", strlib_format_toutf8 }, /* { "toutf16", strlib_format_toutf16 }, */ /* untested */ { "toutf32", strlib_format_toutf32 }, { "utf16toutf8", strlib_utf16toutf8 }, { "packrowscolumns", strlib_pack_rows_columns }, { "hextocharacters", strlib_hextocharacters }, { "octtointeger", strlib_octtointeger }, { "dectointeger", strlib_dectointeger }, { "hextointeger", strlib_hextointeger }, { "chrtointeger", strlib_chrtointeger }, { NULL, NULL }, }; /* The next (old, moved here) experiment was used to check if using some buffer is more efficient than using a table that we concat. It makes no difference. If we ever use this, the initializer |luaextend_string_buffer| will be merged into |luaextend_string|. We could gain a little on a bit more efficient |luaL_checkudata| as we use elsewhere because in practice (surprise) its overhead makes buffers like this {\em 50 percent} slower than the concatinated variant and twice as slow when we reuse a temporary table. It's just better to stay at the \LUA\ end. Replacing the userdata test with a dedicated test gives a speed boost but we're still some {\em 10 percent} slower. So, for now we comment this feature. */ # if (0) typedef struct lmt_string_buffer { char *buffer; size_t length; size_t size; size_t step; } lmt_string_buffer; static lmt_string_buffer *strlib_buffer_instance(lua_State *L) { lmt_string_buffer *b = (lmt_string_buffer *) lua_touserdata(L, 1); if (b && lua_getmetatable(L, 1)) { lua_get_metatablelua(string_buffer_instance); if (! lua_rawequal(L, -1, -2)) { b = NULL; } else if (! b->buffer) { b = NULL; } lua_pop(L, 2); return b; } return NULL; } static int strlib_buffer_gc(lua_State *L) { lmt_string_buffer *b = strlib_buffer_instance(L); if (b) { lmt_memory_free(b->buffer); } return 0; } static int strlib_buffer_new(lua_State *L) { size_t size = lmt_optsizet(L, 1, LUAL_BUFFERSIZE); size_t step = lmt_optsizet(L, 2, size); lmt_string_buffer *b = (lmt_string_buffer *) lua_newuserdatauv(L, sizeof(lmt_string_buffer), 0); b->buffer = lmt_memory_malloc(size); b->size = size; b->step = step; b->length = 0; lua_get_metatablelua(string_buffer_instance); lua_setmetatable(L, -2); return 1; } static int strlib_buffer_add(lua_State *L) { lmt_string_buffer *b = strlib_buffer_instance(L); if (b) { switch (lua_type(L, 2)) { case LUA_TSTRING: case LUA_TNUMBER: { size_t l; const char *s = lua_tolstring(L, 2, &l); size_t length = b->length + l; if (length >= b->size) { while (length >= b->size) { b->size += b->step; } b->buffer = lmt_memory_realloc(b->buffer, b->size); } memcpy(&b->buffer[b->length], s, l); b->length = length; } break; default: break; } } return 0; } static int strlib_buffer_get_data(lua_State *L) { lmt_string_buffer *b = strlib_buffer_instance(L); if (b) { lua_pushlstring(L, b->buffer, b->length); lua_pushinteger(L, (int) b->length); return 2; } else { lua_pushnil(L); return 1; } } static int strlib_buffer_get_size(lua_State *L) { lmt_string_buffer *b = strlib_buffer_instance(L); lua_pushinteger(L, b ? b->length : 0); return 1; } static const luaL_Reg strlib_function_list_buffer[] = { { "newbuffer", strlib_buffer_new }, { "addtobuffer", strlib_buffer_add }, { "getbufferdata", strlib_buffer_get_data }, { "getbuffersize", strlib_buffer_get_size }, { NULL, NULL }, }; static int luaextend_string_buffer(lua_State *L) { lua_getglobal(L, "string"); for (const luaL_Reg *lib = strlib_function_list_buffer; lib->name; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); } lua_pop(L, 1); luaL_newmetatable(L, STRING_BUFFER_INSTANCE); lua_pushcfunction(L, strlib_buffer_gc); lua_setfield(L, -2, "__gc"); lua_pop(L, 1); return 1; } # else static int luaextend_string_buffer(lua_State *L) { (void) L; return 0; } # endif int luaextend_string(lua_State * L) { lua_getglobal(L, "string"); for (const luaL_Reg *lib = strlib_function_list; lib->name; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); } lua_pop(L, 1); luaextend_string_buffer(L); return 1; } luametatex-2.11.08/source/luarest/lmttablibext.c0000644000175000017500000000536015063273560020641 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" static int tablib_keys(lua_State *L) { int category = 0; // 0=unknown 1=string 2=number 3=mixed lua_settop(L, 1); lua_createtable(L, 0, 0); if (lua_type(L, 1) == LUA_TTABLE) { int index = 0; lua_pushnil(L); while (lua_next(L, -3)) { int tkey = lua_type(L, -2); /* key at -2, value at -1 */ if (category != 3) { if (category == 1) { if (tkey != LUA_TSTRING) { category = 3; } } else if (category == 2) { if (tkey != LUA_TNUMBER) { category = 3; } } else { if (tkey == LUA_TSTRING) { category = 1; } else if (tkey == LUA_TNUMBER) { category = 2; } else { category = 3; } } } lua_pushvalue(L, -2); lua_rawseti(L, 2, ++index); lua_pop(L, 1); /* key kept for next iteration */ } } lua_pushinteger(L, category); return 2; } /* local function get(t,n) local min = 1 local max = #t while min <= max do local mid = min + (max - min) // 2 if t[mid] == n then return mid elseif t[mid] < n then min = mid + 1 else max = mid - 1 end end return nil end */ static int tablib_binsearch(lua_State *L) { if (lua_type(L, 1) == LUA_TTABLE) { lua_Integer val = lua_tointeger(L, 2); lua_Unsigned min = 1; lua_Unsigned max = lua_rawlen(L, 1); while (min <= max) { lua_Unsigned mid = min + (max - min) / 2; if (lua_rawgeti(L, 1, mid) == LUA_TNUMBER) { lua_Integer tmp = lua_tointeger(L, -1); lua_pop(L, 1); if (tmp == val) { lua_pushinteger(L, mid); return 1; } else if (tmp < val) { min = mid + 1; } else { max = mid - 1; } } } } lua_pushnil(L); return 1; } static const luaL_Reg tablib_function_list[] = { { "getkeys", tablib_keys }, { "binsearch", tablib_binsearch }, { NULL, NULL }, }; int luaextend_table(lua_State * L) { lua_getglobal(L, "table"); for (const luaL_Reg *lib = tablib_function_list; lib->name; lib++) { lua_pushcfunction(L, lib->func); lua_setfield(L, -2, lib->name); } lua_pop(L, 1); return 1; } luametatex-2.11.08/source/luarest/lmtxmathlib.c0000644000175000017500000003040115063273560020465 0ustar hillehille/* See license.txt in the root of this project. This is a reformatted and slightly adapted version of lmathx.c: title : C99 math functions for Lua 5.3+ author : Luiz Henrique de Figueiredo date : 24 Jun 2015 09:51:50 licence: This code is hereby placed in the public domain. In the end I just expanded and adapted the code a bit which made it easier to get rid of some compiler warnings (if possible at all). */ # include "luametatex.h" # include # define xmathlib_pi ((lua_Number)(3.141592653589793238462643383279502884)) # define xmathlib_180 ((lua_Number) 180.0) # define xmathlib_inf ((lua_Number) INFINITY) # define xmathlib_nan ((lua_Number) NAN) static int xmathlib_acos(lua_State *L) { lua_pushnumber(L, (lua_Number) acos(luaL_checknumber(L, 1))); return 1; } static int xmathlib_acosh(lua_State *L) { lua_pushnumber(L, (lua_Number) acosh(luaL_checknumber(L, 1))); return 1; } static int xmathlib_asin(lua_State *L) { lua_pushnumber(L, (lua_Number) asin(luaL_checknumber(L, 1))); return 1; } static int xmathlib_asinh(lua_State *L) { lua_pushnumber(L, (lua_Number) asinh(luaL_checknumber(L, 1))); return 1; } static int xmathlib_atan(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushnumber(L, (lua_Number) atan(luaL_checknumber(L, 1))); } else { lua_pushnumber(L, (lua_Number) atan2(luaL_checknumber(L, 1),luaL_checknumber(L, 2))); } return 1; } static int xmathlib_atan2(lua_State *L) { lua_pushnumber(L, (lua_Number) atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_atanh(lua_State *L) { lua_pushnumber(L, (lua_Number) atanh(luaL_checknumber(L, 1))); return 1; } static int xmathlib_cbrt(lua_State *L) { lua_pushnumber(L, (lua_Number) cbrt(luaL_checknumber(L, 1))); return 1; } static int xmathlib_ceil(lua_State *L) { lua_pushnumber(L, (lua_Number) ceil(luaL_checknumber(L, 1))); return 1; } static int xmathlib_copysign (lua_State *L) { lua_pushnumber(L, (lua_Number) copysign(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_cos(lua_State *L) { lua_pushnumber(L, (lua_Number) cos(luaL_checknumber(L, 1))); return 1; } static int xmathlib_cosh(lua_State *L) { lua_pushnumber(L, (lua_Number) cosh(luaL_checknumber(L, 1))); return 1; } static int xmathlib_deg(lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1) * (xmathlib_180 / xmathlib_pi)); return 1; } static int xmathlib_erf(lua_State *L) { lua_pushnumber(L, (lua_Number) erf(luaL_checknumber(L, 1))); return 1; } static int xmathlib_erfc(lua_State *L) { lua_pushnumber(L, (lua_Number) erfc(luaL_checknumber(L, 1))); return 1; } static int xmathlib_exp(lua_State *L) { lua_pushnumber(L, (lua_Number) exp(luaL_checknumber(L, 1))); return 1; } static int xmathlib_exp2(lua_State *L) { lua_pushnumber(L, (lua_Number) exp2(luaL_checknumber(L, 1))); return 1; } static int xmathlib_expm1(lua_State *L) { lua_pushnumber(L, (lua_Number) expm1(luaL_checknumber(L, 1))); return 1; } static int xmathlib_fabs(lua_State *L) { lua_pushnumber(L, (lua_Number) fabs(luaL_checknumber(L, 1))); return 1; } static int xmathlib_fdim(lua_State *L) { lua_pushnumber(L, (lua_Number) fdim(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_floor(lua_State *L) { lua_pushnumber(L, (lua_Number) floor(luaL_checknumber(L, 1))); return 1; } static int xmathlib_fma(lua_State *L) { lua_pushnumber(L, (lua_Number) fma(luaL_checknumber(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3))); return 1; } static int xmathlib_fmax(lua_State *L) { int n = lua_gettop(L); lua_Number m = luaL_checknumber(L, 1); for (int i = 2; i <= n; i++) { m = (lua_Number) fmax(m, luaL_checknumber(L, i)); } lua_pushnumber(L, m); return 1; } static int xmathlib_fmin(lua_State *L) { int n = lua_gettop(L); lua_Number m = luaL_checknumber(L, 1); for (int i = 2; i <= n; i++) { m = (lua_Number) fmin(m, luaL_checknumber(L, i)); } lua_pushnumber(L, m); return 1; } static int xmathlib_fmod(lua_State *L) { lua_pushnumber(L, (lua_Number) fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_frexp(lua_State *L) { int e; lua_pushnumber(L, (lua_Number) frexp(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int xmathlib_fremquo(lua_State *L) { int e; lua_pushnumber(L, (lua_Number) remquo(luaL_checknumber(L, 1),luaL_checknumber(L, 2), &e)); lua_pushinteger(L, e); return 2; } static int xmathlib_gamma(lua_State *L) { lua_pushnumber(L, (lua_Number) tgamma(luaL_checknumber(L, 1))); return 1; } static int xmathlib_hypot(lua_State *L) { lua_pushnumber(L, hypot(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_isfinite(lua_State *L) { lua_pushboolean(L, isfinite(luaL_checknumber(L, 1))); return 1; } static int xmathlib_isinf(lua_State *L) { lua_pushboolean(L, isinf(luaL_checknumber(L, 1))); return 1; } static int xmathlib_isnan(lua_State *L) { lua_pushboolean(L, isnan(luaL_checknumber(L, 1))); return 1; } static int xmathlib_isnormal (lua_State *L) { lua_pushboolean(L, isnormal(luaL_checknumber(L, 1))); return 1; } static int xmathlib_j0(lua_State *L) { lua_pushnumber(L, (lua_Number) j0(luaL_checknumber(L, 1))); return 1; } static int xmathlib_j1(lua_State *L) { lua_pushnumber(L, (lua_Number) j1(luaL_checknumber(L, 1))); return 1; } static int xmathlib_jn(lua_State *L) { lua_pushnumber(L, (lua_Number) jn((int) luaL_checkinteger(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_ldexp(lua_State *L) { lua_pushnumber(L, (lua_Number) ldexp(luaL_checknumber(L, 1), (int) luaL_checkinteger(L, 2))); return 1; } static int xmathlib_lgamma(lua_State *L) { lua_pushnumber (L, (lua_Number) lgamma(luaL_checknumber(L, 1))); return 1; } static int xmathlib_log(lua_State *L) { if (lua_gettop(L) == 1) { lua_pushnumber(L, (lua_Number) log(luaL_checknumber(L, 1))); } else { lua_Number n = luaL_checknumber(L, 2); if (n == 10.0) { n = (lua_Number) log10(luaL_checknumber(L, 1)); } else if (n == 2.0) { n = (lua_Number) log2(luaL_checknumber(L, 1)); } else { n = (lua_Number) log(luaL_checknumber(L, 1)) / (lua_Number) log(n); } lua_pushnumber(L, n); } return 1; } static int xmathlib_log10(lua_State *L) { lua_pushnumber(L, (lua_Number) log10(luaL_checknumber(L, 1))); return 1; } static int xmathlib_log1p(lua_State *L) { lua_pushnumber(L, (lua_Number) log1p(luaL_checknumber(L, 1))); return 1; } static int xmathlib_log2(lua_State *L) { lua_pushnumber(L, (lua_Number) log2(luaL_checknumber(L, 1))); return 1; } static int xmathlib_logb(lua_State *L) { lua_pushnumber(L, (lua_Number) logb(luaL_checknumber(L, 1))); return 1; } static int xmathlib_modf(lua_State *L) { lua_Number ip; lua_Number fp = (lua_Number) modf(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int xmathlib_nearbyint(lua_State *L) { lua_pushnumber(L, (lua_Number) nearbyint(luaL_checknumber(L, 1))); return 1; } static int xmathlib_nextafter(lua_State *L) { lua_pushnumber(L, (lua_Number) nextafter(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_pow(lua_State *L) { lua_pushnumber(L, (lua_Number) pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_rad(lua_State *L) { lua_pushnumber(L, (luaL_checknumber(L, 1) * (xmathlib_pi / xmathlib_180))); return 1; } static int xmathlib_remainder(lua_State *L) { lua_pushnumber(L, (lua_Number) remainder(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int xmathlib_round(lua_State *L) { lua_pushinteger(L, lround(luaL_checknumber(L, 1))); return 1; } static int xmathlib_scalbn(lua_State *L) { lua_pushnumber(L, (lua_Number) scalbn(luaL_checknumber(L, 1), (int) luaL_checkinteger(L, 2))); return 1; } static int xmathlib_sin(lua_State *L) { lua_pushnumber(L, (lua_Number) sin(luaL_checknumber(L, 1))); return 1; } static int xmathlib_sinh(lua_State *L) { lua_pushnumber(L, (lua_Number) sinh(luaL_checknumber(L, 1))); return 1; } static int xmathlib_sqrt(lua_State *L) { lua_pushnumber(L, (lua_Number) sqrt(luaL_checknumber(L, 1))); return 1; } static int xmathlib_tan(lua_State *L) { lua_pushnumber(L, (lua_Number) tan(luaL_checknumber(L, 1))); return 1; } static int xmathlib_tanh(lua_State *L) { lua_pushnumber(L, (lua_Number) tanh(luaL_checknumber(L, 1))); return 1; } static int xmathlib_tgamma(lua_State *L) { lua_pushnumber(L, (lua_Number) tgamma(luaL_checknumber(L, 1))); return 1; } static int xmathlib_trunc(lua_State *L) { lua_pushnumber(L, (lua_Number) trunc(luaL_checknumber(L, 1))); return 1; } static int xmathlib_y0(lua_State *L) { lua_pushnumber(L, (lua_Number) y0(luaL_checknumber(L, 1))); return 1; } static int xmathlib_y1(lua_State *L) { lua_pushnumber(L, y1(luaL_checknumber(L, 1))); return 1; } static int xmathlib_yn(lua_State *L) { lua_pushnumber(L, yn((int) luaL_checkinteger(L, 1), luaL_checknumber(L, 2))); return 1; } static const luaL_Reg xmathlib_function_list[] = { { "acos", xmathlib_acos }, { "acosh", xmathlib_acosh }, { "asin", xmathlib_asin }, { "asinh", xmathlib_asinh }, { "atan", xmathlib_atan }, { "atan2", xmathlib_atan2 }, { "atanh", xmathlib_atanh }, { "cbrt", xmathlib_cbrt }, { "ceil", xmathlib_ceil }, { "copysign", xmathlib_copysign }, { "cos", xmathlib_cos }, { "cosh", xmathlib_cosh }, { "deg", xmathlib_deg }, { "erf", xmathlib_erf }, { "erfc", xmathlib_erfc }, { "exp", xmathlib_exp }, { "exp2", xmathlib_exp2 }, { "expm1", xmathlib_expm1 }, { "fabs", xmathlib_fabs }, { "fdim", xmathlib_fdim }, { "floor", xmathlib_floor }, { "fma", xmathlib_fma }, { "fmax", xmathlib_fmax }, { "fmin", xmathlib_fmin }, { "fmod", xmathlib_fmod }, { "frexp", xmathlib_frexp }, { "gamma", xmathlib_gamma }, { "hypot", xmathlib_hypot }, { "isfinite", xmathlib_isfinite }, { "isinf", xmathlib_isinf }, { "isnan", xmathlib_isnan }, { "isnormal", xmathlib_isnormal }, { "j0", xmathlib_j0 }, { "j1", xmathlib_j1 }, { "jn", xmathlib_jn }, { "ldexp", xmathlib_ldexp }, { "lgamma", xmathlib_lgamma }, { "log", xmathlib_log }, { "log10", xmathlib_log10 }, { "log1p", xmathlib_log1p }, { "log2", xmathlib_log2 }, { "logb", xmathlib_logb }, { "modf", xmathlib_modf }, { "nearbyint", xmathlib_nearbyint }, { "nextafter", xmathlib_nextafter }, { "pow", xmathlib_pow }, { "rad", xmathlib_rad }, { "remainder", xmathlib_remainder }, { "remquo", xmathlib_fremquo }, { "round", xmathlib_round }, { "scalbn", xmathlib_scalbn }, { "sin", xmathlib_sin }, { "sinh", xmathlib_sinh }, { "sqrt", xmathlib_sqrt }, { "tan", xmathlib_tan }, { "tanh", xmathlib_tanh }, { "tgamma", xmathlib_tgamma }, { "trunc", xmathlib_trunc }, { "y0", xmathlib_y0 }, { "y1", xmathlib_y1 }, { "yn", xmathlib_yn }, { NULL, NULL }, }; int luaopen_xmath(lua_State *L) { luaL_newlib(L, xmathlib_function_list); lua_pushnumber(L, xmathlib_inf); lua_setfield(L, -2, "inf"); lua_pushnumber(L, xmathlib_nan); lua_setfield(L, -2, "nan"); lua_pushnumber(L, xmathlib_pi); lua_setfield(L, -2, "pi"); return 1; } luametatex-2.11.08/source/luarest/lmtxcomplexlib.c0000644000175000017500000002517215063273560021214 0ustar hillehille/* See license.txt in the root of this project. This is a reformatted and slightly adapted version of lcomplex.c: title : C99 complex numbers for Lua 5.3+ author : Luiz Henrique de Figueiredo date : 26 Jul 2018 17:57:06 licence: This code is hereby placed in the public domain and also under the MIT license That implementation doesn't work for MSVC so I rewrote the code to support the microsoft compiler. I no longer use the macro approach to save bytes because with expanded code it is easier to get rid of some compiler warnings (if possible at all). In an optional module we hook the error functions into the complex library. Note: Alan has to test if all works okay. */ # include "luametatex.h" # include # define COMPLEX_METATABLE "complex number" # if (_MSC_VER) /*tex Instead of the somewhat strange two-doubles-in-a-row hack in C the microsoft vatiant uses structs. Here we use the double variant. */ # define Complex _Dcomplex static inline Complex xcomplexlib_get(lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TUSERDATA: return *((Complex*) luaL_checkudata(L, i, COMPLEX_METATABLE)); case LUA_TNUMBER: case LUA_TSTRING: return _Cbuild(luaL_checknumber(L, i), 0); default: return _Cbuild(0, 0); } } # else /*tex Here we use the two-doubles-in-a-row variant. */ # define Complex double complex static inline Complex xcomplexlib_get(lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TUSERDATA: return *((Complex*)luaL_checkudata(L, i, COMPLEX_METATABLE)); case LUA_TNUMBER: case LUA_TSTRING: return luaL_checknumber(L, i); default: return 0; } } # endif static inline int xcomplexlib_push(lua_State *L, Complex z) { Complex *p = lua_newuserdatauv(L, sizeof(Complex), 0); luaL_setmetatable(L, COMPLEX_METATABLE); *p = z; return 1; } # if (_MSC_VER) static int xcomplexlib_new(lua_State *L) { xcomplexlib_push(L, _Cbuild(0, 0)); return 1; } static int xcomplexlib_inew(lua_State *L) { xcomplexlib_push(L, _Cbuild(0, 1)); return 1; } static int xcomplexlib_eq(lua_State *L) { Complex a = xcomplexlib_get(L, 1); Complex b = xcomplexlib_get(L, 2); lua_pushboolean(L, creal(a) == creal(b) && cimag(a) == cimag(b)); return 1; } static int xcomplexlib_add(lua_State *L) { Complex a = xcomplexlib_get(L, 1); Complex b = xcomplexlib_get(L, 2); return xcomplexlib_push(L, _Cbuild(creal(a) + creal(b), cimag(a) + cimag(b))); } static int xcomplexlib_sub(lua_State *L) { Complex a = xcomplexlib_get(L, 1); Complex b = xcomplexlib_get(L, 2); return xcomplexlib_push(L, _Cbuild(creal(a) - creal(b), cimag(a) - cimag(b))); } static int xcomplexlib_neg(lua_State *L) { Complex a = xcomplexlib_get(L, 1); return xcomplexlib_push(L, _Cbuild(-creal(a), -cimag(a))); } static int xcomplexlib_div(lua_State *L) { Complex b = xcomplexlib_get(L, 2); if (creal(b) == 0.0 || cimag(b) == 0.0) { return 0; } else { Complex a = xcomplexlib_get(L, 1); Complex t = { 1 / creal(b), 1 / cimag(b) }; return xcomplexlib_push(L, _Cmulcc(a, t)); } } static int xcomplexlib_mul(lua_State *L) { Complex a = xcomplexlib_get(L, 1); Complex b = xcomplexlib_get(L, 2); return xcomplexlib_push(L, _Cmulcc(a, b)); } # else static int xcomplexlib_new(lua_State *L) { return xcomplexlib_push(L, luaL_optnumber(L, 1, 0) + luaL_optnumber(L, 2, 0) * I); } static int xcomplexlib_inew(lua_State *L) { return xcomplexlib_push(L, I); } static int xcomplexlib_eq(lua_State *L) { lua_pushboolean(L, xcomplexlib_get(L, 1) == xcomplexlib_get(L, 2)); return 1; } static int xcomplexlib_add(lua_State *L) { return xcomplexlib_push(L, xcomplexlib_get(L, 1) + xcomplexlib_get(L, 2)); } static int xcomplexlib_sub(lua_State *L) { return xcomplexlib_push(L, xcomplexlib_get(L, 1) - xcomplexlib_get(L, 2)); } static int xcomplexlib_neg(lua_State *L) { return xcomplexlib_push(L, - xcomplexlib_get(L, 1)); } static int xcomplexlib_div(lua_State *L) { return xcomplexlib_push(L, xcomplexlib_get(L, 1) / xcomplexlib_get(L, 2)); } static int xcomplexlib_mul(lua_State *L) { return xcomplexlib_push(L, xcomplexlib_get(L, 1) * xcomplexlib_get(L, 2)); } # endif static int xcomplexlib_abs(lua_State *L) { lua_pushnumber(L, (lua_Number) cabs(xcomplexlib_get(L, 1))); return 1; } static int xcomplexlib_acos(lua_State *L) { return xcomplexlib_push(L, cacos(xcomplexlib_get(L, 1))); } static int xcomplexlib_acosh(lua_State *L) { return xcomplexlib_push(L, cacosh(xcomplexlib_get(L, 1))); } static int xcomplexlib_arg(lua_State *L) { lua_pushnumber(L, (lua_Number) carg(xcomplexlib_get(L, 1))); return 1; } static int xcomplexlib_asin(lua_State *L) { return xcomplexlib_push(L, casin(xcomplexlib_get(L, 1))); } static int xcomplexlib_asinh(lua_State *L) { return xcomplexlib_push(L, casinh(xcomplexlib_get(L, 1))); } static int xcomplexlib_atan(lua_State *L) { return xcomplexlib_push(L, catan(xcomplexlib_get(L, 1))); } static int xcomplexlib_atanh(lua_State *L) { return xcomplexlib_push(L, catanh(xcomplexlib_get(L, 1))); } static int xcomplexlib_cos(lua_State *L) { return xcomplexlib_push(L, ccos(xcomplexlib_get(L, 1))); } static int xcomplexlib_cosh(lua_State *L) { return xcomplexlib_push(L, ccosh(xcomplexlib_get(L, 1))); } static int xcomplexlib_exp(lua_State *L) { xcomplexlib_push(L, cexp(xcomplexlib_get(L, 1))); return 1; } static int xcomplexlib_imag(lua_State *L) { lua_pushnumber(L, (lua_Number) (cimag)(xcomplexlib_get(L, 1))); return 1; } static int xcomplexlib_log(lua_State *L) { return xcomplexlib_push(L, clog(xcomplexlib_get(L, 1))); } static int xcomplexlib_pow(lua_State *L) { return xcomplexlib_push(L, cpow(xcomplexlib_get(L, 1), xcomplexlib_get(L, 2))); } static int xcomplexlib_proj(lua_State *L) { return xcomplexlib_push(L, cproj(xcomplexlib_get(L, 1))); } static int xcomplexlib_real(lua_State *L) { lua_pushnumber(L, (lua_Number) creal(xcomplexlib_get(L, 1))); return 1; } static int xcomplexlib_sin(lua_State *L) { return xcomplexlib_push(L, csin(xcomplexlib_get(L, 1))); } static int xcomplexlib_sinh(lua_State *L) { return xcomplexlib_push(L, csinh(xcomplexlib_get(L, 1))); } static int xcomplexlib_sqrt(lua_State *L) { return xcomplexlib_push(L, csqrt(xcomplexlib_get(L, 1))); } static int xcomplexlib_tan(lua_State *L) { return xcomplexlib_push(L, ctan(xcomplexlib_get(L, 1))); } static int xcomplexlib_tanh(lua_State *L) { return xcomplexlib_push(L, ctanh(xcomplexlib_get(L, 1))); } /*tex A few convenience functions: */ static int xcomplexlib_tostring(lua_State *L) { Complex z = xcomplexlib_get(L, 1); lua_Number x = creal(z); lua_Number y = cimag(z); lua_settop(L, 0); if (x != 0.0 || y == 0.0) { lua_pushnumber(L, x); } if (y != 0.0) { if (y == 1.0) { if (x != 0.0) { lua_pushliteral(L, "+"); } } else if (y == -1.0) { lua_pushliteral(L, "-"); } else { if (y > 0.0 && x != 0.0) { lua_pushliteral(L, "+"); } lua_pushnumber(L, y); } lua_pushliteral(L, "i"); } lua_concat(L, lua_gettop(L)); return 1; } static int xcomplexlib_topair(lua_State *L) { Complex z = xcomplexlib_get(L, 1); lua_pushnumber(L, (lua_Number) creal(z)); lua_pushnumber(L, (lua_Number) cimag(z)); return 2; } static int xcomplexlib_totable(lua_State *L) { Complex z = xcomplexlib_get(L, 1); lua_createtable(L, 2, 0); lua_pushnumber(L, (lua_Number) creal(z)); lua_pushnumber(L, (lua_Number) cimag(z)); lua_rawseti(L, -3, 1); lua_rawseti(L, -3, 2); return 1; } /*tex Now we assemble the library: */ static const struct luaL_Reg xcomplexlib_function_list[] = { /* management */ { "new", xcomplexlib_new }, { "tostring", xcomplexlib_tostring }, { "topair", xcomplexlib_topair }, { "totable", xcomplexlib_totable }, { "i", xcomplexlib_inew }, /* operators */ { "__add", xcomplexlib_add }, { "__div", xcomplexlib_div }, { "__eq", xcomplexlib_eq }, { "__mul", xcomplexlib_mul }, { "__sub", xcomplexlib_sub }, { "__unm", xcomplexlib_neg }, { "__pow", xcomplexlib_pow }, /* functions */ { "abs", xcomplexlib_abs }, { "acos", xcomplexlib_acos }, { "acosh", xcomplexlib_acosh }, { "arg", xcomplexlib_arg }, { "asin", xcomplexlib_asin }, { "asinh", xcomplexlib_asinh }, { "atan", xcomplexlib_atan }, { "atanh", xcomplexlib_atanh }, { "conj", xcomplexlib_neg }, { "cos", xcomplexlib_cos }, { "cosh", xcomplexlib_cosh }, { "exp", xcomplexlib_exp }, { "imag", xcomplexlib_imag }, { "log", xcomplexlib_log }, { "pow", xcomplexlib_pow }, { "proj", xcomplexlib_proj }, { "real", xcomplexlib_real }, { "sin", xcomplexlib_sin }, { "sinh", xcomplexlib_sinh }, { "sqrt", xcomplexlib_sqrt }, { "tan", xcomplexlib_tan }, { "tanh", xcomplexlib_tanh }, /* */ { NULL, NULL }, }; int luaopen_xcomplex(lua_State *L) { luaL_newmetatable(L, COMPLEX_METATABLE); luaL_setfuncs(L, xcomplexlib_function_list, 0); lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); lua_pushliteral(L, "__tostring"); lua_pushliteral(L, "tostring"); lua_gettable(L, -3); lua_settable(L, -3); lua_pushliteral(L, "I"); lua_pushliteral(L, "i"); lua_gettable(L, -3); lua_settable(L, -3); lua_pushliteral(L, "__name"); /* kind of redundant */ lua_pushliteral(L, "complex"); lua_settable(L, -3); return 1; } luametatex-2.11.08/source/luarest/lmtpdfelib.c0000644000175000017500000016433015063273560020273 0ustar hillehille/* See license.txt in the root of this project. */ /*tex This file hosts the encapsulated \PDF\ support code used for inclusion and access from \LUA. */ # include "luametatex.h" // # define PDFE_METATABLE_INSTANCE "pdfe.instance" // # define PDFE_METATABLE_DICTIONARY "pdfe.dictionary" // # define PDFE_METATABLE_ARRAY "pdfe.array" // # define PDFE_METATABLE_STREAM "pdfe.stream" // # define PDFE_METATABLE_REFERENCE "pdfe.reference" # include "../libraries/pplib/pplib.h" /*tex We start with some housekeeping. Dictionaries, arrays, streams and references get userdata, while strings, names, integers, floats and booleans become regular \LUA\ objects. We need to define a few metatable identifiers too. */ typedef struct pdfe_document { ppdoc *document; int open; int isfile; char *memstream; int pages; int index; } pdfe_document ; typedef struct pdfe_dictionary { ppdict *dictionary; } pdfe_dictionary; typedef struct pdfe_array { pparray *array; } pdfe_array; typedef struct pdfe_stream { ppstream *stream; int decode; int open; } pdfe_stream; typedef struct pdfe_reference { /* ppref *reference; */ ppxref *xref; int onum; } pdfe_reference; /*tex We need to check if we have the right userdata. A similar warning is issued when encounter a problem. We don't exit. */ static void pdfe_invalid_object_warning(const char *detail, int where) { tex_formatted_warning("pdfe lib", "lua expected, case %i", detail, where); } /* todo: use luaL_checkudata */ typedef enum pdfelib_errors { no_error, to_string_error, to_table_error, get_catalog_error, get_trailer_error, get_info_error, get_page_error, get_pages_error, get_size_error, get_status_error, get_version_error, get_n_of_pages_error, get_n_of_objects_error, get_memory_usage_error, get_from_error, get_box_error, open_error, close_error, read_error, free_error, unencrypt_error, } pdfelib_errors; static pdfe_document *pdfelib_aux_check_isdocument(lua_State *L, int n, int where) { pdfe_document *p = (pdfe_document *) lua_touserdata(L, n); if (p && lua_getmetatable(L, n)) { lua_get_metatablelua(pdfe_instance); if (! lua_rawequal(L, -1, -2)) { p = NULL; // todo: no document } else if (! p->document) { p = NULL; // todo: invalid document } lua_pop(L, 2); if (p) { return p; } } if (where != free_error) { pdfe_invalid_object_warning("document", where); } return NULL; } static pdfe_dictionary *pdfelib_aux_check_isdictionary(lua_State *L, int n, int where) { pdfe_dictionary *p = (pdfe_dictionary *) lua_touserdata(L, n); if (p && lua_getmetatable(L, n)) { lua_get_metatablelua(pdfe_dictionary_instance); if (! lua_rawequal(L, -1, -2)) { p = NULL; } lua_pop(L, 2); if (p) { return p; } } pdfe_invalid_object_warning("dictionary", where); return NULL; } static pdfe_array *pdfelib_aux_check_isarray(lua_State *L, int n, int where) { pdfe_array *p = (pdfe_array *) lua_touserdata(L, n); if (p && lua_getmetatable(L, n)) { lua_get_metatablelua(pdfe_array_instance); if (! lua_rawequal(L, -1, -2)) { p = NULL; } lua_pop(L, 2); if (p) { return p; } } pdfe_invalid_object_warning("array", where); return NULL; } static pdfe_stream *pdfelib_aux_check_isstream(lua_State *L, int n, int where) { pdfe_stream *p = (pdfe_stream *) lua_touserdata(L, n); if (p && lua_getmetatable(L, n)) { lua_get_metatablelua(pdfe_stream_instance); if (! lua_rawequal(L, -1, -2)) { p = NULL; } lua_pop(L, 2); if (p) { return p; } } pdfe_invalid_object_warning("stream", where); return NULL; } static pdfe_reference *pdfelib_aux_check_isreference(lua_State *L, int n, int where) { pdfe_reference *p = (pdfe_reference *) lua_touserdata(L, n); if (p && lua_getmetatable(L, n)) { lua_get_metatablelua(pdfe_reference_instance); if (! lua_rawequal(L, -1, -2)) { p = NULL; } lua_pop(L, 2); if (p) { return p; } } pdfe_invalid_object_warning("reference", where); return NULL; } /*tex Reporting the type of a userdata is just a sequence of tests till we find the right one. We return nothing is it is no pdfe type. \starttyping t = pdfe.type() \stoptyping */ /* # define check_type(field,meta,name) do { \ lua_get_metatablelua(meta); \ if (lua_rawequal(L, -1, -2)) { \ lua_pushstring(L, name); \ return 1; \ } \ lua_pop(L, 1); \ } while (0) static int pdfelib_type(lua_State *L) { void *p = lua_touserdata(L, 1); if (p && lua_getmetatable(L, 1)) { check_type(document, pdfe_instance, PDFE_METATABLE_INSTANCE); check_type(dictionary, pdfe_dictionary, PDFE_METATABLE_DICTIONARY); check_type(array, pdfe_array, PDFE_METATABLE_ARRAY); check_type(reference, pdfe_reference, PDFE_METATABLE_REFERENCE); check_type(stream, pdfe_stream, PDFE_METATABLE_STREAM); } return 0; } */ # define check_type(field,meta) do { \ lua_get_metatablelua(meta); \ if (lua_rawequal(L, -1, -2)) { \ lua_push_key(meta); \ return 1; \ } \ lua_pop(L, 1); \ } while (0) static int pdfelib_type(lua_State *L) { void *p = lua_touserdata(L, 1); if (p && lua_getmetatable(L, 1)) { check_type(document, pdfe_instance); check_type(dictionary, pdfe_dictionary_instance); check_type(array, pdfe_array_instance); check_type(reference, pdfe_reference_instance); check_type(stream, pdfe_stream_instance); } return 0; } /*tex The \type {tostring} metamethods are similar and report a pdfe type plus a pointer value, as is rather usual in \LUA. I ditched the macro that defined them and are now verbose. */ static int pdfelib_document_tostring(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, to_string_error); if (p) { lua_pushfstring(L, "", p->document); return 1; } else { return 0; } } static int pdfelib_dictionary_tostring(lua_State *L) { pdfe_dictionary *p = pdfelib_aux_check_isdictionary(L, 1, to_string_error); if (p) { lua_pushfstring(L, "", p->dictionary); return 1; } else { return 0; } } static int pdfelib_array_tostring(lua_State *L) { pdfe_array *p = pdfelib_aux_check_isarray(L, 1, to_string_error); if (p) { lua_pushfstring(L, "", p->array); return 1; } else { return 0; } } static int pdfelib_stream_tostring(lua_State *L) { pdfe_stream *p = pdfelib_aux_check_isstream(L, 1, to_string_error); if (p) { lua_pushfstring(L, "", p->stream); return 1; } else { return 0; } } static int pdfelib_reference_tostring(lua_State *L) { pdfe_reference *p = pdfelib_aux_check_isreference(L, 1, to_string_error); if (p) { lua_pushfstring(L, "", p->onum); return 1; } else { return 0; } } /*tex The pushers look rather similar. We have two variants, one that just pushes the object, and another that also pushes some extra information. */ static inline void pdfe_push_dictionary(lua_State *L, ppdict *dictionary) { pdfe_dictionary *d = (pdfe_dictionary *) lua_newuserdatauv(L, sizeof(pdfe_dictionary), 0); // luaL_getmetatable(L, PDFE_METATABLE_DICTIONARY); lua_get_metatablelua(pdfe_dictionary_instance); lua_setmetatable(L, -2); d->dictionary = dictionary; } static int pdfelib_aux_pushdictionary(lua_State *L, ppdict *dictionary) { if (dictionary) { pdfe_push_dictionary(L, dictionary); lua_pushinteger(L, (lua_Integer) dictionary->size); return 2; } else { return 0; } } static int pdfelib_aux_pushdictionaryonly(lua_State *L, ppdict *dictionary) { if (dictionary) { pdfe_push_dictionary(L, dictionary); return 1; } else { return 0; } } static inline void pdfe_push_array(lua_State *L, pparray *array) { pdfe_array *a = (pdfe_array *) lua_newuserdatauv(L, sizeof(pdfe_array), 0); // luaL_getmetatable(L, PDFE_METATABLE_ARRAY); lua_get_metatablelua(pdfe_array_instance); lua_setmetatable(L, -2); a->array = array; } static int pdfelib_aux_pusharray(lua_State *L, pparray *array) { if (array) { pdfe_push_array(L, array); lua_pushinteger(L, (lua_Integer) array->size); return 2; } else { return 0; } } static int pdfelib_aux_pusharrayonly(lua_State *L, pparray *array) { if (array) { pdfe_push_array(L, array); return 1; } else { return 0; } } static inline void pdfe_push_stream(lua_State *L, ppstream *stream) { pdfe_stream *s = (pdfe_stream *) lua_newuserdatauv(L, sizeof(pdfe_stream), 0); // luaL_getmetatable(L, PDFE_METATABLE_STREAM); lua_get_metatablelua(pdfe_stream_instance); lua_setmetatable(L, -2); s->stream = stream; s->open = 0; s->decode = 0; } static int pdfelib_aux_pushstream(lua_State *L, ppstream *stream) { if (stream) { pdfe_push_stream(L, stream); if (pdfelib_aux_pushdictionary(L, stream->dict) > 0) { return 3; } else { return 1; } } else { return 0; } } static int pdfelib_aux_pushstreamonly(lua_State *L, ppstream *stream) { if (stream) { pdfe_push_stream(L, stream); if (pdfelib_aux_pushdictionaryonly(L, stream->dict) > 0) { return 2; } else { return 1; } } else { return 0; } } static inline void pdfe_push_reference(lua_State *L, ppref *reference) { pdfe_reference *r = (pdfe_reference *) lua_newuserdatauv(L, sizeof(pdfe_reference), 0); // luaL_getmetatable(L, PDFE_METATABLE_REFERENCE); lua_get_metatablelua(pdfe_reference_instance); lua_setmetatable(L, -2); r->xref = reference->xref; r->onum = (int) reference->number; } static int pdfelib_aux_pushreference(lua_State *L, ppref *reference) { if (reference && reference->number != 0) { pdfe_push_reference(L, reference); lua_pushinteger(L, (lua_Integer) reference->number); return 2; } else { return 0; } } /*tex The next function checks for the type and then pushes the matching data on the stack. \starttabulate[|rT|l|l|l|] \BC type \BC meaning \BC value \BC detail \NC \NR \NC 0 \NC none \NC nil \NC \NC \NR \NC 1 \NC null \NC nil \NC \NC \NR \NC 2 \NC boolean \NC boolean \NC \NC \NR \NC 3 \NC integer \NC integer \NC \NC \NR \NC 4 \NC number \NC float \NC \NC \NR \NC 5 \NC name \NC string \NC \NC \NR \NC 6 \NC string \NC string \NC type \NC \NR \NC 7 \NC array \NC arrayobject \NC size \NC \NR \NC 8 \NC dictionary \NC dictionaryobject \NC size \NC \NR \NC 9 \NC stream \NC streamobject \NC dictionary size \NC \NR \NC 10 \NC reference \NC integer \NC \NC \NR \LL \stoptabulate A name and string can be distinguished by the extra type value that a string has. */ static int pdfelib_aux_pushvalue(lua_State *L, ppobj *object) { switch (object->type) { case PPNONE: case PPNULL: lua_pushnil(L); return 1; case PPBOOL: lua_pushboolean(L, (int) object->integer); return 1; case PPINT: lua_pushinteger(L, (lua_Integer) object-> integer); return 1; case PPNUM: lua_pushnumber(L, (double) object->number); return 1; case PPNAME: { ppname *n = ppname_decoded(object->name) ; lua_pushlstring(L, ppname_data(n), ppname_size(n)); return 1; } case PPSTRING: // lua_pushlstring(L, ppstring_data(object->string), ppstring_size(object->string)); // lua_pushboolean(L, ppstring_hex(object->string)); { ppstring *s = ppstring_decoded(object->string); lua_pushlstring(L, ppstring_data(s), ppstring_size(s)); lua_pushinteger(L, (s)->flags); return 2; } case PPARRAY: return pdfelib_aux_pusharray(L, object->array); case PPDICT: return pdfelib_aux_pushdictionary(L, object->dict); case PPSTREAM: return pdfelib_aux_pushstream(L, object->stream); case PPREF: return pdfelib_aux_pushreference(L, object->ref); } return 0; } /*tex We need to start someplace when we traverse a document's tree. There are three places: \starttyping catalogdictionary = getcatalog(documentobject) trailerdictionary = gettrailer(documentobject) infodictionary = getinfo (documentobject) \stoptyping */ static int pdfelib_getcatalog(lua_State *L) { pdfe_document* p = pdfelib_aux_check_isdocument (L, 1, get_catalog_error); if (p) { return pdfelib_aux_pushdictionaryonly (L, ppdoc_catalog (p->document)); } else { return 0; } } static int pdfelib_gettrailer(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_trailer_error); if (p) { return pdfelib_aux_pushdictionaryonly (L, ppdoc_trailer (p->document)); } else { return 0; } } static int pdfelib_getinfo(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_info_error); if (p) { return pdfelib_aux_pushdictionaryonly (L, ppdoc_info (p->document)); } else { return 0; } } static int pdfelib_getpermissions(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_info_error); if (p) { lua_pushinteger(L, ppdoc_permissions(p->document)); } else { lua_pushnil(L); } return 1; } /*tex We have three more helpers. \starttyping [key,] type, value, detail = getfromdictionary(dictionaryobject,name|index) type, value, detail = getfromarray (arrayobject,index) [key,] type, value, detail = getfromstream (streamobject,name|index) \stoptyping */ static int pdfelib_getfromarray(lua_State *L) { pdfe_array *a = pdfelib_aux_check_isarray(L, 1, get_from_error); if (a) { unsigned int index = lmt_checkinteger(L, 2) - 1; if (index < a->array->size) { ppobj *object = pparray_at(a->array,index); if (object) { lua_pushinteger(L, (lua_Integer) object->type); return 1 + pdfelib_aux_pushvalue(L, object); } } } return 0; } static int pdfelib_getfromdictionary(lua_State *L) { pdfe_dictionary *d = pdfelib_aux_check_isdictionary(L, 1, get_from_error); if (d) { if (lua_type(L, 2) == LUA_TSTRING) { const char *name = luaL_checkstring(L, 2); ppobj *object = ppdict_get_obj(d->dictionary, name); if (object) { lua_pushinteger(L, (lua_Integer) object->type); return 1 + pdfelib_aux_pushvalue(L, object); } } else { unsigned int index = lmt_checkinteger(L, 2) - 1; if (index < d->dictionary->size) { ppobj *object = ppdict_at(d->dictionary,index); if (object) { ppname *key = ppname_decoded(ppdict_key(d->dictionary, index)); lua_pushlstring(L, ppname_data(key), ppname_size(key)); lua_pushinteger(L, (lua_Integer) object->type); return 2 + pdfelib_aux_pushvalue(L, object); } } } } return 0; } static int pdfelib_getfromstream(lua_State *L) { pdfe_stream *s = (pdfe_stream *) lua_touserdata(L, get_from_error); // pdfe_stream *s = check_isstream(L, 1); if (s) { ppdict *d = s->stream->dict; if (lua_type(L, 2) == LUA_TSTRING) { const char *name = luaL_checkstring(L, 2); ppobj *object = ppdict_get_obj(d, name); if (object) { lua_pushinteger(L, (lua_Integer) object->type); return 1 + pdfelib_aux_pushvalue(L, object); } } else { unsigned int index = lmt_checkinteger(L, 2) - 1; if (index < d->size) { ppobj *object = ppdict_at(d, index); if (object) { ppname *key = ppname_decoded(ppdict_key(d, index)); lua_pushlstring(L, ppname_data(key), ppname_size(key)); lua_pushinteger(L, (lua_Integer) object->type); return 2 + pdfelib_aux_pushvalue(L, object); } } } } return 0; } /*tex An indexed table with all entries in an array can be fetched with:: \starttyping t = arraytotable(arrayobject) \stoptyping An hashed table with all entries in an dictionary can be fetched with:: \starttyping t = dictionarytotable(arrayobject) \stoptyping */ static void pdfelib_totable(lua_State *L, ppobj *object, int flat) { int n = pdfelib_aux_pushvalue(L, object); if (flat && n < 2) { return; } else { /* [value] [extra] [more] */ lua_createtable(L, n + 1, 0); if (n == 1) { /* value { nil, nil } */ lua_insert(L, -2); /* { nil, nil } value */ lua_rawseti(L, -2, 2); /* { nil , value } */ } else if (n == 2) { /* value extra { nil, nil, nil } */ lua_insert(L, -3); /* { nil, nil, nil } value extra */ lua_rawseti(L, -3, 3); /* { nil, nil, extra } value */ lua_rawseti(L, -2, 2); /* { nil, value, extra } */ } else if (n == 3) { /* value extra more { nil, nil, nil, nil } */ lua_insert(L, -4); /* { nil, nil, nil, nil, nil } value extra more */ lua_rawseti(L, -4, 4); /* { nil, nil, nil, more } value extra */ lua_rawseti(L, -3, 3); /* { nil, nil, extra, more } value */ lua_rawseti(L, -2, 2); /* { nil, value, extra, more } */ } lua_pushinteger(L, (lua_Integer) object->type); /* { nil, [value], [extra], [more] } type */ lua_rawseti(L, -2, 1); /* { type, [value], [extra], [more] } */ } } static int pdfelib_arraytotable(lua_State *L) { pdfe_array *a = pdfelib_aux_check_isarray(L, 1, to_table_error); if (a) { int flat = lua_isboolean(L, 2); int j = 0; lua_createtable(L, (int) a->array->size, 0); /* table */ for (unsigned int i = 0; i < a->array->size; i++) { ppobj *object = pparray_at(a->array,i); if (object) { pdfelib_totable(L, object, flat); /* table { type, [value], [extra], [more] } */ lua_rawseti(L, -2, ++j); /* table[i] = { type, [value], [extra], [more] } */ } } return 1; } else { return 0; } } static int pdfelib_dictionarytotable(lua_State *L) { pdfe_dictionary *d = pdfelib_aux_check_isdictionary(L, 1, to_table_error); if (d) { int flat = lua_isboolean(L, 2); lua_createtable(L, 0, (int) d->dictionary->size); /* table */ for (unsigned int i = 0; i < d->dictionary->size; i++) { ppobj *object = ppdict_at(d->dictionary, i); if (object) { ppname *key = ppname_decoded(ppdict_key(d->dictionary, i)); lua_pushlstring(L, ppname_data(key), ppname_size(key)); /* table key */ pdfelib_totable(L, object, flat); /* table key { type, [value], [extra], [more] } */ lua_rawset(L, -3); /* table[key] = { type, [value], [extra] } */ } } return 1; } else { return 0; } } /*tex All pages are collected with: \starttyping { { dict, size, objnum }, ... } = pagestotable(document) \stoptyping */ static int pdfelib_pagestotable(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, to_table_error); if (p) { ppdoc *d = p->document; int i = 1; int j = 0; lua_createtable(L, (int) ppdoc_page_count(d), 0); /* pages[1..n] */ for (ppref *r = ppdoc_first_page(d); r; r = ppdoc_next_page(d), ++i) { lua_createtable(L, 3, 0); if (ppref_obj(r)) { pdfelib_aux_pushdictionary(L, ppref_obj(r)->dict); /* table dictionary n */ lua_rawseti(L, -3, 2); /* table dictionary */ lua_rawseti(L, -2, 1); /* table */ lua_pushinteger(L, r->number); /* table reference */ lua_rawseti(L, -2, 3); /* table */ lua_rawseti(L, -2, ++j); /* pages[i] = { dictionary, size, objnum } */ } } return 1; } else { return 0; } } /*tex Streams can be fetched on one go: \starttyping string, n = readwholestream(streamobject,decode) \stoptyping */ static int pdfelib_stream_readwhole(lua_State *L) { pdfe_stream *s = pdfelib_aux_check_isstream(L, 1, read_error); if (s) { uint8_t *b = NULL; int decode = 0; size_t n = 0; if (s->open > 0) { ppstream_done(s->stream); s->open = 0; s->decode = 0; } if (lua_gettop(L) > 1 && lua_isboolean(L, 2)) { decode = lua_toboolean(L, 2); } b = ppstream_all(s->stream, &n, decode); lua_pushlstring(L, (const char *) b, n); lua_pushinteger(L, (lua_Integer) n); ppstream_done(s->stream); return 2; } else { return 0; } } /*tex Alternatively streams can be fetched stepwise: \starttyping okay = openstream(streamobject,[decode]) string, n = readfromstream(streamobject) closestream(streamobject) \stoptyping */ static int pdfelib_stream_open(lua_State *L) { pdfe_stream *s = pdfelib_aux_check_isstream(L, 1, open_error); if (s) { if (s->open == 0) { if (lua_gettop(L) > 1) { s->decode = lua_isboolean(L, 2); } s->open = 1; } lua_pushboolean(L,1); return 1; } else { return 0; } } static int pdfelib_stream_close(lua_State *L) { pdfe_stream *s = pdfelib_aux_check_isstream(L, 1, close_error); if (s && s->open > 0) { ppstream_done(s->stream); s->open = 0; s->decode = 0; } return 0; } static int pdfelib_stream_read(lua_State *L) { pdfe_stream *s = pdfelib_aux_check_isstream(L, 1, read_error); if (s) { size_t n = 0; uint8_t *d = NULL; if (s->open == 1) { d = ppstream_first(s->stream, &n, s->decode); s->open = 2; } else if (s->open == 2) { d = ppstream_next(s->stream, &n); } else { return 0; } lua_pushlstring(L, (const char *) d, n); lua_pushinteger(L, (lua_Integer) n); return 2; } else { return 0; } } /*tex There are two methods for opening a document: files and strings. \starttyping documentobject = open(filename) documentobject = new(string,length) \stoptyping Closing happens with: \starttyping close(documentobject) \stoptyping When the \type {new} function gets a peudo filename as third argument, no user data will be created but the stream is accessible as image. */ /* static int pdfelib_test(lua_State *L) { const char *filename = luaL_checkstring(L, 1); ppdoc *d = ppdoc_load(filename); if (d) { lua_pushboolean(L,1); ppdoc_free(d); } else { lua_pushboolean(L,0); } return 1; } */ static int aux_pdfelib_open(lua_State *L, FILE *f) { ppdoc *d = ppdoc_filehandle(f, 1); if (d) { pdfe_document *p = (pdfe_document *) lua_newuserdatauv(L, sizeof(pdfe_document), 0); // luaL_getmetatable(L, PDFE_METATABLE_INSTANCE); lua_get_metatablelua(pdfe_instance); lua_setmetatable(L, -2); p->document = d; p->open = 1; p->isfile = 1; p->memstream = NULL; return 1; } else { return 0; } } static int pdfelib_open(lua_State *L) { const char *filename = luaL_checkstring(L, 1); FILE *f = aux_utf8_fopen(filename, "rb"); if (f && aux_pdfelib_open(L, f)) { return 1; } else { /* tex_normal_warning("pdfe lib", "no valid file handle"); */ /* the caller should handle it */ return 0; } } static int pdfelib_openfile(lua_State *L) { luaL_Stream *fs = ((luaL_Stream *) luaL_checkudata(L, 1, LUA_FILEHANDLE)); FILE *f = (fs->closef) ? fs->f : NULL; if (f && aux_pdfelib_open(L, f)) { /*tex We trick \LUA\ in believing the file is closed. */ fs->closef = NULL; return 1; } else { /* tex_normal_warning("pdfe lib", "no valid file handle"); */ /* the caller should handle it */ return 0; } } static int pdfelib_new(lua_State *L) { size_t streamsize = 0; const char *docstream = NULL; switch (lua_type(L, 1)) { case LUA_TSTRING: docstream = lua_tolstring(L, 1, &streamsize); if (! docstream) { tex_normal_warning("pdfe lib", "invalid string"); return 0; } else { break; } case LUA_TLIGHTUSERDATA: /*tex The stream comes as a sequence of bytes. This could happen from a library (we used this for swiglib gm output tests). */ docstream = (const char *) lua_touserdata(L, 1); if (! docstream) { tex_normal_warning("pdfe lib", "invalid lightuserdata"); return 0; } else { break; } default: tex_normal_warning("pdfe lib", "string or lightuserdata expected"); return 0; } streamsize = luaL_optinteger(L, 2, streamsize); if (streamsize > 0) { char *memstream = lmt_generic_malloc((unsigned) (streamsize + 1)); /* we have no hook into pdfe free */ if (memstream) { ppdoc *d = NULL; memcpy(memstream, docstream, (streamsize + 1)); memstream[streamsize] = '\0'; d = ppdoc_mem(memstream, streamsize); if (d) { pdfe_document *p = (pdfe_document *) lua_newuserdatauv(L, sizeof(pdfe_document), 0); lua_get_metatablelua(pdfe_instance); lua_setmetatable(L, -2); p->document = d; p->open = 1; p->isfile = 0; p->memstream = memstream; return 1; } else { tex_normal_warning("pdfe lib", "unable to handle stream"); } } else { tex_normal_warning("pdfe lib", "not enough memory for new stream"); } } else { tex_normal_warning("pdfe lib", "stream with size > 0 expected"); } return 0; } /* There is no garbage collection needed as the library itself manages the objects. Normally objects don't take much space. Streams use buffers so (I assume) that they are not persistent. The only collector is in the parent object (the document). */ static int pdfelib_document_free(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, free_error); if (p && p->open) { if (p->document) { ppdoc_free(p->document); p->document = NULL; } if (p->memstream) { /* pplib does this: xfree(p->memstream); */ p->memstream = NULL; } p->open = 0; } return 0; } static int pdfelib_close(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, close_error); if (p && p->open) { if (p->document) { ppdoc_free(p->document); p->document = NULL; } if (p->memstream) { /* pplib does this: xfree(p->memstream); */ p->memstream = NULL; } p->open = 0; } return 0; } /*tex A document is can be uncrypted with: \starttyping status = unencrypt(documentobject,user,owner) \stoptyping Instead of a password \type {nil} can be passed, so there are three possible useful combinations. */ static int pdfelib_unencrypt(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, unencrypt_error); if (p) { size_t u = 0; size_t o = 0; const char* user = NULL; const char* owner = NULL; int top = lua_gettop(L); if (top > 1) { if (lua_type(L,2) == LUA_TSTRING) { user = lua_tolstring(L, 2, &u); } else { /*tex we're not too picky but normally it will be nil or false */ } if (top > 2) { if (lua_type(L,3) == LUA_TSTRING) { owner = lua_tolstring(L, 3, &o); } else { /*tex we're not too picky but normally it will be nil or false */ } } lua_pushinteger(L, (lua_Integer) ppdoc_crypt_pass(p->document, user, u, owner, o)); return 1; } } lua_pushinteger(L, (lua_Integer) PPCRYPT_FAIL); return 1; } /*tex There are a couple of ways to get information about the document: \starttyping n = getsize (documentobject) major, minor = getversion (documentobject) status = getstatus (documentobject) n = getnofobjects (documentobject) n = getnofpages (documentobject) bytes, waste = getmemoryusage(documentobject) \stoptyping */ static int pdfelib_getsize(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_size_error); if (p) { lua_pushinteger(L, (lua_Integer) ppdoc_file_size(p->document)); return 1; } else { return 0; } } static int pdfelib_getversion(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_version_error); if (p) { int minor; int major = ppdoc_version_number(p->document, &minor); lua_pushinteger(L, (lua_Integer) major); lua_pushinteger(L, (lua_Integer) minor); return 2; } else { return 0; } } static int pdfelib_getstatus(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_status_error); if (p) { lua_pushinteger(L, (lua_Integer) ppdoc_crypt_status(p->document)); return 1; } else { return 0; } } static int pdfelib_getnofobjects(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_n_of_objects_error); if (p) { lua_pushinteger(L, (lua_Integer) ppdoc_objects(p->document)); return 1; } else { return 0; } } static int pdfelib_getnofpages(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_n_of_pages_error); if (p) { lua_pushinteger(L, (lua_Integer) ppdoc_page_count(p->document)); return 1; } else { return 0; } } static int pdfelib_getmemoryusage(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_memory_usage_error); if (p) { size_t w = 0; size_t m = ppdoc_memory(p->document, &w); lua_pushinteger(L, (lua_Integer) m); lua_pushinteger(L, (lua_Integer) w); return 2; } else { return 0; } } /* A specific page dictionary can be filtered with the next command. So, there is no need to parse the document page tree (with these \type {kids} arrays). \starttyping dictionaryobject = getpage(documentobject,pagenumber) \stoptyping */ static int pdfelib_aux_pushpage(lua_State *L, ppdoc *d, int page) { if ((page <= 0) || (page > ((int) ppdoc_page_count(d)))) { return 0; } else { ppref *pp = ppdoc_page(d, page); return pdfelib_aux_pushdictionaryonly(L, ppref_obj(pp)->dict); } } static int pdfelib_getpage(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_page_error); if (p) { return pdfelib_aux_pushpage(L, p->document, lmt_checkinteger(L, 2)); } else { return 0; } } static int pdfelib_aux_pushpages(lua_State *L, ppdoc *d) { int i = 1; lua_createtable(L, (int) ppdoc_page_count(d), 0); /* pages[1..n] */ for (ppref *r = ppdoc_first_page(d); r; r = ppdoc_next_page(d), ++i) { pdfelib_aux_pushdictionaryonly(L,ppref_obj(r)->dict); lua_rawseti(L, -2, i); } return 1 ; } static int pdfelib_getpages(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_pages_error); if (p) { return pdfelib_aux_pushpages(L, p->document); } else { return 0; } } /*tex The bounding box (\type {MediaBox) and similar boxes can be available in a (page) dictionary but also in a parent object. Therefore a helper is available that does the (backtracked) lookup. \starttyping { lx, ly, rx, ry } = getbox(dictionaryobject) \stoptyping */ static int pdfelib_getbox(lua_State *L) { if (lua_gettop(L) > 1 && lua_type(L,2) == LUA_TSTRING) { pdfe_dictionary *p = pdfelib_aux_check_isdictionary(L, 1, get_box_error); if (p) { const char *key = lua_tostring(L, 2); pprect box = { 0, 0, 0, 0 }; pprect *r = ppdict_get_box(p->dictionary, key, &box); if (r) { lua_createtable(L, 4, 0); lua_pushnumber(L, r->lx); lua_rawseti(L, -2, 1); lua_pushnumber(L, r->ly); lua_rawseti(L, -2, 2); lua_pushnumber(L, r->rx); lua_rawseti(L, -2, 3); lua_pushnumber(L, r->ry); lua_rawseti(L, -2, 4); return 1; } } } return 0; } /*tex This one is needed when you use the detailed getters and run into an object reference. The regular getters resolve this automatically. \starttyping [dictionary|array|stream]object = getfromreference(referenceobject) \stoptyping */ static int pdfelib_getfromreference(lua_State *L) { pdfe_reference *r = pdfelib_aux_check_isreference(L, 1, get_from_error); if (r && r->xref) { ppref *rr = ppxref_find(r->xref, (ppuint) r->onum); if (rr) { ppobj *o = ppref_obj(rr); if (o) { lua_pushinteger(L, (lua_Integer) o->type); return 1 + pdfelib_aux_pushvalue(L, o); } } } return 0; } static int pdfelib_getfromobject(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_from_error); if (p) { ppref *rr = ppxref_find(p->document->xref, lua_tointeger(L, 2)); if (rr) { ppobj *o = ppref_obj(rr); if (o) { lua_pushinteger(L, (lua_Integer) o->type); return 1 + pdfelib_aux_pushvalue(L, o); } } } return 0; } static int pdfelib_getobjectrange(lua_State *L) { pdfe_document *p = pdfelib_aux_check_isdocument(L, 1, get_from_error); if (p) { ppref *rr = ppxref_find(p->document->xref, lua_tointeger(L, 2)); if (rr) { lua_pushinteger(L, (lua_Integer) rr->offset); lua_pushinteger(L, (lua_Integer) rr->length); return 2; } } return 0; } /*tex Here are some convenient getters: \starttyping = getstring (array|dict|ref,index|key) = getinteger (array|dict|ref,index|key) = getnumber (array|dict|ref,index|key) = getboolean (array|dict|ref,index|key) = getname (array|dict|ref,index|key) = getdictionary(array|dict|ref,index|key) = getarray (array|dict|ref,index|key) , = getstream (array|dict|ref,index|key) \stoptyping We report issues when reasonable but are silent when it makes sense. We don't error on this because we expect the user code to act reasonable on a return value. */ static int pdfelib_valid_index(lua_State *L, void **p, int *t) { *t = lua_type(L, 2); *p = lua_touserdata(L, 1); lua_settop(L, 2); if (! *p) { switch (*t) { case LUA_TSTRING: tex_normal_warning("pdfe lib", "lua expected"); break; case LUA_TNUMBER: tex_normal_warning("pdfe lib", "lua expected"); break; default: tex_normal_warning("pdfe lib", "invalid arguments"); break; } return 0; } else if (! lua_getmetatable(L, 1)) { tex_normal_warning("pdfe lib", "first argument should be a or "); return 0; } else { return 1; } } static void pdfelib_invalid_index_warning(void) { tex_normal_warning("pdfe lib", "second argument should be integer or string"); } /*tex The direct fetcher returns the result or |NULL| when there is nothing found. The indirect fetcher passes a pointer to the target variable and returns success state. The next two functions used to be macros but as we try to avoid large ones with much code, they are now functions. */ typedef void * (*pp_a_direct) (void *a, size_t index); typedef void * (*pp_d_direct) (void *d, const char *key); typedef int (*pp_a_indirect) (void *a, size_t index, void **value); typedef int (*pp_d_indirect) (void *d, const char *key, void **value); static int pdfelib_get_value_direct(lua_State *L, void **value, pp_d_direct get_d, pp_a_direct get_a) { int t = 0; void *p = NULL; if (pdfelib_valid_index(L, &p, &t)) { switch (t) { case LUA_TSTRING: { const char *key = lua_tostring(L, 2); lua_get_metatablelua(pdfe_dictionary_instance); if (lua_rawequal(L, -1, -2)) { *value = get_d(((pdfe_dictionary *) p)->dictionary, key); return 1; } else { lua_get_metatablelua(pdfe_reference_instance); if (lua_rawequal(L, -1, -3)) { ppref *r = (((pdfe_reference *) p)->xref) ? ppxref_find(((pdfe_reference *) p)->xref, (ppuint) (((pdfe_reference *) p)->onum)) : NULL; \ ppobj *o = (r) ? ppref_obj(r) : NULL; if (o && o->type == PPDICT) { *value = get_d((ppdict *) o->dict, key); return 1; } } } } break; case LUA_TNUMBER: { size_t index = lua_tointeger(L, 2); lua_get_metatablelua(pdfe_array_instance); if (lua_rawequal(L, -1, -2)) { *value = get_a(((pdfe_array *) p)->array, index); return 2; } else { lua_get_metatablelua(pdfe_reference_instance); if (lua_rawequal(L, -1, -3)) { ppref *r = (((pdfe_reference *) p)->xref) ? ppxref_find(((pdfe_reference *) p)->xref, (ppuint) (((pdfe_reference *) p)->onum)) : NULL; \ ppobj *o = (r) ? ppref_obj(r) : NULL; if (o && o->type == PPARRAY) { *value = get_a((pparray *) o->array, index); return 2; } } } } break; default: pdfelib_invalid_index_warning(); break; } } return 0; } static int pdfelib_get_value_indirect(lua_State *L, void **value, pp_d_indirect get_d, pp_a_indirect get_a) { int t = 0; void *p = NULL; if (pdfelib_valid_index(L, &p, &t)) { switch (t) { case LUA_TSTRING: { const char *key = lua_tostring(L, 2); lua_get_metatablelua(pdfe_dictionary_instance); if (lua_rawequal(L, -1, -2)) { return get_d(((pdfe_dictionary *) p)->dictionary, key, value); } else { lua_get_metatablelua(pdfe_reference_instance); if (lua_rawequal(L, -1, -3)) { ppref *r = (((pdfe_reference *) p)->xref) ? ppxref_find(((pdfe_reference *) p)->xref, (ppuint) (((pdfe_reference *) p)->onum)) : NULL; ppobj *o = (r) ? ppref_obj(r) : NULL; if (o && o->type == PPDICT) return get_d(o->dict, key, value); } } } break; case LUA_TNUMBER: { size_t index = lua_tointeger(L, 2); lua_get_metatablelua(pdfe_array_instance); if (lua_rawequal(L, -1, -2)) { return get_a(((pdfe_array *) p)->array, index, value); } else { lua_get_metatablelua(pdfe_reference_instance); if (lua_rawequal(L, -1, -3)) { ppref *r = (((pdfe_reference *) p)->xref) ? ppxref_find(((pdfe_reference *) p)->xref, (ppuint) (((pdfe_reference *) p)->onum)) : NULL; ppobj *o = (r) ? ppref_obj(r) : NULL; if (o && o->type == PPARRAY) return get_a(o->array, index, value); } } } break; default: pdfelib_invalid_index_warning(); break; } } return 0; } static int pdfelib_getstring(lua_State *L) { if (lua_gettop(L) > 1) { ppstring *value = NULL; int okay = 0; int how = 0; if (lua_type(L, 3) == LUA_TBOOLEAN) { if (lua_toboolean(L, 3)) { how = 1; } else { how = 2; } } okay = pdfelib_get_value_direct(L, (void *) &value, (void *) &ppdict_rget_string, (void *) &pparray_rget_string); if (okay && value) { if (how == 1) { value = ppstring_decoded(value); /* we probably always need that */ } /*tex This used to return one value but we made it \LUATEX\ compatible. */ lua_pushlstring(L, ppstring_data(value), ppstring_size(value)); if (how == 2) { lua_pushboolean(L, ppstring_hex(value)); return 2; } else { return 1; } } } return 0; } static int pdfelib_getinteger(lua_State *L) { if (lua_gettop(L) > 1) { ppint value = 0; if (pdfelib_get_value_indirect(L, (void *) &value, (void *) &ppdict_rget_int, (void *) &pparray_rget_int)) { lua_pushinteger(L, (lua_Integer) value); return 1; } } return 0; } static int pdfelib_getnumber(lua_State *L) { if (lua_gettop(L) > 1) { ppnum value = 0; if (pdfelib_get_value_indirect(L, (void *) &value, (void *) &ppdict_rget_num, (void *) &pparray_rget_num)) { lua_pushnumber(L, value); return 1; } } return 0; } static int pdfelib_getboolean(lua_State *L) { if (lua_gettop(L) > 1) { int value = 0; if (pdfelib_get_value_indirect(L, (void *) &value, (void *) &ppdict_rget_bool, (void *) &pparray_rget_bool)) { lua_pushboolean(L, value); return 1; } } return 0; } static int pdfelib_getname(lua_State *L) { if (lua_gettop(L) > 1) { ppname *value = NULL; pdfelib_get_value_direct(L, (void *) &value, (void *) &ppdict_rget_name, (void *) &pparray_rget_name); if (value) { value = ppname_decoded(value) ; lua_pushlstring(L, ppname_data(value), ppname_size(value)); return 1; } } return 0; } static int pdfelib_getdictionary(lua_State *L) { if (lua_gettop(L) > 1) { ppdict *value = NULL; pdfelib_get_value_direct(L, (void *) &value, (void *) &ppdict_rget_dict, (void *) &pparray_rget_dict); if (value) { return pdfelib_aux_pushdictionaryonly(L, value); } } return 0; } static int pdfelib_getarray(lua_State *L) { if (lua_gettop(L) > 1) { pparray *value = NULL; pdfelib_get_value_direct(L, (void *) &value, (void *) &ppdict_rget_array, (void *) &pparray_rget_array); if (value) { return pdfelib_aux_pusharrayonly(L, value); } } return 0; } static int pdfelib_getstream(lua_State *L) { if (lua_gettop(L) > 1) { ppobj *value = NULL; pdfelib_get_value_direct(L, (void *) &value, (void *) &ppdict_rget_obj, (void *) &pparray_rget_obj); if (value && value->type == PPSTREAM) { return pdfelib_aux_pushstreamonly(L, (ppstream *) value->stream); } } return 0; } /*tex The generic pushed that does a similar job as the previous getters acts upon the type. */ static int pdfelib_pushvalue(lua_State *L, ppobj *object) { switch (object->type) { case PPNONE: case PPNULL: lua_pushnil(L); break; case PPBOOL: lua_pushboolean(L, (int) object->integer); break; case PPINT: lua_pushinteger(L, (lua_Integer) object->integer); break; case PPNUM: lua_pushnumber(L, (double) object->number); break; case PPNAME: { ppname *n = ppname_decoded(object->name) ; lua_pushlstring(L, ppname_data(n), ppname_size(n)); } break; case PPSTRING: lua_pushlstring(L, ppstring_data(object->string), ppstring_size(object->string)); break; case PPARRAY: return pdfelib_aux_pusharrayonly(L, object->array); case PPDICT: return pdfelib_aux_pushdictionary(L, object->dict); case PPSTREAM: return pdfelib_aux_pushstream(L, object->stream); case PPREF: pdfelib_aux_pushreference(L, object->ref); break; /*tex We get a funny message in clang about covering all cases. */ /* default: lua_pushnil(L); break; */ } return 1; } /*tex Finally we arrived at the acessors for the userdata objects. The use previously defined helpers. */ static int pdfelib_document_access(lua_State *L) { if (lua_type(L, 2) == LUA_TSTRING) { // pdfe_document *p = (pdfe_document *) lua_touserdata(L, 1); const char *s = lua_tostring(L, 2); if (lua_key_eq(s, catalog) || lua_key_eq(s, Catalog)) { // return pdfelib_aux_pushdictionaryonly(L, ppdoc_catalog(p->document)); return pdfelib_getcatalog(L); } else if (lua_key_eq(s, info) || lua_key_eq(s, Info)) { // return pdfelib_aux_pushdictionaryonly(L, ppdoc_info(p->document)); return pdfelib_getinfo(L); } else if (lua_key_eq(s, trailer) || lua_key_eq(s, Trailer)) { // return pdfelib_aux_pushdictionaryonly(L, ppdoc_trailer(p->document)); return pdfelib_getcatalog(L); } else if (lua_key_eq(s, pages) || lua_key_eq(s, Pages)) { // return pdfelib_aux_pushpages(L, p->document); return pdfelib_getpages(L); } } return 0; } static int pdfelib_array_access(lua_State *L) { if (lua_type(L, 2) == LUA_TNUMBER) { pdfe_array *p = (pdfe_array *) lua_touserdata(L, 1); ppint index = lua_tointeger(L, 2) - 1; ppobj *o = pparray_rget_obj(p->array, index); if (o) { return pdfelib_pushvalue(L, o); } } return 0; } static int pdfelib_dictionary_access(lua_State *L) { pdfe_dictionary *p = (pdfe_dictionary *) lua_touserdata(L, 1); switch (lua_type(L, 2)) { case LUA_TSTRING: { const char *key = lua_tostring(L, 2); ppobj *o = ppdict_rget_obj(p->dictionary, key); if (o) { return pdfelib_pushvalue(L, o); } } break; case LUA_TNUMBER: { ppint index = lua_tointeger(L, 2) - 1; ppobj *o = ppdict_at(p->dictionary, index); if (o) { return pdfelib_pushvalue(L, o); } } break; } return 0; } static int pdfelib_stream_access(lua_State *L) { pdfe_stream *p = (pdfe_stream *) lua_touserdata(L, 1); switch (lua_type(L, 2)) { case LUA_TSTRING: { const char *key = lua_tostring(L, 2); ppobj *o = ppdict_rget_obj(p->stream->dict, key); if (o) { return pdfelib_pushvalue(L, o); } } break; case LUA_TNUMBER: { ppint index = lua_tointeger(L, 2) - 1; ppobj *o = ppdict_at(p->stream->dict, index); if (o) { return pdfelib_pushvalue(L, o); } } break; } return 0; } /*tex The length metamethods are defined last. */ static int pdfelib_array_size(lua_State *L) { pdfe_array *p = (pdfe_array *) lua_touserdata(L, 1); lua_pushinteger(L, (lua_Integer) p->array->size); return 1; } static int pdfelib_dictionary_size(lua_State *L) { pdfe_dictionary *p = (pdfe_dictionary *) lua_touserdata(L, 1); lua_pushinteger(L, (lua_Integer) p->dictionary->size); return 1; } static int pdfelib_stream_size(lua_State *L) { pdfe_stream *p = (pdfe_stream *) lua_touserdata(L, 1); lua_pushinteger(L, (lua_Integer) p->stream->dict->size); return 1; } /*tex We now initialize the main interface. We might add few more informational helpers but this is it. */ static int pdfelib_getencodingvalues(lua_State *L) { lua_createtable(L, 2, 6); lua_set_string_by_index(L, PPSTRING_PLAIN, "plain" ); /* 0 */ lua_set_string_by_index(L, PPSTRING_ENCODED, "encoded"); /* 1 */ lua_set_string_by_index(L, PPSTRING_DECODED, "decoded"); /* 2 */ /* lua_set_string_by_index(L, PPSTRING_EXEC, "exec" ); */ /* 4 */ lua_set_string_by_index(L, PPSTRING_BASE16, "base16" ); /* 8 */ lua_set_string_by_index(L, PPSTRING_BASE85, "base85" ); /* 16 */ lua_set_string_by_index(L, PPSTRING_UTF16BE, "utf16be"); /* 32 */ lua_set_string_by_index(L, PPSTRING_UTF16LE, "utf16le"); /* 64 */ return 1; } static int pdfelib_getstatusvalues(lua_State *L) { lua_createtable(L, 1, 3); lua_set_string_by_index(L, PPCRYPT_PASS, "is protected"); lua_set_string_by_index(L, PPCRYPT_FAIL, "failed to open"); lua_set_string_by_index(L, PPCRYPT_NONE, "not encrypted"); lua_set_string_by_index(L, PPCRYPT_DONE, "is decrypted"); return 1; } static int pdfelib_getfieldtypes(lua_State *L) { lua_createtable(L, 10, 1); lua_set_string_by_index(L, PPNONE, "none"); lua_set_string_by_index(L, PPNULL, "null"); lua_set_string_by_index(L, PPBOOL, "boolean"); lua_set_string_by_index(L, PPINT, "integer"); lua_set_string_by_index(L, PPNUM, "number"); lua_set_string_by_index(L, PPNAME, "name"); lua_set_string_by_index(L, PPSTRING, "string"); lua_set_string_by_index(L, PPARRAY, "array"); lua_set_string_by_index(L, PPDICT, "dictionary"); lua_set_string_by_index(L, PPSTREAM, "stream"); lua_set_string_by_index(L, PPREF, "reference"); return 1; } // PPDOC_ALLOW_PRINT // PPDOC_ALLOW_MODIFY // PPDOC_ALLOW_COPY // PPDOC_ALLOW_ANNOTS // PPDOC_ALLOW_EXTRACT // PPDOC_ALLOW_ASSEMBLY // # define PPDOC_ALLOW_PRINT_HIRES static const struct luaL_Reg pdfelib_function_list[] = { /* management */ { "type", pdfelib_type }, { "open", pdfelib_open }, { "openfile", pdfelib_openfile }, { "new", pdfelib_new }, { "close", pdfelib_close }, { "unencrypt", pdfelib_unencrypt }, { "getencodingvalues", pdfelib_getencodingvalues }, { "getstatusvalues", pdfelib_getstatusvalues }, { "getfieldtypes", pdfelib_getfieldtypes }, /* statistics */ { "getversion", pdfelib_getversion }, { "getstatus", pdfelib_getstatus }, { "getsize", pdfelib_getsize }, { "getnofobjects", pdfelib_getnofobjects }, { "getnofpages", pdfelib_getnofpages }, { "getmemoryusage", pdfelib_getmemoryusage }, /* getters */ { "getcatalog", pdfelib_getcatalog }, { "gettrailer", pdfelib_gettrailer }, { "getinfo", pdfelib_getinfo }, { "getpermissions", pdfelib_getpermissions }, { "getpage", pdfelib_getpage }, { "getpages", pdfelib_getpages }, { "getbox", pdfelib_getbox }, { "getfromreference", pdfelib_getfromreference }, { "getfromdictionary", pdfelib_getfromdictionary }, { "getfromarray", pdfelib_getfromarray }, { "getfromstream", pdfelib_getfromstream }, /* handy too */ { "getfromobject", pdfelib_getfromobject }, { "getobjectrange", pdfelib_getobjectrange }, /* collectors */ { "dictionarytotable", pdfelib_dictionarytotable }, { "arraytotable", pdfelib_arraytotable }, { "pagestotable", pdfelib_pagestotable }, /* more getters */ { "getstring", pdfelib_getstring }, { "getinteger", pdfelib_getinteger }, { "getnumber", pdfelib_getnumber }, { "getboolean", pdfelib_getboolean }, { "getname", pdfelib_getname }, { "getdictionary", pdfelib_getdictionary }, { "getarray", pdfelib_getarray }, { "getstream", pdfelib_getstream }, /* streams */ { "readwholestream", pdfelib_stream_readwhole }, /* not really needed */ { "openstream", pdfelib_stream_open }, { "readfromstream", pdfelib_stream_read }, { "closestream", pdfelib_stream_close }, /* only for me, a test hook */ /* { "test", pdfelib_test }, */ /* done */ { NULL, NULL } }; /*tex The user data metatables are defined as follows. Watch how only the document needs a garbage collector. */ static const struct luaL_Reg pdfelib_instance_metatable[] = { { "__tostring", pdfelib_document_tostring }, { "__gc", pdfelib_document_free }, { "__index", pdfelib_document_access }, { NULL, NULL }, }; static const struct luaL_Reg pdfelib_dictionary_metatable[] = { { "__tostring", pdfelib_dictionary_tostring }, { "__index", pdfelib_dictionary_access }, { "__len", pdfelib_dictionary_size }, { NULL, NULL }, }; static const struct luaL_Reg pdfelib_array_metatable[] = { { "__tostring", pdfelib_array_tostring }, { "__index", pdfelib_array_access }, { "__len", pdfelib_array_size }, { NULL, NULL }, }; static const struct luaL_Reg pdfelib_stream_metatable[] = { { "__tostring", pdfelib_stream_tostring }, { "__index", pdfelib_stream_access }, { "__len", pdfelib_stream_size }, { "__call", pdfelib_stream_readwhole }, { NULL, NULL }, }; static const struct luaL_Reg pdfelib_reference_metatable[] = { { "__tostring", pdfelib_reference_tostring }, { NULL, NULL }, }; /*tex Finally we have arrived at the main initialiser that will be called as part of \LUATEX's initializer. */ /*tex Here we hook in the error handler. */ static void pdfelib_message(const char *message, void *alien) { (void) (alien); tex_normal_warning("pdfe", message); } int luaopen_pdfe(lua_State *L) { /*tex First the four userdata object get their metatables defined. */ luaL_newmetatable(L, PDFE_METATABLE_DICTIONARY); luaL_setfuncs(L, pdfelib_dictionary_metatable, 0); luaL_newmetatable(L, PDFE_METATABLE_ARRAY); luaL_setfuncs(L, pdfelib_array_metatable, 0); luaL_newmetatable(L, PDFE_METATABLE_STREAM); luaL_setfuncs(L, pdfelib_stream_metatable, 0); luaL_newmetatable(L, PDFE_METATABLE_REFERENCE); luaL_setfuncs(L, pdfelib_reference_metatable, 0); /*tex Then comes the main (document) metatable: */ luaL_newmetatable(L, PDFE_METATABLE_INSTANCE); luaL_setfuncs(L, pdfelib_instance_metatable, 0); /*tex Last the library opens up itself to the world. */ lua_newtable(L); luaL_setfuncs(L, pdfelib_function_list, 0); pplog_callback(pdfelib_message, stderr); return 1; } luametatex-2.11.08/source/luarest/lmtserial.c0000644000175000017500000002240715063273560020143 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" # define SERIAL_METATABLE "serial" # ifdef _WIN32 /* see: https://ds.opdenbrouw.nl/micprg/pdf/serial-win.pdf */ /* see: https://learn.microsoft.com/en-us/previous-versions/ff802693(v=msdn.10)?redirectedfrom=MSDN */ /* COM6 */ typedef struct serial_data { HANDLE handle; int closed; } serial_data; // CreateFile( // "\\\\.\\COM10", // address of name of the communications device: \\.\COM10 // fdwAccess, // access (read-write) mode // 0, // share mode // NULL, // address of security descriptor // OPEN_EXISTING, // how to create // 0, // file attributes // NULL // handle of file with attributes to copy // ); static serial_data *seriallib_aux_open(lua_State *L, serial_data *existing) { int success = 0; HANDLE handle = NULL; const char *portname = lua_type(L, 1) == LUA_TSTRING ? lua_tostring(L, 1) : NULL; lua_Integer baudrate = lua_type(L, 2) == LUA_TNUMBER ? lua_tointeger(L, 2) : CBR_19200; DCB dcb = { 0 }; COMMTIMEOUTS timeouts = { 0 }; /* */ if (! portname || strlen(portname) == 0) { goto DONE; } handle = CreateFile( portname, GENERIC_WRITE, 0, /* Sharing doesn't work for serial devices. */ NULL, OPEN_EXISTING, 0, NULL ); if (handle == INVALID_HANDLE_VALUE) { goto DONE; } /* */ dcb.DCBlength = sizeof(dcb); if (! GetCommState(handle, &dcb)) { goto DONE; } dcb.BaudRate = (DWORD) (baudrate ? dcb.BaudRate : CBR_19200); dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; dcb.Parity = NOPARITY; if (! SetCommState(handle, &dcb)) { goto DONE; } /* */ timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (SetCommTimeouts(handle, &timeouts) == FALSE) { goto DONE; } /* */ success = 1; DONE: if (success) { serial_data *serial = existing ? existing : (serial_data *) lua_newuserdatauv(L, sizeof(serial_data), 1); serial->handle = handle; serial->closed = 0; if (! existing) { lua_pushstring(L, portname); lua_setiuservalue(L, -2, 1); } return serial; } else { if (handle) { CloseHandle(handle); } return NULL; } } static void seriallib_aux_close(serial_data *serial) { CloseHandle(serial->handle); } static int seriallib_aux_send(serial_data *serial, const char *sequence, size_t length) { DWORD written = 0; return (int) WriteFile(serial->handle, sequence, (DWORD) length, &written, NULL) ? 1 : 0; } /*tex For old times sake, no temporary user data. */ static int seriallib_write(lua_State *L) { serial_data serial = { .handle = NULL, .closed = 0 }; int success = seriallib_aux_open(L, &serial) && serial.handle; if (success) { size_t length = 0; const char *sequence = lua_tolstring(L, 3, &length); if (length) { DWORD written = 0; success = (int) WriteFile(serial.handle, sequence,(DWORD) length, &written,NULL) ? 1 : 0; } CloseHandle(serial.handle); } lua_pushboolean(L, success); return 1; } # else #include #include #include #include #include /* /dev/ttyUSBx /dev/ttySx /dev/ttyACM0 */ typedef struct serial_data { int handle; int closed; } serial_data; static serial_data *seriallib_aux_open(lua_State *L, serial_data *existing) { int success = 0; int handle = 0; const char *portname = lua_type(L, 1) == LUA_TSTRING ? lua_tostring(L, 1) : NULL; lua_Integer baudrate = lua_type(L, 2) == LUA_TNUMBER ? lua_tointeger(L, 2) : B19200; struct termios settings; /* */ if (! portname || strlen(portname) == 0) { goto DONE; } /* */ handle = open( portname, O_WRONLY | O_NOCTTY | O_NDELAY ); if (handle == -1) { goto DONE; } /* */ tcgetattr(handle, &settings); cfsetispeed(&settings, baudrate ? baudrate : B19200); cfsetospeed(&settings, baudrate ? baudrate : B19200); settings.c_cflag &= ~PARENB; settings.c_cflag &= ~CSTOPB; settings.c_cflag &= ~CSIZE; settings.c_cflag |= CS8; settings.c_cflag &= ~CRTSCTS; settings.c_cflag |= (CREAD | CLOCAL); settings.c_iflag &= ~(IXON | IXOFF | IXANY); settings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); settings.c_oflag &= ~OPOST; // ASYNC_LOW_LATENCY // settings.c_cc[VMIN] = 0; // don't block // settings.c_cc[VTIME] = 2; // timeout in 1/10 sec // settings.c_lflag = 0; /* no echo etc */ // settings.c_oflag = 0; // cfmakeraw(&settings); if (tcsetattr(handle, TCSANOW, &settings) != 0) { goto DONE; } /* */ success = 1; DONE: if (success) { serial_data *serial = existing ? existing : (serial_data *) lua_newuserdatauv(L, sizeof(serial_data), 1); if (! existing) { lua_pushstring(L, portname); lua_setiuservalue(L, -2, 1); } serial->handle = handle; serial->closed = 0; return serial; } else { return NULL; } } static void seriallib_aux_close(serial_data *serial) { close(serial->handle); } static int seriallib_aux_send(serial_data *serial, const char *sequence, size_t length) { return write(serial->handle, sequence, length) ? 1 : 0; } /*tex For old times sake, no temporary user data. */ static int seriallib_write(lua_State *L) { serial_data serial = { .handle = -1, .closed = 0 }; int success = seriallib_aux_open(L, &serial) && serial.handle >= 0; if (success) { size_t length = 0; const char *sequence = lua_tolstring(L, 3, &length); if (length) { success = write(serial.handle, sequence, length) ? 1 : 0; } close(serial.handle); } lua_pushboolean(L, success); return 1; } # endif static int seriallib_open(lua_State *L) { serial_data *serial = seriallib_aux_open(L, NULL); if (serial) { luaL_getmetatable(L, SERIAL_METATABLE); lua_setmetatable(L, -2); } else { lua_pushnil(L); } return 1; } static int seriallib_send(lua_State *L) { serial_data *serial = (serial_data *) luaL_checkudata(L, 1, SERIAL_METATABLE); int success = 0; if (serial && ! serial->closed) { size_t length = 0; const char *sequence = lua_tolstring(L, 2, &length); if (seriallib_aux_send(serial, sequence, length)) { success = 1; } } lua_pushboolean(L, success); return 1; } static int seriallib_close(lua_State *L) /* maybe use the onclose method */ { serial_data *serial = (serial_data *) luaL_checkudata(L, 1, SERIAL_METATABLE); if (serial && ! serial->closed) { serial->closed = 1; seriallib_aux_close(serial); } return 0; } static int seriallib_tostring(lua_State *L) { serial_data *serial = (serial_data *) luaL_checkudata(L, 1, SERIAL_METATABLE); if (serial && ! serial->closed) { const char *port; lua_getiuservalue(L, 1, 1); port = lua_tostring(L, -1); lua_pop(L, -1); lua_pushfstring(L, "", port); return 1; } else { return 0; } } static const luaL_Reg seriallib_function_list[] = { /* management */ { "open", seriallib_open }, { "close", seriallib_close }, { "send", seriallib_send }, { "write", seriallib_write }, /* */ { "tostring", seriallib_tostring }, /* */ { "__gc", seriallib_close }, /* */ { NULL, NULL }, }; int luaopen_serial(lua_State *L) { luaL_newmetatable(L, SERIAL_METATABLE); luaL_setfuncs(L, seriallib_function_list, 0); lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); lua_pushliteral(L, "__tostring"); lua_pushliteral(L, "tostring"); lua_gettable(L, -3); lua_settable(L, -3); lua_pushliteral(L, "__name"); lua_pushliteral(L, "serial"); lua_settable(L, -3); return 1; } luametatex-2.11.08/source/luarest/lmtbytemaplib.c0000644000175000017500000003276315063273560021022 0ustar hillehille/* See license.txt in the root of this project. */ # include # include "utilities/auxbytemaps.h" # define BYTEMAP_METATABLE "bytemap" typedef enum bytemap_loop { bytemap_loop_xy, bytemap_loop_yx, } bytemap_loop; # define first_bytemap_loop bytemap_loop_xy # define last_bytemap_loop bytemap_loop_yx static inline bytemap_data * bytemaplib_aux_valid(lua_State *L, int i) { // we need a fast one for this return (bytemap_data *) luaL_checkudata(L, i, BYTEMAP_METATABLE); } static inline int bytemaplib_new(lua_State *L) { int nx = lua_tointeger(L, 1); int ny = lua_tointeger(L, 2); int nz = lua_tointeger(L, 3); if (bytemap_okay(nx, ny, nz)) { int nn = nx * ny * nz; if (nn > 0) { bytemap_data * bytemap = lua_newuserdatauv(L, sizeof(bytemap_data), 0); if (bytemap) { luaL_setmetatable(L, BYTEMAP_METATABLE); bytemap_allocate(bytemap, nx, ny, nz, NULL); } } return 1; } else { tex_formatted_warning("bytemaplib", "new overflow: %i x %i x #i", nx, ny, nz); return 0; } } static int bytemaplib_reset(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { bytemap_reset(bytemap, NULL); } return 0; } static int bytemaplib_reduce(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int method = lmt_optinteger(L, 2, bytemap_reduction_weighted); bytemap_reduce(bytemap, method, NULL); } return 0; } static int bytemaplib_slice_gray(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lua_tointeger(L, 2); int y = lua_tointeger(L, 3); int dx = lua_tointeger(L, 4); int dy = lua_tointeger(L, 5); int s = lua_tointeger(L, 6); bytemap_slice_gray(bytemap, x, y, dx, dy, s); } return 0; } static int bytemaplib_slice_rgb(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lua_tointeger(L, 2); int y = lua_tointeger(L, 3); int dx = lua_tointeger(L, 4); int dy = lua_tointeger(L, 5); int r = lua_tointeger(L, 6); int g = lua_tointeger(L, 7); int b = lua_tointeger(L, 8); bytemap_slice_rgb(bytemap, x, y, dx, dy, r, g, b); } return 0; } static int bytemaplib_slice_range(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lua_tointeger(L, 2); int y = lua_tointeger(L, 3); int dx = lua_tointeger(L, 4); int dy = lua_tointeger(L, 5); int min = lua_tointeger(L, 6); int max = lua_tointeger(L, 7); bytemap_slice_range(bytemap, x, y, dx, dy, min, max); } return 0; } static int bytemaplib_bounds(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int value = lua_tointeger(L, 2); int llx = 0; int lly = 1; int urx = bytemap->nx - 1; int ury = bytemap->ny - 1; bytemap_bounds(bytemap, value, &llx, &lly, &urx, &ury); lua_pushinteger(L, llx); lua_pushinteger(L, lly); lua_pushinteger(L, urx); lua_pushinteger(L, ury); return 4; } return 0; } static int bytemaplib_clip(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int value = lua_tointeger(L, 2); bytemap_clip(bytemap, value, NULL); } return 0; } static int bytemaplib_copy(lua_State *L) { bytemap_data *source = bytemaplib_aux_valid(L, 1); if (source) { bytemap_data *target = NULL; if (lua_gettop(L) > 1) { target = bytemaplib_aux_valid(L, 2); } else { target = lua_newuserdatauv(L, sizeof(bytemap_data), 0); if (target) { luaL_setmetatable(L, BYTEMAP_METATABLE); bytemap_wipe(target); } } if (target) { bytemap_copy(source, target, NULL); return 1; } } return 0; } static int bytemaplib_has_byte_gray(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int s = lua_tointeger(L, 2); lua_pushboolean(L, bytemap_has_byte_gray(bytemap, s)); return 1; } return 0; } static int bytemaplib_has_byte_range(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int min = lua_tointeger(L, 2); int max = lua_tointeger(L, 3); lua_pushboolean(L, bytemap_has_byte_range(bytemap, min, max)); return 1; } return 0; } static int bytemaplib_has_byte_rgb(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int r = lmt_tointeger(L, 2); int g = lmt_tointeger(L, 3); int b = lmt_tointeger(L, 4); lua_pushboolean(L, bytemap_has_byte_rgb(bytemap, r, g, b)); } return 0; } static int bytemaplib_set_gray(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lmt_tointeger(L, 2); int y = lmt_tointeger(L, 3); int s = lmt_tointeger(L, 4); bytemap_set_gray(bytemap, x, y, s); } return 0; } static int bytemaplib_set_rgb(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lmt_tointeger(L, 2); int y = lmt_tointeger(L, 3); int r = lmt_tointeger(L, 4); int g = lmt_tointeger(L, 5); int b = lmt_tointeger(L, 6); bytemap_set_rgb(bytemap, x, y, r, g, b); } return 0; } static int bytemaplib_get_byte(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lmt_tointeger(L, 2); int y = lmt_tointeger(L, 3); int z = lmt_tointeger(L, 3); lua_pushinteger(L, bytemap_get_byte(bytemap, x, y, z)); return 1; } return 0; } static int bytemaplib_get_bytes(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int x = lmt_tointeger(L, 2); int y = lmt_tointeger(L, 3); unsigned char b1, b2, b3; bytemap_get_bytes(bytemap, x, y, &b1, &b2, &b3); if (bytemap->nz == 1) { lua_pushinteger(L, b1); return 1; } else { lua_pushinteger(L, b1); lua_pushinteger(L, b2); lua_pushinteger(L, b3); return 3; } } return 0; } static int bytemaplib_get_value(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { int nx = 0; int ny = 0; int nz = 0; char * s = bytemap_get_value(bytemap, &nx, &ny, &nz); lua_pushlstring(L, s, nx * ny * nz); lua_pushinteger(L, nx); lua_pushinteger(L, ny); lua_pushinteger(L, nz); lmt_memory_free(s); return 4; } return 0; } /* This one is modelled after the effects octave one but here there is only some gain when we want access to the values so when the third argument in true because then we save a call and a userdata lookup (which we can actually speed up anyway). */ /* bytemap function [existing] [looptype] */ static inline unsigned char clipped(int i) { return i < 0 ? 0 : i > 255 ? 255 : (unsigned char) i; } static void bytemaplib_aux_loop(lua_State * L, unsigned char * bytemap, int nx, int ny, int nz, int slot) { if (bytemap) { int fn = lua_type(L, slot) == LUA_TFUNCTION; if (fn) { int existing = lua_toboolean(L, slot + 1) ? nz : 0; int loop = lua_tointeger(L, slot + 2); lua_settop(L, slot); if (loop == bytemap_loop_yx) { unsigned char *p = bytemap; for (int y = 0; y < ny; y++) { for (int x = 0; x < nx; x++) { /* we need to retain the function */ lua_pushvalue(L, slot); /* pass to function */ lua_pushinteger(L, x); lua_pushinteger(L, y); if (existing == 3) { lua_pushinteger(L, (int) *p); lua_pushinteger(L, (int) *(p+1)); lua_pushinteger(L, (int) *(p+2)); } else if (existing == 1) { lua_pushinteger(L, (int) *p); } /* call function */ if (lua_pcall(L, existing + 2, nz, 0) != 0) { tex_formatted_warning("bytemaplib", "run bytemap: %s", lua_tostring(L, -1)); } /* use results */ if (nz == 3) { *p++ = clipped(lmt_roundnumber(L, -3)); *p++ = clipped(lmt_roundnumber(L, -2)); } *p++ = clipped(lmt_roundnumber(L, -1)); /* wrap up */ lua_settop(L, slot); } } } else { unsigned char *p = bytemap; for (int x = 0; x < nx; x++) { for (int y = 0; y < ny; y++) { int i = ((ny - y - 1) * nx * nz) + x * nz; /* we need to retain the function */ lua_pushvalue(L, slot); /* pass to function */ lua_pushinteger(L, x); lua_pushinteger(L, y); if (existing == 3) { lua_pushinteger(L, (int) p[i ]); lua_pushinteger(L, (int) p[i+1]); lua_pushinteger(L, (int) p[i+2]); } else if (existing == 1) { lua_pushinteger(L, (int) p[i ]); } /* call function */ if (lua_pcall(L, existing + 2, nz, 0) != 0) { tex_formatted_warning("bytemaplib", "run bytemap: %s", lua_tostring(L, -1)); } /* use results */ if (nz == 3) { p[i++] = clipped(lmt_roundnumber(L, -3)); /* slot + 1 */ p[i++] = clipped(lmt_roundnumber(L, -2)); /* slot + 2 */ } p[i] = clipped(lmt_roundnumber(L, -1)); /* slot + 1 */ /* wrap up */ lua_settop(L, slot); } } } } } } static int bytemaplib_process(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap && bytemap->data) { bytemaplib_aux_loop(L, bytemap->data, bytemap->nx, bytemap->ny, bytemap->nz, 2); } return 0; } static int bytemaplib_downsample(lua_State *L) { bytemap_data *source = bytemaplib_aux_valid(L, 1); bytemap_data *target = bytemaplib_aux_valid(L, 2); if (source && target) { int r = lmt_optinteger(L, 3, 2); bytemap_downsample(source, target, r); } return 0; } int bytemaplib_bytemapped(lua_State * L, unsigned char * bytemap, int nx, int ny, int nz, int slot) { if (bytemap && nx > 0 && ny > 0 && (nz == 1 || nz == 3)) { bytemaplib_aux_loop(L, bytemap, nx, ny, nz, slot); } return 0; } static int bytemaplib_tostring(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap) { lua_pushfstring(L, "", bytemap, bytemap->nx, bytemap->ny, bytemap->nz); /* details */ return 1; } else { return 0; } return 0; } static int bytemaplib_gc(lua_State *L) { bytemap_data *bytemap = bytemaplib_aux_valid(L, 1); if (bytemap && bytemap->data) { lmt_memory_free(bytemap->data); } return 0; } static const luaL_Reg bytemaplib_metatable[] = { { "__tostring", bytemaplib_tostring }, { "__gc", bytemaplib_gc }, { NULL, NULL }, }; static struct luaL_Reg bytemaplib_function_list[] = { { "new", bytemaplib_new }, { "reset", bytemaplib_reset }, { "reduce", bytemaplib_reduce }, { "slicegray", bytemaplib_slice_gray }, { "slicergb", bytemaplib_slice_rgb }, { "slicerange", bytemaplib_slice_range }, { "bounds", bytemaplib_bounds }, { "clip", bytemaplib_clip }, { "copy", bytemaplib_copy }, { "hasbytegray", bytemaplib_has_byte_gray }, { "hasbyterange", bytemaplib_has_byte_range }, { "hasbytergb", bytemaplib_has_byte_rgb }, { "setgray", bytemaplib_set_gray }, { "setrgb", bytemaplib_set_rgb }, { "getbyte", bytemaplib_get_byte }, { "getbytes", bytemaplib_get_bytes }, { "getvalue", bytemaplib_get_value }, { "process", bytemaplib_process }, { "downsample", bytemaplib_downsample }, { NULL, NULL }, }; int luaopen_bytemap(lua_State *L) { luaL_newmetatable(L, BYTEMAP_METATABLE); luaL_setfuncs(L, bytemaplib_metatable, 0); lua_newtable(L); luaL_setfuncs(L, bytemaplib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtvectorlib.h0000644000175000017500000000336415063273560020663 0ustar hillehille/* See license.txt in the root of this project. */ # ifndef LUAVECTORLIB_H # define LUAVECTORLIB_H /* We could use unsigned for rows and columns but it is more work and although it might be a bit more efficient for now we stick to int. We assume sane vectors so the next maxima are actually already over the top. */ # define max_vector_rows 0x00FFFFFF /* we can have many rows if we use vectors for graphic but still ... */ # define max_vector_columns 0x00FFFFFF /* normally there are only a few columns involved so ... */ # define max_vector 0x0FFFFFFF /* so we stay way below |max_vector_rows * max_vector_columns| */ typedef enum vector_classification { generic_type, zero_type, identity_type, // definer product translation_type, // definer product inverse determinant scaling_type, // definer product inverse determinant rotation_type, // definer product inverse determinant affine_type, // definer product inverse determinant } vector_classification; typedef struct vectordata { int rows; int columns; int type; int stacking; int index; int padding; double data[1]; } vectordata; typedef vectordata *vector; # define max_mesh 0xFFFF typedef enum mesh_classification { no_mesh_type = 0x00, dot_mesh_type = 0x01, line_mesh_type = 0x02, triangle_mesh_type = 0x03, quad_mesh_type = 0x04, } mesh_classification; typedef struct meshentry { unsigned short points[4]; double average; } meshentry; typedef struct meshdata { int rows; int type; meshentry data[1]; } meshdata; typedef meshdata *mesh; extern vector vectorlib_get (lua_State *L, int index); # endif luametatex-2.11.08/source/luarest/lmtsparselib.c0000644000175000017500000002362215063273560020650 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" /*tex This module just provides as a more compact alternative for storing bitsets. I have no clue if it ever will be used but we had this sparse tree mechanism so the overhead in terms of code is neglectable. A possible application is bitmaps. Because we cross the c boundary it's about three times slower when we get/set values than staying in \LUA\ although traversing from |min| to |max| is performance wise the same. We could actually gain a bit when we add more helpers (like |inc| and |dec| or so). So, for the moment I consider this a low impact, and thereby undocumented, fun project. */ # define SPARSE_STACK 8 # define SPARSE_STEP 8 # define SPARSE_BYTES 4 typedef struct sa_tree_object { sa_tree tree; int min; int max; } sa_tree_object; static sa_tree_object *sparselib_aux_check_is_sa_object(lua_State *L, int n) { sa_tree_object *o = (sa_tree_object *) lua_touserdata(L, n); if (o && lua_getmetatable(L, n)) { lua_get_metatablelua(sparse_instance); if (! lua_rawequal(L, -1, -2)) { o = NULL; } lua_pop(L, 2); if (o) { return o; } } tex_normal_warning("sparse lib", "lua expected"); return NULL; } /* bytes=0|1|2|4, default=0|* */ static int sparselib_new(lua_State *L) { int bytes = lmt_optinteger(L, 1, SPARSE_BYTES); int defval = lmt_optinteger(L, 2, 0); sa_tree_item item = { .int_value = defval }; sa_tree_object *o = lua_newuserdatauv(L, sizeof(sa_tree_object), 0); switch (bytes) { case 0: { int d = defval < 0 ? 0 : (defval > 0xF ? 0xF : defval); for (int i = 0; i <= 7; i++) { item.uint_value = set_nibble(item.uint_value,i,d); } break; } case 1: { int d = defval < 0 ? 0 : (defval > 0xFF ? 0xFF : defval); for (int i = 0; i <= 3; i++) { item.uchar_value[i] = (unsigned char) d; } break; } case 2: { int d = defval < 0 ? 0 : (defval > 0xFFFF ? 0xFFFF : defval); for (int i = 0; i <= 1; i++) { item.ushort_value[i] = (unsigned short) d; } break; } case 4: break; default: bytes = SPARSE_BYTES; break; } o->tree = sa_new_tree(user_sparse_identifier, SPARSE_STACK, SPARSE_STEP, bytes, item); o->min = -1; o->max = -1; luaL_setmetatable(L, SPARSE_METATABLE_INSTANCE); return 1; } static int sparselib_gc(lua_State *L) { sa_tree_object *o = (sa_tree_object *) lua_touserdata(L, 1); if (o) { sa_destroy_tree(o->tree); } return 0; } static int sparselib_tostring(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { lua_pushfstring(L, "", o->tree); return 1; } else { return 0; } } /* sparse, index, value */ static int sparselib_set(lua_State *L) /* maybe also globalset as fast one */ { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { quarterword level; int slot = lmt_check_for_level(L, 2, &level, cur_level); int n = lmt_tointeger(L, slot++); if (n >= 0) { int v = lmt_optinteger(L, slot++, 1); if (o->min < 0) { o->min = n; o->max = n; } else if (n < o->min) { o->min = n; } else if (n > o->max) { o->max = n; } sa_set_item_n(o->tree, n, v, (int) level); } } return 0; } /* sparse, index */ static int sparselib_get(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { int n = lmt_tointeger(L, 2); if (n >= 0) { lua_pushinteger(L, sa_get_item_n(o->tree, n)); return 1; } } lua_pushnil(L); return 1; } static int sparselib_min(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { lua_pushinteger(L, o->min >= 0 ? o->min : 0); } else { lua_pushnil(L); } return 1; } static int sparselib_max(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { lua_pushinteger(L, o->max >= 0 ? o->max : 0); } else { lua_pushnil(L); } return 1; } static int sparselib_range(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { lua_pushinteger(L, o->min >= 0 ? o->min : 0); lua_pushinteger(L, o->max >= 0 ? o->max : 0); } else { lua_pushnil(L); lua_pushnil(L); } return 2; } static int sparselib_aux_nil(lua_State *L) { lua_pushnil(L); return 1; } static int sparselib_aux_next(lua_State *L) { sa_tree_object *o = (sa_tree_object *) lua_touserdata(L, lua_upvalueindex(1)); int ind = lmt_tointeger(L, lua_upvalueindex(2)); if (ind <= o->max) { lua_pushinteger(L, (lua_Integer) ind + 1); lua_replace(L, lua_upvalueindex(2)); lua_pushinteger(L, ind); lua_pushinteger(L, sa_get_item_n(o->tree, ind)); return 2; } else { return 0; } } static int sparselib_traverse(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o && o->min >= 0) { lua_settop(L, 1); lua_pushinteger(L, o->min); lua_pushcclosure(L, sparselib_aux_next, 2); } else { lua_pushcclosure(L, sparselib_aux_nil, 0); } return 1; } typedef enum concat_options { concat_as_byte = 0, concat_as_lsb = 1, concat_as_msb = 2, } concat_options; static inline char sparselib_aux_concat(sa_tree t, int i) { int h = LMT_SA_H_PART(i); if (t->tree[h]) { int m = LMT_SA_M_PART(i); if (t->tree[h][m]) { return (char) t->tree[h][m][LMT_SA_L_PART(i)/4].uchar_value[i%4]; } else { return (char) t->dflt.uchar_value[i%4]; } } else { return (char) t->dflt.uchar_value[i%4]; } } static int sparselib_concat(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { sa_tree t = o->tree; if (t->bytes == 1) { /* quick hack: we can add whole slices */ luaL_Buffer buffer; int min = lmt_optinteger(L, 2, o->min); int max = lmt_optinteger(L, 3, o->max); int how = lmt_optinteger(L, 4, concat_as_byte); int siz = 0; if (min < 0) { min = 0; } if (max < min) { max = min; } siz = (size_t) max - (size_t) min + 1; luaL_buffinitsize(L, &buffer, siz); switch (how) { case concat_as_lsb: case concat_as_msb: { int n = 0; char b = 0; luaL_buffinitsize(L, &buffer, (siz / 8) + 1); for (int i = min; i <= max; i++) { char c = sparselib_aux_concat(t, i); if (c) { b |= how == concat_as_lsb ? (1 << n) : (1 << (7 - n)); } if (++n == 8) { luaL_addlstring(&buffer, &b, 1); n = 0; } } if (n) { luaL_addlstring(&buffer, &b, 1); } } break; default: { luaL_buffinitsize(L, &buffer, siz); for (int i = min; i <= max; i++) { char c = sparselib_aux_concat(t, i); luaL_addlstring(&buffer, &c, 1); } } break; } luaL_pushresult(&buffer); return 1; } } lua_pushnil(L); return 1; } static int sparselib_restore(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { /* restore_sa_stack(o->tree, cur_level); */ sa_restore_stack(o->tree, cur_level+1); } return 0; } static int sparselib_wipe(lua_State *L) { sa_tree_object *o = sparselib_aux_check_is_sa_object(L, 1); if (o) { int bytes = o->tree->bytes; sa_tree_item dflt = o->tree->dflt; sa_destroy_tree(o->tree); o->tree = sa_new_tree(user_sparse_identifier, SPARSE_STACK, SPARSE_STEP, bytes, dflt); o->min = -1; o->max = -1; } return 0; } static const struct luaL_Reg sparselib_instance[] = { { "__tostring", sparselib_tostring }, { "__gc", sparselib_gc }, { "__index", sparselib_get }, { "__newindex", sparselib_set }, { NULL, NULL }, }; static const luaL_Reg sparselib_function_list[] = { { "new", sparselib_new }, { "set", sparselib_set }, { "get", sparselib_get }, { "min", sparselib_min }, { "max", sparselib_max }, { "range", sparselib_range }, { "traverse", sparselib_traverse }, { "concat", sparselib_concat }, { "restore", sparselib_restore }, { "wipe", sparselib_wipe }, { NULL, NULL }, }; int luaopen_sparse(lua_State *L) { luaL_newmetatable(L, SPARSE_METATABLE_INSTANCE); luaL_setfuncs(L, sparselib_instance, 0); lua_newtable(L); luaL_setfuncs(L, sparselib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtposit.c0000644000175000017500000004473715063273560020034 0ustar hillehille/* See license.txt in the root of this project. */ /*tex This is an experiment using the posit implementation https://gitlab.com/cerlane/SoftPosit#known, which is afaiks the standard. The posit (unum) number system is also available in mplib so that we can play with it (no specific gains there). We need to figure out some helpers (sin, cos, pow etc). Watch out: this is just a playground for me and a few others. There are \CONTEXT\ interfaces but these are also quite experimental. For instance we might move to 64 bit posits. And how about quires. It all depends on developments in this area. The standard is at: https://posithub.org/docs/posit_standard-2.pdf The reference code can be found here: https://gitlab.com/cerlane/SoftPosit However, the implementation lags behind the standard: no posit64 and no functions except from a few that add, subtract, multiply, divide etc. But I will keep an eye in it. Todo: check if we used the right functions (also in auxposit). */ # include # define POSIT_METATABLE "posit number" static inline posit_t *positlib_push(lua_State *L) { posit p = lua_newuserdatauv(L, sizeof(posit_t), 0); luaL_setmetatable(L, POSIT_METATABLE); return p; } static inline int positlib_new(lua_State *L) { posit p = positlib_push(L); switch (lua_type(L, 1)) { case LUA_TSTRING: *p = double_to_posit(lua_tonumber(L, 1)); break; case LUA_TNUMBER: if (lua_isinteger(L, 1)) { *p = i64_to_posit(lua_tointeger(L, 1)); } else { *p = double_to_posit(lua_tonumber(L, 1)); } break; default: p->v = 0; break; } return 1; } static inline int positlib_toposit(lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { posit_t p = double_to_posit(lua_tonumber(L, 1)); lua_pushinteger(L, p.v); } else { lua_pushinteger(L, 0); } return 1; } static inline int positlib_fromposit(lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { posit_t p = { .v = lmt_roundnumber(L, 1) }; lua_pushnumber(L, posit_to_double(p)); } else { lua_pushinteger(L, 0); } return 1; } /* This is nicer for the user. Beware, we create a userdata object on the stack so we need to replace the original non userdata. */ static posit_t *positlib_get(lua_State *L, int i) { switch (lua_type(L, i)) { case LUA_TUSERDATA: return (posit) luaL_checkudata(L, i, POSIT_METATABLE); case LUA_TSTRING: { posit p = positlib_push(L); *p = double_to_posit(lua_tonumber(L, i)); lua_replace(L, i); return p; } case LUA_TNUMBER: { posit p = positlib_push(L); *p = lua_isinteger(L, i) ? integer_to_posit(lua_tointeger(L, i)) : double_to_posit(lua_tonumber(L, i)); lua_replace(L, i); return p; } default: { posit p = positlib_push(L); lua_replace(L, i); return p; } } } static int positlib_tostring(lua_State *L) { posit p = positlib_get(L, 1); double d = posit_to_double(*p); lua_pushnumber(L, d); lua_tostring(L, -1); return 1; } static int positlib_tonumber(lua_State *L) { posit p = positlib_get(L, 1); double d = posit_to_double(*p); lua_pushnumber(L, d); return 1; } static int positlib_copy(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = *a; return 1; } static int positlib_eq(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); lua_pushboolean(L, posit_eq(*a, *b)); return 1; } static int positlib_le(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); lua_pushboolean(L, posit_le(*a, *b)); return 1; } static int positlib_lt(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); lua_pushboolean(L, posit_lt(*a, *b)); return 1; } static int positlib_add(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); *p = posit_add(*a, *b); return 1; } static int positlib_sub(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); *p = posit_sub(*a, *b); return 1; } static int positlib_mul(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); *p = posit_mul(*a, *b); return 1; } static int positlib_div(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); *p = posit_div(*a, *b); return 1; } static int positlib_round(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = posit_round_to_integer(*a); return 1; } static int positlib_rounded(lua_State *L) { posit a = positlib_get(L, 1); lua_pushinteger(L, posit_to_integer(*a)); return 1; } static int positlib_integer(lua_State *L) { posit p = positlib_get(L, 1); lua_pushinteger(L, (lua_Integer) posit_to_i64(*p)); return 1; } static int positlib_NaN(lua_State *L) { posit p = positlib_get(L, 1); lua_pushboolean(L, p->v == (uint32_t) 0x80000000); return 1; } static int positlib_NaR(lua_State *L) { posit p = positlib_get(L, 1); lua_pushboolean(L, posit_is_NaR(p->v)); return 1; } // static int positlib_idiv(lua_State *L) { // return 0; // } // static int positlib_mod(lua_State *L) { // return 0; // } static int positlib_neg(lua_State* L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = posit_neg(*a); return 1; } static int positlib_min(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); *p = posit_lt(*a, *b) ? *a : *b; return 1; } static int positlib_max(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); *p = posit_lt(*a, *b) ? *b : *a; return 1; } static int positlib_pow(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(pow(posit_to_double(*a),posit_to_double(*b))); return 1; } static int positlib_abs(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = posit_abs(*a); return 1; } static int positlib_sqrt(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = posit_sqrt(*a); return 1; } // static int positlib_ln(lua_State *L) // { // posit a = positlib_get(L, 1); // posit p = positlib_push(L); // *p = double_to_posit(ln(posit_to_double(*a))); // return 1; // } static int positlib_log10(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(log10(posit_to_double(*a))); return 1; } static int positlib_log1p(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(log1p(posit_to_double(*a))); return 1; } static int positlib_log2(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(log2(posit_to_double(*a))); return 1; } static int positlib_logb(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(logb(posit_to_double(*a))); return 1; } static int positlib_log(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); if (lua_gettop(L) == 1) { *p = double_to_posit(log(posit_to_double(*a))); } else { posit b = positlib_get(L, 2); double d = posit_to_double(*a); double n = posit_to_double(*b); if (n == 10.0) { n = (lua_Number) log10(d); } else if (n == 2.0) { n = (lua_Number) log2(d); } else { n = (lua_Number) log(d) / (lua_Number) log(n); } *p = double_to_posit(n); } return 1; } static int positlib_exp(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(exp(posit_to_double(*a))); return 1; } static int positlib_exp2(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(exp2(posit_to_double(*a))); return 1; } static int positlib_ceil(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(ceil(posit_to_double(*a))); return 1; } static int positlib_floor(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(floor(posit_to_double(*a))); return 1; } static int positlib_modf(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); posit q = positlib_push(L); double d; *q = double_to_posit(modf(posit_to_double(*a),&d)); *p = double_to_posit(d); return 2; } static int positlib_sin(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(sin(posit_to_double(*a))); return 1; } static int positlib_cos(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(cos(posit_to_double(*a))); return 1; } static int positlib_tan(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(tan(posit_to_double(*a))); return 1; } static int positlib_asin(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(asin(posit_to_double(*a))); return 1; } static int positlib_acos(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(acos(posit_to_double(*a))); return 1; } static int positlib_atan(lua_State *L) { posit a = positlib_get(L, 1); posit p = positlib_push(L); *p = double_to_posit(atan(posit_to_double(*a))); return 1; } static int positlib_rotate(lua_State *L) { posit a = positlib_get(L, 1); lua_Integer n = luaL_optinteger(L, 2, 1); posit p = positlib_push(L); if (n > 0) { p->v = (a->v >> n) | (a->v << (posit_bits - n)); } else if (n < 0) { p->v = (a->v << n) | (a->v >> (posit_bits - n)); } else { p->v = a->v; } return 1; } static int positlib_shift(lua_State *L) { posit a = positlib_get(L, 1); lua_Integer shift = luaL_optinteger(L, 2, 1); posit p = positlib_push(L); if (shift > 0) { p->v = (a->v >> shift) & 0xFFFFFFFF; } else if (shift < 0) { p->v = (a->v << -shift) & 0xFFFFFFFF; } else { p->v = a->v; } return 1; } static int positlib_left(lua_State *L) { posit a = positlib_get(L, 1); lua_Integer shift = luaL_optinteger(L, 2, 1); posit p = positlib_push(L); p->v = (a->v << shift) & 0xFFFFFFFF; return 1; } static int positlib_right(lua_State *L) { posit_t *a = positlib_get(L, 1); lua_Integer shift = - luaL_optinteger(L, 2, 1); posit_t *p = positlib_push(L); p->v = (a->v >> shift) & 0xFFFFFFFF; return 1; } static int positlib_and(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); p->v = (a->v) & (b->v); return 1; } static int positlib_or(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); p->v = (a->v) | (b->v); return 1; } static int positlib_xor(lua_State *L) { posit a = positlib_get(L, 1); posit b = positlib_get(L, 2); posit p = positlib_push(L); p->v = (a->v) ^ (b->v); return 1; } /* experiment */ static int positlib_to_byte(lua_State *L) { posit8_t p = convertDoubleToP8(lua_tonumber(L, 1)); lua_pushinteger(L, (lua_Integer) p.v); return 1; } static int positlib_from_byte(lua_State *L) { posit8_t p = { .v = (uint8_t) lua_tointeger(L, 1) }; lua_pushnumber(L, convertP8ToDouble(p)); return 1; } static int positlib_to_char(lua_State *L) { posit8_t p = convertDoubleToP8(lua_tonumber(L, 1)); char c[1] = { (char) p.v }; lua_pushlstring(L, c, 1); return 1; } static int positlib_from_char(lua_State *L) { size_t l; const char *s = lua_tolstring(L, 1, &l); if (l == 1) { posit8_t p = { .v = (uint8_t) s[0] }; lua_pushnumber(L, convertP8ToDouble(p)); } else { lua_pushnil(L); } return 1; } static int positlib_expand(lua_State *L) { size_t size; const char *data = lua_tolstring(L, 1, &size); if (size > 0) { char *temp = lmt_memory_malloc(size); if (temp) { int expansion = lmt_optinteger(L, 2, 255); for (size_t i = 0; i < size; i++) { posit8_t b = { .v = (unsigned char) data[i] }; temp[i] = (unsigned char) lround(convertP8ToDouble(b) * expansion); } lua_pushlstring(L, (const char *) temp, size); lmt_memory_free(temp); return 1; } } return 0; } static const luaL_Reg positlib_function_list[] = { /* management */ { "new", positlib_new }, { "copy", positlib_copy }, { "tostring", positlib_tostring }, { "tonumber", positlib_tonumber }, { "integer", positlib_integer }, { "rounded", positlib_rounded }, { "toposit", positlib_toposit }, { "fromposit", positlib_fromposit }, /* operators */ { "__add", positlib_add }, // { "__idiv", positlib_idiv }, { "__div", positlib_div }, // { "__mod", positlib_mod }, { "__eq", positlib_eq }, { "__le", positlib_le }, { "__lt", positlib_lt }, { "__mul", positlib_mul }, { "__sub", positlib_sub }, { "__unm", positlib_neg }, { "__pow", positlib_pow }, { "__bor", positlib_or }, { "__bxor", positlib_xor }, { "__band", positlib_and }, { "__shl", positlib_left }, { "__shr", positlib_right }, /* */ { "NaN", positlib_NaN }, { "NaR", positlib_NaR }, /* */ { "bor", positlib_or }, { "bxor", positlib_xor }, { "band", positlib_and }, { "shift", positlib_shift }, { "rotate", positlib_rotate }, /* */ { "min", positlib_min }, { "max", positlib_max }, { "abs", positlib_abs }, { "conj", positlib_neg }, { "modf", positlib_modf }, /* */ { "acos", positlib_acos }, // { "acosh", positlib_acosh }, { "asin", positlib_asin }, // { "asinh", positlib_asinh }, { "atan", positlib_atan }, // { "atan2", positlib_atan2 }, // { "atanh", positlib_atanh }, // { "cbrt", positlib_cbrt }, { "ceil", positlib_ceil }, // { "copysign", positlib_copysign }, { "cos", positlib_cos }, // { "cosh", positlib_cosh }, // { "deg", positlib_deg }, // { "erf", positlib_erf }, // { "erfc", positlib_erfc }, { "exp", positlib_exp }, { "exp2", positlib_exp2 }, // { "expm1", positlib_expm1 }, // { "fabs", positlib_fabs }, // { "fdim", positlib_fdim }, { "floor", positlib_floor }, // { "fma", positlib_fma }, // { "fmax", positlib_fmax }, // { "fmin", positlib_fmin }, // { "fmod", positlib_fmod }, // { "frexp", positlib_frexp }, // { "gamma", positlib_gamma }, // { "hypot", positlib_hypot }, // { "isfinite", positlib_isfinite }, // { "isinf", positlib_isinf }, // { "isnan", positlib_isnan }, // { "isnormal", positlib_isnormal }, // { "j0", positlib_j0 }, // { "j1", positlib_j1 }, // { "jn", positlib_jn }, // { "ldexp", positlib_ldexp }, // { "lgamma", positlib_lgamma }, { "log", positlib_log }, { "log10", positlib_log10 }, { "log1p", positlib_log1p }, { "log2", positlib_log2 }, { "logb", positlib_logb }, // { "modf", positlib_modf }, // { "nearbyint", positlib_nearbyint }, // { "nextafter", positlib_nextafter }, { "pow", positlib_pow }, // { "rad", positlib_rad }, // { "remainder", positlib_remainder }, // { "remquo", positlib_fremquo }, { "round", positlib_round }, // { "scalbn", positlib_scalbn }, { "sin", positlib_sin }, // { "sinh", positlib_sinh }, { "sqrt", positlib_sqrt }, { "tan", positlib_tan }, // { "tanh", positlib_tanh }, // { "tgamma", positlib_tgamma }, // { "trunc", positlib_trunc }, // { "y0", positlib_y0 }, // { "y1", positlib_y1 }, // { "yn", positlib_yn }, /* */ { "tobyte", positlib_to_byte }, { "frombyte", positlib_from_byte }, { "tochar", positlib_to_char }, { "fromchar", positlib_from_char }, { "expand", positlib_expand }, /* */ { NULL, NULL }, }; int luaopen_posit(lua_State *L) { luaL_newmetatable(L, POSIT_METATABLE); luaL_setfuncs(L, positlib_function_list, 0); lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); lua_pushliteral(L, "__tostring"); lua_pushliteral(L, "tostring"); lua_gettable(L, -3); lua_settable(L, -3); lua_pushliteral(L, "__name"); lua_pushliteral(L, "posit"); lua_settable(L, -3); return 1; } luametatex-2.11.08/source/luarest/lmtfilelib.c0000644000175000017500000007220215063273560020270 0ustar hillehille/* See license.txt in the root of this project. This is a replacement for lfs, a file system manipulation library from the Kepler project. I started from the lfs.c file from luatex because we need to keep a similar interface. That file mentioned: Copyright Kepler Project 2003 - 2017 (http://keplerproject.github.io/luafilesystem) The original library offers the following functions: lfs.attributes(filepath [, attributename | attributetable]) lfs.chdir(path) lfs.currentdir() lfs.dir(path) lfs.link(old, new[, symlink]) -- lfs.lock(fh, mode) -- lfs.lock_dir(path) lfs.mkdir(path) lfs.rmdir(path) -- lfs.setmode(filepath, mode) lfs.symlinkattributes(filepath [, attributename]) lfs.touch(filepath [, atime [, mtime]]) -- lfs.unlock(fh) We have additional code in other modules and the code was already adapted a little. In the meantime the code looks quite different. Because \TEX| is multi-platform we try to provide a consistent interface. So, for instance block size and inode number are not relevant for us, nor are user and group ids. The lock functions have been removed as they serve no purpose in a \TEX\ system and devices make no sense either. The iterator could be improved. I also fixed some abnormalities. Permissions are not useful either. */ # include "../lua/lmtinterface.h" # include "../utilities/auxmemory.h" # include "../utilities/auxfile.h" # ifndef R_OK # define F_OK 0x0 # define W_OK 0x2 # define R_OK 0x4 # endif # define DIR_METATABLE "file.directory" # ifndef _WIN32 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # endif # ifdef _WIN32 # ifndef WINVER # define WINVER 0x0601 # undef _WIN32_WINNT # define _WIN32_WINNT 0x0601 # endif # endif // # ifndef _LARGEFILE64_SOURCE # define _LARGEFILE64_SOURCE 1 // # endif # include # include # include # include # include # include // # ifdef _MSC_VER // # ifndef MAX_PATH // # define MAX_PATH 256 // # endif // # endif # ifdef _WIN32 # include # include # include # include # include # include # include /* Todo MS Windows: By default, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, prepend "\\?\" to the path. For more information, see Naming Files, Paths, and Namespaces. */ # ifdef MAX_PATH # define MY_MAXPATHLEN MAX_PATH # else # define MY_MAXPATHLEN 255 # endif # else /* the next one is sensitive for c99 */ # include # include # include # include # include # include # ifdef MAXPATHLEN # define MY_MAXPATHLEN MAXPATHLEN # else # define MY_MAXPATHLEN 255 # endif # endif /* This has to go to the h file. See luainit.c where it's also needed. */ # ifdef _WIN32 # ifndef S_ISDIR # define S_ISDIR(mode) (mode & _S_IFDIR) # endif # ifndef S_ISREG # define S_ISREG(mode) (mode & _S_IFREG) # endif # ifndef S_ISLNK # define S_ISLNK(mode) (0) # endif # ifndef S_ISSUB # define S_ISSUB(mode) (file_data.attrib & _A_SUBDIR) # endif # define info_struct struct _stati64 # define utime_struct struct __utimbuf64 # define exec_mode_flag _S_IEXEC /* There is a difference between msvc and mingw wrt the daylight saving time correction being applied toy the times. I couldn't figure it out and don't want to waste more time on it. */ /* A windows path should not end with a / so maybe we should check for that and remove it when we have one. Even better is to add a period. size_t l = wcslen(w) - 1; if (w[l] == L'/') { w[l] == L'\0'); } */ typedef struct dir_data { intptr_t handle; int closed; char pattern[MY_MAXPATHLEN+1]; } dir_data; static int get_stat(const char *s, info_struct *i) { LPWSTR w = aux_utf8_to_wide(s); int r = _wstati64(w, i); lmt_memory_free(w); return r; } static int mk_dir(const char *s) { LPWSTR w = aux_utf8_to_wide(s); int r = _wmkdir(w); lmt_memory_free(w); return r; } static int ch_dir(const char *s) { LPWSTR w = aux_utf8_to_wide(s); int r = _wchdir(w); lmt_memory_free(w); return r; } static int rm_dir(const char *s) { LPWSTR w = aux_utf8_to_wide(s); int r = _wrmdir(w); lmt_memory_free(w); return r; } // # if defined(__MINGW64__) || defined(__MINGW32__) // extern int CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags); // # endif static int mk_symlink(const char *t, const char *f) { LPWSTR wt = aux_utf8_to_wide(t); LPWSTR wf = aux_utf8_to_wide(f); int r = CreateSymbolicLinkW((LPCWSTR) t, (LPCWSTR) f, 0x2) != 0; lmt_memory_free(wt); lmt_memory_free(wf); return r; } static int mk_link(const char *t, const char *f) { LPWSTR wt = aux_utf8_to_wide(t); LPWSTR wf = aux_utf8_to_wide(f); int r = CreateSymbolicLinkW((LPCWSTR) t, (LPCWSTR) f, 0x3) != 0; lmt_memory_free(wt); lmt_memory_free(wf); return r; } static int ch_to_exec(const char *s, int n) { LPWSTR w = aux_utf8_to_wide(s); int r = _wchmod(w, n); lmt_memory_free(w); return r; } // # ifdef _MSC_VER // // static int set_utime(const char *s, utime_struct *b) // { // LPWSTR w = utf8_to_wide(s); // HANDLE h = CreateFileW(w, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); // int r = -1; // lmt_memory_free(w); // if (h != INVALID_HANDLE_VALUE) { // r = SetFileTime(h, (const struct _FILETIME *) b, (const struct _FILETIME *) b, (const struct _FILETIME *) b); // CloseHandle(h); // } // return r; // } // // # else static int set_utime(const char *s, utime_struct *b) { LPWSTR w = aux_utf8_to_wide(s); int r = _wutime64(w, b); lmt_memory_free(w); return r; } // # endif # else # define info_struct struct stat # define utime_struct struct utimbuf typedef struct dir_data { DIR *handle; int closed; char pattern[MY_MAXPATHLEN+1]; } dir_data; # define get_stat stat # define mk_dir(p) (mkdir((p), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH)) # define ch_dir chdir # define get_cwd getcwd # define rm_dir rmdir # define mk_symlink(f,t) (symlink(f,t) != -1) # define mk_link(f,t) (link(f,t) != -1) # define ch_to_exec(f,n) (chmod(f,n)) # define exec_mode_flag S_IXUSR | S_IXGRP | S_IXOTH # define set_utime(f,b) utime(f,b) # endif # include # include # include /* This function changes the current directory. success = chdir(name) */ static int filelib_chdir(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING) { lua_pushboolean(L, ! ch_dir(luaL_checkstring(L, 1))); } else { lua_pushboolean(L, 0); } return 1; } /* This function returns the current directory or false. name = currentdir() */ # ifdef _WIN32 static int filelib_currentdir(lua_State *L) { LPWSTR wpath = NULL; int size = 256; while (1) { LPWSTR temp = lmt_memory_realloc(wpath, size * sizeof(WCHAR)); wpath = temp; if (! wpath) { lua_pushboolean(L, 0); break; } else if (_wgetcwd(wpath, size)) { char *path = aux_utf8_from_wide(wpath); lua_pushstring(L, path); lmt_memory_free(path); break; } else if (errno != ERANGE) { lua_pushboolean(L, 0); break; } else { size *= 2; } } lmt_memory_free(wpath); return 1; } # else static int filelib_currentdir(lua_State *L) { char *path = NULL; size_t size = MY_MAXPATHLEN; while (1) { path = lmt_memory_realloc(path, size); if (! path) { lua_pushboolean(L,0); break; } if (get_cwd(path, size)) { lua_pushstring(L, path); break; } if (errno != ERANGE) { lua_pushboolean(L,0); break; } size *= 2; } lmt_memory_free(path); return 1; } # endif /* This functions create a link: success = link(target,name,[true=symbolic]) success = symlink(target,name) */ static int filelib_link(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) { const char *oldpath = lua_tostring(L, 1); const char *newpath = lua_tostring(L, 2); lua_pushboolean(L, lua_toboolean(L, 3) ? mk_symlink(oldpath, newpath) : mk_link(oldpath, newpath)); } else { lua_pushboolean(L, 0); } return 1; } static int filelib_symlink(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) { const char *oldpath = lua_tostring(L, 1); const char *newpath = lua_tostring(L, 2); lua_pushboolean(L, mk_symlink(oldpath, newpath)); } else { lua_pushboolean(L, 0); } return 1; } /* This function creates a directory. success = mkdir(name) */ static int filelib_mkdir(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING) { lua_pushboolean(L, mk_dir(lua_tostring(L, 1)) != -1); } else { lua_pushboolean(L, 0); } return 1; } /* This function removes a directory (non-recursive). success = mkdir(name) */ static int filelib_rmdir(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING) { lua_pushboolean(L, rm_dir(luaL_checkstring(L, 1)) != -1); } else { lua_pushboolean(L, 0); } return 1; } /* The directory iterator returns multiple values: for name, mode, size, mtime in dir(path) do ... end For practical reasons we keep the metatable the same. */ # ifdef _WIN32 static inline int push_entry(lua_State *L, struct _wfinddata_t file_data, int details) { char *s = aux_utf8_from_wide(file_data.name); lua_pushstring(L, s); lmt_memory_free(s); if (S_ISSUB(file_data.attrib)) { lua_push_key(directory); } else { lua_push_key(file); } if (details) { lua_pushinteger(L, file_data.size); lua_pushinteger(L, file_data.time_write); return 4; } else { return 2; } } static int filelib_aux_dir_iterator(lua_State *L) { struct _wfinddata_t file_data; int details = 1; dir_data *d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE); lua_getiuservalue(L, 1, 1); details = lua_toboolean(L, -1); lua_pop(L, 1); luaL_argcheck(L, d->closed == 0, 1, "closed directory"); if (d->handle == 0L) { /* first entry */ LPWSTR s = aux_utf8_to_wide(d->pattern); if ((d->handle = _wfindfirst(s, &file_data)) == -1L) { d->closed = 1; lmt_memory_free(s); return 0; } else { lmt_memory_free(s); return push_entry(L, file_data, details); } } else if (_wfindnext(d->handle, &file_data) == -1L) { /* no more entries */ /* lmt_memory_free(d->handle); */ /* is done for us */ _findclose(d->handle); d->closed = 1; return 0; } else { /* successive entries */ return push_entry(L, file_data, details); } } static int filelib_aux_dir_close(lua_State *L) { dir_data *d = (dir_data *) lua_touserdata(L, 1); if (!d->closed && d->handle) { _findclose(d->handle); } d->closed = 1; return 0; } static int filelib_dir(lua_State *L) { const char *path = luaL_checkstring(L, 1); int detail = lua_type(L, 2) == LUA_TBOOLEAN ? lua_toboolean(L, 2) : 1; dir_data *d; lua_pushcfunction(L, filelib_aux_dir_iterator); d = (dir_data *) lua_newuserdatauv(L, sizeof(dir_data), 1); lua_pushboolean(L, detail); lua_setiuservalue(L, -2, 1); luaL_getmetatable(L, DIR_METATABLE); lua_setmetatable(L, -2); d->closed = 0; d->handle = 0L; if (path && strlen(path) > MY_MAXPATHLEN-2) { luaL_error(L, "path too long: %s", path); } else { sprintf(d->pattern, "%s/*", path ? path : "."); /* brrr */ } return 2; } // static int filelib_collect(lua_State *L) // { // const char *path = lua_tostring(L, 1); // if (path) { // if (strlen(path) > MY_MAXPATHLEN-2) { // luaL_error(L, "path too long: %s", path); // } else { // LPWSTR s; // intptr_t handle; // struct _wfinddata_t file_data; // char pattern[MY_MAXPATHLEN+1]; // sprintf(pattern, "%s/*", path ? path : "."); /* brrr */ // s = aux_utf8_to_wide(pattern); // handle = _wfindfirst(s, &file_data); // if (handle != -1L) { // int noffiles = 0; // int nofdirectories = 0; // lua_createtable(L, 4, 0); /* files */ // lua_createtable(L, 0, 0); /* dirs */ // do { // char *s = aux_utf8_from_wide(file_data.name); // if (S_ISSUB(file_data.attrib)) { // if (strcmp(s, "..") != 0 && strcmp(s, ".") != 0) { // lua_pushstring(L, s); // lua_rawseti(L, -2, ++nofdirectories); // } // } else { // lua_pushstring(L, s); // lua_rawseti(L, -3, ++noffiles); // } // lmt_memory_free(s); // } while (_wfindnext(handle, &file_data) != -1L); // _findclose(handle); // return 2; // } else { // _findclose(handle); // } // } // } // lua_pushnil(L); // lua_pushnil(L); // return 2; // } // static int filelib_aux_collect(lua_State *L, const char *path, int noffiles) // { // if (path) { // if (strlen(path) > MY_MAXPATHLEN-2) { // luaL_error(L, "path too long: %s", path); // } else { // LPWSTR s; // intptr_t handle; // struct _wfinddata_t file_data; // char pattern[MY_MAXPATHLEN+1]; // sprintf(pattern, "%s/*", path ? path : "."); /* brrr */ // s = aux_utf8_to_wide(pattern); // handle = _wfindfirst(s, &file_data); // if (handle != -1L) { // do { // char *s = aux_utf8_from_wide(file_data.name); // if (S_ISSUB(file_data.attrib)) { // if (strcmp(s, "..") != 0 && strcmp(s, ".") != 0) { // char complete[5*MY_MAXPATHLEN+1]; /* utf filename */ // if (path) { // sprintf(complete, "%s/%s", path, s); /* brrr */ // noffiles = filelib_aux_collect(L, complete, noffiles); // } else { // noffiles = filelib_aux_collect(L, s, noffiles); // } // } // } else { // char complete[5*MY_MAXPATHLEN+1]; /* utf filename */ // if (path) { // sprintf(complete, "%s/%s", path, s); /* brrr */ // lua_pushstring(L, complete); // } else { // lua_pushstring(L, s); // } // lua_rawseti(L, -2, ++noffiles); // } // lmt_memory_free(s); // } while (_wfindnext(handle, &file_data) != -1L); // _findclose(handle); // } // _findclose(handle); // } // } // return noffiles; // } // // static int filelib_collect(lua_State *L) // { // const char *path = lua_tostring(L, 1); // lua_createtable(L, 0, 0); // if (path) { // filelib_aux_collect(L, path, 0); // } // return 1; // } # else /*tex On unix we cannot get the size and time in one go without interference. Also, not all file systems return this field. So eventually we might not do this on unix and revert to the slower method at the lua end when DT_DIR is undefined. After a report from the mailing list about symbolic link issues this is what Taco and I came up with. The |_less| variant is mainly there because in \UNIX\ we then can avoid a costly |stat| when we don't need the details (only a symlink demands such a |stat|). */ static int filelib_aux_dir_iterator(lua_State *L) { struct dirent *entry; dir_data *d; int details = 1; lua_pushcfunction(L, filelib_aux_dir_iterator); d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE); lua_getiuservalue(L, 1, 1); details = lua_toboolean(L, -1); lua_pop(L, 1); luaL_argcheck(L, d->closed == 0, 1, "closed directory"); entry = readdir (d->handle); if (entry) { lua_pushstring(L, entry->d_name); # ifdef _DIRENT_HAVE_D_TYPE if (! details) { if (entry->d_type == DT_DIR) { lua_push_key(directory); return 2; } else if (entry->d_type == DT_REG) { lua_push_key(file); return 2; } } # endif /*tex We can have a symlink and/or we need the details an dfor both we need to |get_stat|. */ { info_struct info; char file_path[2*MY_MAXPATHLEN]; snprintf(file_path, 2*MY_MAXPATHLEN, "%s/%s", d->pattern, entry->d_name); if (! get_stat(file_path, &info)) { if (S_ISDIR(info.st_mode)) { lua_push_key(directory); } else if (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) { lua_push_key(file); } else { lua_pushnil(L); return 2; } if (details) { lua_pushinteger(L, info.st_size); lua_pushinteger(L, info.st_mtime); return 4; } } else { lua_pushnil(L); } return 2; } } else { closedir(d->handle); d->closed = 1; return 0; } } static int filelib_aux_dir_close(lua_State *L) { dir_data *d = (dir_data *) lua_touserdata(L, 1); if (!d->closed && d->handle) { closedir(d->handle); } d->closed = 1; return 0; } static int filelib_dir(lua_State *L) { const char *path = luaL_checkstring(L, 1); dir_data *d; lua_pushcfunction(L, filelib_aux_dir_iterator); d = (dir_data *) lua_newuserdatauv(L, sizeof(dir_data), 1); lua_pushboolean(L, lua_type(L, 2) == LUA_TBOOLEAN ? lua_toboolean(L, 2) : 1); lua_setiuservalue(L, -2, 1); luaL_getmetatable(L, DIR_METATABLE); lua_setmetatable(L, -2); d->closed = 0; d->handle = opendir(path ? path : "."); if (! d->handle) { luaL_error(L, "cannot open %s: %s", path, strerror(errno)); } snprintf(d->pattern, MY_MAXPATHLEN, "%s", path ? path : "."); return 2; } # endif static int dir_create_meta(lua_State *L) { luaL_newmetatable(L, DIR_METATABLE); lua_newtable(L); lua_pushcfunction(L, filelib_aux_dir_iterator); lua_setfield(L, -2, "next"); lua_pushcfunction(L, filelib_aux_dir_close); lua_setfield(L, -2, "close"); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, filelib_aux_dir_close); lua_setfield(L, -2, "__gc"); return 1; } # define mode2string(mode) \ ((S_ISREG(mode)) ? "file" : ((S_ISDIR(mode)) ? "directory" : ((S_ISLNK(mode)) ? "link" : "other"))) /* We keep this for a while: will change to { r, w, x hash } */ # ifdef _WIN32 static const char *perm2string(unsigned short mode) { static char perms[10] = "---------"; /* persistent change hence the for loop */ for (int i = 0; i < 9; i++) { perms[i]='-'; } if (mode & _S_IREAD) { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; } if (mode & _S_IWRITE) { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; } if (mode & _S_IEXEC) { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; } return perms; } # else static const char *perm2string(mode_t mode) { static char perms[10] = "---------"; /* persistent change hence the for loop */ for (int i = 0; i < 9; i++) { perms[i]='-'; } if (mode & S_IRUSR) perms[0] = 'r'; if (mode & S_IWUSR) perms[1] = 'w'; if (mode & S_IXUSR) perms[2] = 'x'; if (mode & S_IRGRP) perms[3] = 'r'; if (mode & S_IWGRP) perms[4] = 'w'; if (mode & S_IXGRP) perms[5] = 'x'; if (mode & S_IROTH) perms[6] = 'r'; if (mode & S_IWOTH) perms[7] = 'w'; if (mode & S_IXOTH) perms[8] = 'x'; return perms; } # endif /* The next one sets access time and modification values for a file: utime(filename) : current, current utime(filename,acess) : access, access utime(filename,acess,modification) : access, modification */ static int filelib_touch(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING) { const char *file = luaL_checkstring(L, 1); utime_struct utb, *buf; if (lua_gettop(L) == 1) { buf = NULL; } else { utb.actime = (time_t) luaL_optinteger(L, 2, 0); utb.modtime = (time_t) luaL_optinteger(L, 3, utb.actime); buf = &utb; } lua_pushboolean(L, set_utime(file, buf) != -1); } else { lua_pushboolean(L, 0); } return 1; } static void push_st_mode (lua_State *L, info_struct *info) { lua_pushstring (L, mode2string (info->st_mode)); } /* inode protection mode */ static void push_st_size (lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_size); } /* file size, in bytes */ static void push_st_mtime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_mtime); } /* time of last data modification */ static void push_st_atime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_atime); } /* time of last access */ static void push_st_ctime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_ctime); } /* time of last file status change */ static void push_st_perm (lua_State *L, info_struct *info) { lua_pushstring (L, perm2string (info->st_mode)); } /* permissions string */ static void push_st_nlink(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_nlink); } /* number of hard links to the file */ typedef void (*push_info_struct_function) (lua_State *L, info_struct *info); struct file_stat_members { const char *name; push_info_struct_function push; }; static struct file_stat_members members[] = { { "mode", push_st_mode }, { "size", push_st_size }, { "modification", push_st_mtime }, { "access", push_st_atime }, { "change", push_st_ctime }, { "permissions", push_st_perm }, { "nlink", push_st_nlink }, { NULL, NULL }, }; /* Get file or symbolic link information. Returns a table or nil. */ static int filelib_attributes(lua_State *L) { if (lua_type(L, 1) == LUA_TSTRING) { info_struct info; const char *file = luaL_checkstring(L, 1); if (get_stat(file, &info)) { /* bad news */ } else if (lua_isstring(L, 2)) { const char *member = lua_tostring(L, 2); for (int i = 0; members[i].name; i++) { if (strcmp(members[i].name, member) == 0) { members[i].push(L, &info); return 1; } } } else { lua_settop(L, 2); if (! lua_istable(L, 2)) { lua_createtable(L, 0, 6); } for (int i = 0; members[i].name; i++) { lua_pushstring(L, members[i].name); members[i].push(L, &info); lua_rawset(L, -3); } return 1; } } lua_pushnil(L); return 1; } # define is_whatever(L,IS_OK,okay) do { \ if (lua_type(L, 1) == LUA_TSTRING) { \ info_struct info; \ const char *name = lua_tostring(L, 1); \ if (get_stat(name, &info)) { \ lua_pushboolean(L, 0); \ } else { \ lua_pushboolean(L, okay && ! access(name, IS_OK)); \ } \ } else { \ lua_pushboolean(L, 0); \ } \ return 1; \ } while(1) static int filelib_isdir (lua_State *L) { is_whatever(L, F_OK,(S_ISDIR(info.st_mode))); } static int filelib_isreadabledir (lua_State *L) { is_whatever(L, R_OK,(S_ISDIR(info.st_mode))); } static int filelib_iswriteabledir (lua_State *L) { is_whatever(L, W_OK,(S_ISDIR(info.st_mode))); } static int filelib_isfile (lua_State *L) { is_whatever(L, F_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); } static int filelib_isreadablefile (lua_State *L) { is_whatever(L, R_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); } static int filelib_iswriteablefile(lua_State *L) { is_whatever(L, W_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); } static int filelib_setexecutable(lua_State *L) { int ok = 0; if (lua_type(L, 1) == LUA_TSTRING) { info_struct info; const char *name = lua_tostring(L, 1); if (! get_stat(name, &info) && S_ISREG(info.st_mode)) { if (ch_to_exec(name, info.st_mode | exec_mode_flag)) { /* the setting failed */ } else { ok = 1; } } else { /* not a valid file */ } } lua_pushboolean(L, ok); return 1; } /* Push the symlink target to the top of the stack. Assumes the file name is at position 1 of the stack. Returns 1 if successful (with the target on top of the stack), 0 on failure (with stack unchanged, and errno set). link("name") : table link("name","target") : targetname */ static int filelib_symlinktarget(lua_State *L) { const char *file = aux_utf8_readlink(luaL_checkstring(L, 1)); if (file) { lua_pushstring(L, file); } else { lua_pushnil(L); } return 1; } static const struct luaL_Reg filelib_function_list[] = { { "attributes", filelib_attributes }, { "chdir", filelib_chdir }, { "currentdir", filelib_currentdir }, { "dir", filelib_dir }, { "mkdir", filelib_mkdir }, { "rmdir", filelib_rmdir }, { "touch", filelib_touch }, /* */ // { "collect", filelib_collect }, /* */ { "link", filelib_link }, { "symlink", filelib_symlink }, { "setexecutable", filelib_setexecutable }, { "symlinktarget", filelib_symlinktarget }, /* */ { "isdir", filelib_isdir }, { "isfile", filelib_isfile }, { "iswriteabledir", filelib_iswriteabledir }, { "iswriteablefile", filelib_iswriteablefile }, { "isreadabledir", filelib_isreadabledir }, { "isreadablefile", filelib_isreadablefile }, /* */ { NULL, NULL }, }; int luaopen_filelib(lua_State *L) { dir_create_meta(L); luaL_newlib(L,filelib_function_list); return 1; } luametatex-2.11.08/source/luarest/lmteffectslib.h0000644000175000017500000000064415063273560020776 0ustar hillehille/* See license.txt in the root of this project. */ # ifndef LUAEFFECTSLIB_H # define LUAEFFECTSLIB_H /*tex On the \LUA\ stack: [1] : mandate octave userdata [2] : optional color function */ extern int effectslib_octave_bytemapped( lua_State * L, unsigned char * bytemap, int nx, int ny, int nz, int slot ); # endif luametatex-2.11.08/source/luarest/lmtziplib.c0000644000175000017500000001515415063273560020156 0ustar hillehille/* See license.txt in the root of this project. */ # define ZLIB_CONST 1 # include "luametatex.h" /*tex This is a rather minimalistic interface to zlib. We can wrap around it and need some specific file overhead anyway. Also, we never needed all that stream stuff. */ # define ziplib_in_char_ptr const unsigned char * # define ziplib_out_char_ptr unsigned char * # define ziplib_buffer_size 16*1024 static int ziplib_aux_compress( lua_State *L, const char *data, int size, int level, int method, int window, int memory, int strategy, int buffersize ) { int state; z_stream zipstream; zipstream.zalloc = &lmt_zlib_alloc; /* Z_NULL */ zipstream.zfree = &lmt_zlib_free; /* Z_NULL */ zipstream.next_out = Z_NULL; zipstream.avail_out = 0; zipstream.next_in = Z_NULL; zipstream.avail_in = 0; state = deflateInit2(&zipstream, level, method, window, memory, strategy); if (state == Z_OK) { luaL_Buffer buffer; luaL_buffinit(L, &buffer); zipstream.next_in = (ziplib_in_char_ptr) data; zipstream.avail_in = size; while (1) { zipstream.next_out = (ziplib_out_char_ptr) luaL_prepbuffsize(&buffer, buffersize); zipstream.avail_out = buffersize; state = deflate(&zipstream, Z_FINISH); if (state != Z_OK && state != Z_STREAM_END) { lua_pushnil(L); break; } else { luaL_addsize(&buffer, buffersize - zipstream.avail_out); if (zipstream.avail_out != 0) { luaL_pushresult(&buffer); break; } } } deflateEnd(&zipstream); } else { lua_pushnil(L); } return 1; } static int ziplib_compress(lua_State *L) /* data compresslevel method window memory strategy */ { const char *data = luaL_checkstring(L, 1); int size = (int) lua_rawlen(L, 1); int level = lmt_optinteger(L, 2, Z_DEFAULT_COMPRESSION); int method = lmt_optinteger(L, 3, Z_DEFLATED); int window = lmt_optinteger(L, 4, 15); int memory = lmt_optinteger(L, 5, 8); int strategy = lmt_optinteger(L, 6, Z_DEFAULT_STRATEGY); return ziplib_aux_compress(L, data, size, level, method, window, memory, strategy, ziplib_buffer_size); } static int ziplib_compresssize(lua_State *L) /* data size compresslevel window */ { const char *data = luaL_checkstring(L, 1); int size = (int) lua_rawlen(L, 1); int buffersize = lmt_optinteger(L, 2, ziplib_buffer_size); int level = lmt_optinteger(L, 3, Z_DEFAULT_COMPRESSION); int window = lmt_optinteger(L, 4, 15); /* like decompresssize */ return ziplib_aux_compress(L, data, size, level, Z_DEFLATED, window, 8, Z_DEFAULT_STRATEGY, buffersize); } static int ziplib_decompress(lua_State *L) { const char *data = luaL_checkstring(L, 1); int size = (int) lua_rawlen(L, 1); int window = lmt_optinteger(L, 2, 15); int state; z_stream zipstream; zipstream.zalloc = &lmt_zlib_alloc; /* Z_NULL */ zipstream.zfree = &lmt_zlib_free; /* Z_NULL */ zipstream.next_out = Z_NULL; zipstream.avail_out = 0; zipstream.next_in = Z_NULL; zipstream.avail_in = 0; state = inflateInit2(&zipstream, window); if (state == Z_OK) { luaL_Buffer buffer; luaL_buffinit(L, &buffer); zipstream.next_in = (ziplib_in_char_ptr) data; zipstream.avail_in = size; while (1) { zipstream.next_out = (ziplib_out_char_ptr) luaL_prepbuffsize(&buffer, ziplib_buffer_size); zipstream.avail_out = ziplib_buffer_size; state = inflate(&zipstream, Z_NO_FLUSH); luaL_addsize(&buffer, ziplib_buffer_size - zipstream.avail_out); if (state == Z_STREAM_END) { luaL_pushresult(&buffer); break; } else if (state != Z_OK) { lua_pushnil(L); break; } else if (zipstream.avail_out == 0) { continue; } else if (zipstream.avail_in == 0) { luaL_pushresult(&buffer); break; } } inflateEnd(&zipstream); } else { lua_pushnil(L); } return 1; } static int ziplib_decompresssize(lua_State *L) { const char *data = luaL_checkstring(L, 1); int size = (int) lua_rawlen(L, 1); int targetsize = lmt_tointeger(L, 2); int window = lmt_optinteger(L, 3, 15); int state; z_stream zipstream; zipstream.zalloc = &lmt_zlib_alloc; /* Z_NULL */ zipstream.zfree = &lmt_zlib_free; /* Z_NULL */ zipstream.next_out = Z_NULL; zipstream.avail_out = 0; zipstream.next_in = Z_NULL; zipstream.avail_in = 0; state = inflateInit2(&zipstream, window); if (state == Z_OK) { luaL_Buffer buffer; zipstream.next_in = (ziplib_in_char_ptr) data; zipstream.avail_in = size; zipstream.next_out = (ziplib_out_char_ptr) luaL_buffinitsize(L, &buffer, (lua_Integer) targetsize + 100); zipstream.avail_out = targetsize + 100; state = inflate(&zipstream, Z_NO_FLUSH); /* maybe Z_FINISH buffer large enough */ if (state != Z_OK && state != Z_STREAM_END) { lua_pushnil(L); } else if (zipstream.avail_in == 0) { luaL_pushresultsize(&buffer, targetsize); } else { lua_pushnil(L); } inflateEnd(&zipstream); } else { lua_pushnil(L); } return 1; } static int ziplib_adler32(lua_State *L) { int checksum = lmt_optinteger(L, 2, 0); size_t buffersize = 0; const char *buffer = lua_tolstring(L, 1, &buffersize); checksum = adler32(checksum, (ziplib_in_char_ptr) buffer, (unsigned int) buffersize); lua_pushinteger(L, checksum); return 1; } static int ziplib_crc32(lua_State *L) { int checksum = lmt_optinteger(L, 2, 0); size_t buffersize = 0; const char *buffer = lua_tolstring(L, 1, &buffersize); checksum = crc32(checksum, (ziplib_in_char_ptr) buffer, (unsigned int) buffersize); lua_pushinteger(L, checksum); return 1; } static struct luaL_Reg ziplib_function_list[] = { { "compress", ziplib_compress }, { "compresssize", ziplib_compresssize }, { "decompress", ziplib_decompress }, { "decompresssize", ziplib_decompresssize }, { "adler32", ziplib_adler32 }, { "crc32", ziplib_crc32 }, { NULL, NULL }, }; int luaopen_xzip(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, ziplib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtvectorlib.c0000644000175000017500000027557015063273560020670 0ustar hillehille/* See license.txt in the root of this project. */ /*tex This is just an experiment by Mikael and Hans in the perspective of 3D experiments in \METAPOST\ with the \LUA\ interface. It is also a kind of follow up on the \type {matrix} module from which we took some of the code. So we have a mix of Jeong Dalyoung, Mikael Sundqvist & Hans Hagen code here. More methods might be added. This module is sort of generic but also geared at using on combination with \METAPOST, which is why we have a few public functions. For that we have extra helpers that work on meshes. */ # include # include "libraries/triangles/triangles.h" # define VECTOR_METATABLE "vector" # define MESH_METATABLE "mesh" /* todo: -- maybe also store size (more readable, less clutter) -- extra array for w (doubles) -- userdata lua upvalue for whatever extras */ static const char *mesh_names[5] = { [no_mesh_type] = "no", [dot_mesh_type] = "dot", [line_mesh_type] = "line", [triangle_mesh_type] = "triangle", [quad_mesh_type] = "quad" }; # define valid_mesh(n) (n >= dot_mesh_type && n <= quad_mesh_type ? n : triangle_mesh_type) /*tex We need to be way above EPSILON in triangles.c because otherwise we get too many false positives at that end! For practical reason we now use a configurable epsilon because we need to interplay nicely with the overlap detection. Alas. \starttyping const double p_epsilon = 0.000001; const double m_epsilon = -0.000001; static inline int iszero(double d) { return d > m_epsilon && d < p_epsilon; } \stoptyping So we now do this: */ # define vector_epsilon_default 1.0e-06 static double vector_epsilon = vector_epsilon_default; # define ISZERO(d) (fabs(d) < epsilon) static int vectorlib_setepsilon(lua_State *L) { vector_epsilon = lmt_optdouble(L, 1, vector_epsilon_default); return 1; } static int vectorlib_getepsilon(lua_State *L) { lua_pushnumber(L, lua_toboolean(L, 1) ? vector_epsilon_default : vector_epsilon); return 1; } static int vectorlib_iszero(lua_State *L) { double epsilon = lmt_optdouble(L, 2, vector_epsilon); lua_pushboolean(L, ISZERO(lua_tonumber(L, 1))); return 1; } static inline int vectorlib_aux_zero_in_column(const vector a, int c, double epsilon) { for (int r = 0; r < a->rows; r++) { if (ISZERO(a->data[r * a->columns + c])) { return 1; } } return 0; } // static inline int vectorlib_aux_zero_in_row(const vector a, int r, double epsilon) // { // for (int c = 0; c < a->columns; c++) { // if (ISZERO(a->data[r * a->columns + c])) { // return 1; // } // } // return 0; // } /* let the compiled deal with this: */ /* memcpy(v->data, a->data,a->rows * a->columns * sizeof(double)); */ inline static void vectorlib_aux_copy_data(vector v, const vector a) { for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i]; } } /* We let \LUA\ manage the temporary vectors if needed which sometimes means that we push too many intermediate nil's too but it's harmless. */ static inline vector vectorlib_aux_push(lua_State *L, int r, int c, int s) { if (r >= max_vector_rows || c >= max_vector_columns || r*c > max_vector) { tex_formatted_error("vector lib", "you can have %i rows, %i columns and at most %i entries", max_vector_rows, max_vector_columns, max_vector); return NULL; } else { vector v = lua_newuserdatauv(L, 6 * sizeof(int) + r * c * sizeof(double), 0); if (v && r > 0 && c > 0) { v->rows = r; v->columns = c; v->type = generic_type; v->stacking = s; v->index = 0; v->padding = 0; lua_get_metatablelua(vector_instance); lua_setmetatable(L, -2); } return v; } } static vector vectorlib_aux_maybe_isvector(lua_State *L, int index) { vector v = lua_touserdata(L, index); if (v && lua_getmetatable(L, index)) { lua_get_metatablelua(vector_instance); if (! lua_rawequal(L, -1, -2)) { v = NULL; } lua_pop(L, 2); } return v; } static int vectorlib_isvector(lua_State *L) { lua_pushboolean(L, vectorlib_aux_maybe_isvector(L, 1) ? 1 : 0); return 1; } static int vectorlib_type(lua_State *L) { if (vectorlib_aux_maybe_isvector(L, 1)) { lua_push_key(vector); } else { lua_pushnil(L); } return 1; } /* tex Only |{ { 1,2,3 }, { 4,5,6 } }| here as we can mix. */ static int vectorlib_aux_be_nice(lua_State *L, int index) { /* We know that we have a table. */ int rows = (int) lua_rawlen(L, index); int columns = lua_rawgeti(L, index, 1) == LUA_TTABLE ? (int) lua_rawlen(L, -1) : 0; lua_pop(L, 1); if (rows && columns) { vector v = vectorlib_aux_push(L, rows, columns, 0); for (int r = 0; r < rows; r++) { long target = r * columns; if (lua_rawgeti(L, index, r + 1) == LUA_TTABLE) { for (int c = 0; c < columns; c++) { v->data[target++] = lua_rawgeti(L, -1, c + 1) == LUA_TNUMBER ? lua_tonumber(L, -1) : 0.0; lua_pop(L, 1); } } else { for (int c = 0; c < columns; c++) { v->data[target++] = 0.0; } } lua_pop(L, 1); } return 1; } lua_pushnil(L); return 1; } inline static vector vectorlib_aux_get(lua_State *L, int index) { switch (lua_type(L, index)) { case LUA_TUSERDATA: { vector v = lua_touserdata(L, index); if (v && lua_getmetatable(L, index)) { lua_get_metatablelua(vector_instance); if (! lua_rawequal(L, -1, -2)) { v = NULL; } lua_pop(L, 2); } return v; } case LUA_TTABLE: { vectorlib_aux_be_nice(L, index); if (lua_type(L, -1) == LUA_TUSERDATA) { vector v = lua_touserdata(L, -1); lua_replace(L, index); return v; } else { lua_pop(L, 1); break; } } default: break; } return NULL; } static int vectorlib_new(lua_State *L) { switch (lua_type(L, 1)) { case LUA_TNUMBER: { /* local v = vector.new( 2, 3 ) */ /* local v = vector.new( 2, 3, 1,2,3, 4,5,6 ) */ /* local v = vector.new( 2, 3, { 1,2,3 }, { 4,5,6 } ) */ /* maybe */ /* local v = vector.new( 2, 3, { 1,2,3 , 4,5,6 } ) */ /* maybe */ int t = lua_gettop(L) - 2; vector v = vectorlib_aux_push(L, lmt_optinteger(L, 1, 1), lmt_optinteger(L, 2, 1), 0); if (t) { if (t > v->rows * v->columns) { t = v->rows * v->columns; } for (int i = 0; i < t; i++) { v->data[i] = lua_type(L, i + 3) == LUA_TNUMBER ? lua_tonumber(L, i + 3) : 0.0; } } else { for (int i = 0; i < v->rows * v->columns; i++) { v->data[i] = 0.0; } } return 1; } case LUA_TTABLE: { int n = (int) lua_rawlen(L, 1); int t = lua_rawgeti(L, 1, 1); lua_pop(L, 1); switch (t) { case LUA_TNUMBER: /* local v = vector.new( { 1,2,3 }, { 4,5,6 } ) */ { int columns = n; int rows = lua_gettop(L); if (rows && columns) { vector v = vectorlib_aux_push(L, rows, columns, 0); for (int r = 0; r < rows; r++) { long index = r * columns; if (lua_type(L, r + 1) == LUA_TTABLE) { for (int c = 0; c < columns; c++) { if (lua_rawgeti(L, r + 1, c + 1) == LUA_TNUMBER) { v->data[index++] = lua_tonumber(L, -1); } else { v->data[index++] = 0.0; } lua_pop(L, 1); } } else { for (int c = 0; c < columns; c++) { v->data[index++] = 0.0; } } } return 1; } else { break; } } case LUA_TTABLE: { /* local v = vector.new( { { 1,2,3 }, { 4,5,6 } } ) */ int type = (int) lua_rawgeti(L, 1, 1); int rows = (int) lua_rawlen(L, 1); int columns = 0; switch (type) { case LUA_TTABLE: columns = (int) lua_rawlen(L, -1); break; case LUA_TUSERDATA: { vector a = vectorlib_aux_get(L, 1); if (a) { columns = a->columns; } break; } } lua_pop(L, 1); if (rows && columns) { vector v = vectorlib_aux_push(L, rows, columns, 0); long index = 0; for (int r = 1; r <= rows; r++) { switch (lua_rawgeti(L, 1, r)) { case LUA_TTABLE: { for (int c = 1; c <= columns; c++) { if (lua_rawgeti(L, -1, c) == LUA_TNUMBER) { v->data[index++] = lua_tonumber(L, -1); } else { v->data[index++] = 0.0; } lua_pop(L, 1); } break; } case LUA_TUSERDATA: { vector a = vectorlib_aux_get(L, 1); if (a && a->columns * a->rows == columns) { long source = 0; for (int c = 0; c < columns; c++) { v->data[index++] = a->data[source++]; } break; } else { /* fall through */ } } default: { for (int c = 0; c < columns; c++) { v->data[index++] = 0.0; } break; } } lua_pop(L, 1); } return 1; } else { break; } } default: break; } break; } } lua_pushnil(L); return 0; } static inline int vectorlib_onerow(lua_State *L) { int t = lua_gettop(L); if (t) { vector v = vectorlib_aux_push(L, 1, t, 0); for (int i = 0; i < t; i++) { v->data[i] = lua_tonumber(L, i + 1); } } else { lua_pushnil(L); } return 1; } static inline int vectorlib_onecolumn(lua_State *L) { int t = lua_gettop(L); if (t) { vector v = vectorlib_aux_push(L, t, 1, 0); for (int i = 0; i < t; i++) { v->data[i] = lua_tonumber(L, i + 1); } } else { lua_pushnil(L); } return 1; } vector vectorlib_get(lua_State *L, int index) { if (lua_type(L, index) == LUA_TUSERDATA) { return (vector) luaL_checkudata(L, index, VECTOR_METATABLE); } else { return NULL; } } static int vectorlib_tostring(lua_State *L) { vector v = vectorlib_aux_get(L, 1); if (v) { lua_pushfstring(L, "", v->rows, v->columns, v); return 1; } else { return 0; } } static int vectorlib_totable(lua_State *L) { vector v = vectorlib_aux_maybe_isvector(L, 1); if (v) { long source = 0; if (lua_toboolean(L, 2)) { lua_createtable(L, v->rows * v->columns, 0); for (int i = 1; i <= v->rows * v->columns; i++) { lua_pushnumber(L, v->data[source++]); lua_rawseti(L, -2, i); } } else { lua_createtable(L, v->rows, 0); for (int r = 1; r <= v->rows; r++) { lua_createtable(L, v->columns, 0); for (int c = 1; c <= v->columns; c++) { lua_pushnumber(L, v->data[source++]); lua_rawseti(L, -2, c); } lua_rawseti(L, -2, r); } } return 1; } else { return 0; } } static int vectorlib_aux_copy(lua_State *L, int index) { vector a = vectorlib_aux_get(L, index); if (a) { /* could be a mem copy */ vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); v->type = a->type; vectorlib_aux_copy_data(v, a); } else { lua_pushnil(L); } return 1; } static int vectorlib_copy(lua_State *L) { return vectorlib_aux_copy(L, 1); } static int vectorlib_eq(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); int result = 1; if (a && b && a->rows == b->rows && a->columns == b->columns) { /* we can do a memcmp but we can have negative zero etc */ for (int i = 0; i < b->rows * b->columns; i++) { if (a->data[i] != b->data[i]) { result = 0; break; } } } else { result = 0; } lua_pushboolean(L, result); return 1; } static int vectorlib_add(lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { vector b = vectorlib_aux_get(L, 2); if (b) { double d = lua_tonumber(L, 1); vector v = vectorlib_aux_push(L, b->rows, b->columns, b->stacking); for (int i = 0; i < b->rows * b->columns; i++) { v->data[i] = b->data[i] + d; } } else { lua_pushnil(L); } } else if (lua_type(L, 2) == LUA_TNUMBER) { vector a = vectorlib_aux_get(L, 1); if (a) { double d = lua_tonumber(L, 2); vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i] + d; } } else { lua_pushnil(L); } } else { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b && a->rows == b->rows && a->columns == b->columns) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i] + b->data[i]; } } else { lua_pushnil(L); } } return 1; } static int vectorlib_sub(lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { vector b = vectorlib_aux_get(L, 2); if (b) { double d = lua_tonumber(L, 1); vector v = vectorlib_aux_push(L, b->rows, b->columns, b->stacking); for (int i = 0; i < b->rows * b->columns; i++) { v->data[i] = b->data[i] - d; } } else { lua_pushnil(L); } } else if (lua_type(L, 2) == LUA_TNUMBER) { vector a = vectorlib_aux_get(L, 1); if (a) { double d = lua_tonumber(L, 2); vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i] - d; } } else { lua_pushnil(L); } } else { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b && a->rows == b->rows && a->columns == b->columns) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i] - b->data[i]; } } else { lua_pushnil(L); } } return 1; } static int vectorlib_product(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b && a->columns == b->rows) { vector v = vectorlib_aux_push(L, a->rows, b->columns, b->stacking); /* not a->stacking */ for (int ra = 0; ra < a->rows; ra++) { /* loop over rows a : a[r] */ for (int cb = 0; cb < b->columns; cb++) { /* loop over columns b */ double d = 0; for (int i = 0; i < b->rows; i++) { /* loop over rows b */ d = d + a->data[ra * a->columns + i] * b->data[i * b->columns + cb]; } /* result [ra][cb] */ v->data[ra * b->columns + cb] = d; } } } else { lua_pushnil(L); } return 1; } static int vectorlib_mul(lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { vector b = vectorlib_aux_get(L, 2); if (b) { double d = lua_tonumber(L, 1); if (d == 1.0) { vectorlib_aux_copy(L, 2); } else { vector v = vectorlib_aux_push(L, b->rows, b->columns, b->stacking); for (int i = 0; i < b->rows * b->columns; i++) { v->data[i] = b->data[i] * d; } } } else { lua_pushnil(L); } } else if (lua_type(L, 2) == LUA_TNUMBER) { vector a = vectorlib_aux_get(L, 1); if (a) { double d = lua_tonumber(L, 2); if (d == 1.0) { vectorlib_aux_copy(L, 1); } else { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i] * d; } } } else { lua_pushnil(L); } } else { return vectorlib_product(L); } return 1; } static int vectorlib_div(lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { lua_pushnil(L); } else if (lua_type(L, 2) == LUA_TNUMBER) { vector a = vectorlib_aux_get(L, 1); if (a) { double d = lua_tonumber(L, 2); vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { /* Should we check for d == 0.0 or not here? */ v->data[i] = a->data[i] / d; } } else { lua_pushnil(L); } } else { lua_pushnil(L); } return 1; } static int vectorlib_neg(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = - a->data[i]; } } else { lua_pushnil(L); } return 1; } static int vectorlib_getrow(lua_State *L) { vector v = vectorlib_aux_get(L, 1); if (v) { int row = lmt_tointeger(L, 2) - 1; if (row >= 0 && row < v->rows) { long source = row * v->columns; if (lua_toboolean(L, 3)) { long target = 1; lua_createtable(L, v->columns, 0); for (int c = 0; c < v->columns; c++) { lua_pushnumber(L, v->data[source++]); lua_rawseti(L, -2, target++); } return 1; } else { for (int c = 0; c < v->columns; c++) { lua_pushnumber(L, v->data[source++]); } return v->columns; } } } else { lua_pushnil(L); } return 1; } static int vectorlib_getvalue(lua_State *L) { vector v = vectorlib_aux_get(L, 1); if (v) { long index = lmt_tolong(L, 2); lua_pushnumber(L, index > 0 && index <= v->rows * v->columns ? v->data[index-1] : 0); } else { lua_pushnil(L); } return 1; } static int vectorlib_setvalue(lua_State *L) { vector v = vectorlib_aux_get(L, 1); if (v) { long index = lmt_tolong(L, 2); if (index > 0 && index <= v->rows * v->columns) { v->data[index-1] = lua_type(L, 3) == LUA_TNUMBER ? lua_tonumber(L, 3) : 0; } } else { lua_pushnil(L); } return 1; } static int vectorlib_getlength(lua_State *L) { vector v = vectorlib_aux_get(L, 1); lua_pushinteger(L, v ? v->rows : 0); return 1; } static int vectorlib_setnext(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a && a->index < (a->rows * a->columns)) { int value = 1; for (int c = 0; c < a->columns; c++) { a->data[a->index++] = lua_type(L, ++value) == LUA_TNUMBER ? lua_tonumber(L, value) : 0; } } else { lua_pushnil(L); } return 1; } static int vectorlib_getvaluerc(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { int row = lmt_tointeger(L, 2) - 1; int column = lmt_tointeger(L, 3) - 1; if (row >= 0 && row < a->rows && column >= 0 && column < a->columns) { lua_pushnumber(L, a->data[row * a->columns + column]); return 1; } } lua_pushnil(L); return 1; } static int vectorlib_setvaluerc(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { int row = lmt_tointeger(L, 2) - 1; int column = lmt_tointeger(L, 3) - 1; if (row >= 0 && row < a->rows && column >= 0 && column < a->columns) { a->data[row * a->columns] = lua_type(L, 4) == LUA_TNUMBER ? lua_tonumber(L, 4) : 0.0; } } else { lua_pushnil(L); } return 1; } /* round floor ceil */ static int vectorlib_identity(lua_State *L) { int n = lmt_tointeger(L, 1); if (n > 0) { vector v = vectorlib_aux_push(L, n, n, 0); v->type = identity_type; for (int i = 0; i < v->rows * v->columns; i++) { v->data[i] = 0.0; } for (int i = 0; i < n; i++) { v->data[i * v->columns + i] = 1.0; } } else { lua_pushnil(L); } return 1; } static int vectorlib_transpose(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { if (a->type == identity_type) { vectorlib_aux_copy(L, 1); } else { // if one column or one row just swap vector v = vectorlib_aux_push(L, a->columns, a->rows, a->stacking); for (int r = 0; r < a->rows; r++) { for (int c = 0; c < a->columns; c++) { v->data[c * a->rows + r] = a->data[r * a->columns + c]; } } } } else { lua_pushnil(L); } return 1; } static int vectorlib_inner(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b && a->rows == b->rows) { double d = 0.0; for (int i = 0; i < a->rows; i++) { d = d + a->data[i] * b->data[i]; } lua_pushnumber(L, d); } else { lua_pushnil(L); } return 1; } static int vectorlib_round(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = round(a->data[i]); } } else { lua_pushnil(L); } return 1; } static int vectorlib_floor(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = floor(a->data[i]); } } else { lua_pushnil(L); } return 1; } static int vectorlib_ceiling(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = ceil(a->data[i]); } } else { lua_pushnil(L); } return 1; } static int vectorlib_truncate(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { if (lua_toboolean(L, 2)) { double epsilon = lmt_optdouble(L, 3, vector_epsilon); /* in place */ for (int i = 0; i < a->rows * a->columns; i++) { if (ISZERO(a->data[i])) { a->data[i] = 0.0; } } } else { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); double epsilon = lmt_optdouble(L, 3, vector_epsilon); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = ISZERO(a->data[i]) ? 0.0 : a->data[i]; } } } else { lua_pushnil(L); } return 1; } static int vectorlib_aux_uppertriangle(vector v, int sign, double epsilon) { for (int i = 0; i < v->rows - 1; i++) { double pivot = v->data[i * v->columns + i]; if (ISZERO(pivot)) { int p = i + 1; // while (! (v->data[p * v->columns + i])) { while (ISZERO(v->data[p * v->columns + i])) { p++; if (p > v->rows) { return sign; } } // for (int k = 0; k < v->columns; k++) { // double d1 = v->data[p * v->columns + k]; // double d2 = v->data[i * v->columns + k]; // v->data[p * v->columns + k] = d2; // v->data[i * v->columns + k] = d1; // } p = p * v->columns; i = i * v->columns; for (int k = 0; k < v->columns; k++) { double d1 = v->data[p]; double d2 = v->data[i]; v->data[p++] = d2; v->data[i++] = d1; } sign = -sign; } for (int k = i + 1; k < v->rows; k++) { double factor = - v->data[k * v->columns + i] / v->data[i * v->columns + i]; long target = k * v->columns; if (ISZERO(factor)) { for (int l = i; l < v->columns; l++) { v->data[target++] += 0.0; } } else { long source = i * v->columns; for (int l = i; l < v->columns; l++) { v->data[target++] += factor * v->data[source++]; } } } } return sign; } static int vectorlib_aux_determinant(lua_State *L, int singular, double *d, double epsilon) { vector a = vectorlib_aux_get(L, 1); (void) singular; if (a && a->rows == a->columns) { if (a->type == identity_type) { *d = 1.0; return 1; } else { switch (a->columns) { case 1: /* { { a } } : a */ { *d = a->data[0]; } break; case 2: /* { { a, b }, { c, d } } : ad - bc */ { *d = a->data[0] * a->data[3] - a->data[1] * a->data[2]; } break; case 3: /* {{ a, b, c }, { d, e, f }. { g, g, i } } : a(ei-fh) - b(di-gf) + c(dh-eg) */ /* see gems article about pos / neg separation, appendix v2.5 */ { *d = a->data[0] * (a->data[4] * a->data[8] - a->data[5] * a->data[7]) - a->data[1] * (a->data[3] * a->data[8] - a->data[6] * a->data[5]) + a->data[2] * (a->data[3] * a->data[7] - a->data[4] * a->data[6]); } break; default: vectorlib_aux_copy(L, 1); { vector a = vectorlib_aux_get(L, -1); double epsilon = lmt_optdouble(L, 2, vector_epsilon); int sign = vectorlib_aux_uppertriangle(a, 1, epsilon); *d = 1.0; for (int i = 0; i < a->rows; i++) { double dd = a->data[i * a->columns + i]; if (ISZERO(dd)) { /*tex This is also an attempt to avoid the -0.0 case. But even this doesn't catches all it seems. */ *d = 0.0; goto DONE; } else { *d = *d * a->data[i * a->columns + i]; } } *d = sign * *d; } break; } /*tex These -0.0 result in random tiny number, is this a compiler issue? The next test doesn't always catch is. We also have this issue in \METAPOST\ double mode. A |-d == 0.0| is more reliable than a |d == -0.0| test it seems. */ // if (-d == 0.0) { // d = 0.0; // } DONE: if (ISZERO(*d)) { *d = 0.0; } return 1; } } else { return 0; } } static int vectorlib_determinant(lua_State *L) { double determinant = 0.0; double epsilon = lmt_optdouble(L, 2, vector_epsilon); if (vectorlib_aux_determinant(L, 0, &determinant, epsilon)) { if (ISZERO(determinant)) { lua_pushinteger(L, 0); } else { lua_pushnumber(L, determinant); } } else { lua_pushnil(L); } return 1; } static int vectorlib_issingular(lua_State *L) { double d = 0.0; double epsilon = lmt_optdouble(L, 2, vector_epsilon); if (vectorlib_aux_determinant(L, 0, &d, epsilon)) { double e = lua_type(L, 2) == LUA_TNUMBER ? lua_tonumber(L, 2) : 0.001; lua_pushboolean(L, d <= e || d >= -e); } else { lua_pushnil(L); } return 1; } static int vectorlib_aux_rowechelon(vector v, int reduce, int augmented, double epsilon) { int pRow = 0; int pCol = 0; int nRow = v->rows; int nCol = v->columns; while (pRow < nRow) { double pivot = v->data[pRow * nCol + pCol]; if (ISZERO(pivot)) { int i = pRow; int n = nRow; while (ISZERO(v->data[i * nCol + pCol])) { i++; if (i > n) { pCol = pCol + 1; if (pCol >= nCol) { if (augmented) { /* we have a serious problem */ } return 1; } else { i = pRow; } } } for (int k = 0; k < v->columns; k++) { double d1 = v->data[pRow * v->columns + k]; double d2 = v->data[i * v->columns + k]; v->data[pRow * v->columns + k] = d2; v->data[i * v->columns + k] = d1; } } pivot = v->data[pRow * nCol + pCol]; for (int l = pCol; l < nCol; l++) { v->data[pRow * nCol + l] /= pivot; } if (reduce) { for (int k = 0; k < pRow; k++) { double factor = - v->data[k * nCol + pCol]; for (int l = pCol; l < nCol; l++) { v->data[k * nCol + l] += factor * v->data[pRow * nCol + l]; } } } for (int k = pRow + 1; k < nRow; k++) { double factor = - v->data[k * nCol + pCol]; for (int l = pCol; l < nCol; l++) { // + 1 v->data[k * nCol + l] += factor * v->data[pRow * nCol + l]; } } pRow = pRow + 1; pCol = pCol + 1; if (pRow > nRow || pCol > nCol) { pRow = nRow + 1; } } return 0; } static int vectorlib_inverse(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { switch (a->type) { case identity_type: vectorlib_aux_copy(L, 1); break; default: if (a->rows == a->columns) { double epsilon = lmt_optdouble(L, 2, vector_epsilon); switch (a->rows) { case 1: { vector w = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); if (ISZERO(a->data[0])) { goto BAD; } else { w->data[0] = 1.0 / a->data[0]; } } break; case 2: { double d = 0.0; if (vectorlib_aux_determinant(L, 0, &d, epsilon)) { if (ISZERO(d)) { goto BAD; } else { vector w = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); w->data[0] = a->data[3] / d; w->data[1] = - a->data[1] / d; w->data[2] = - a->data[2] / d; w->data[3] = a->data[0] / d; } } } break; case 3: { double d = 0.0; if (vectorlib_aux_determinant(L, 0, &d, epsilon)) { if (ISZERO(d)) { goto BAD; } else { vector w = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); w->data[0] = (a->data[4] * a->data[8] - a->data[5] * a->data[7]) / d; w->data[1] = (a->data[2] * a->data[7] - a->data[1] * a->data[8]) / d; w->data[2] = (a->data[1] * a->data[5] - a->data[2] * a->data[4]) / d; w->data[3] = (a->data[5] * a->data[6] - a->data[3] * a->data[8]) / d; w->data[4] = (a->data[0] * a->data[8] - a->data[2] * a->data[6]) / d; w->data[5] = (a->data[2] * a->data[3] - a->data[0] * a->data[5]) / d; w->data[6] = (a->data[3] * a->data[7] - a->data[4] * a->data[6]) / d; w->data[7] = (a->data[1] * a->data[6] - a->data[0] * a->data[7]) / d; w->data[8] = (a->data[0] * a->data[4] - a->data[1] * a->data[3]) / d; } } } break; default: { // vectorlib_copy(L); // vectorlib_identity(L); // vectorlib_concat(L); vector v = vectorlib_aux_push(L, a->rows, a->columns * 2, a->stacking); vector w = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int r = 0; r < a->rows; r++) { long target = r * v->columns; long source = r * a->columns; for (int c = 0; c < a->columns; c++) { v->data[target++] = a->data[source++]; } // v->data[r * v->columns + a->columns + r] = 1.0; v->data[target + r] = 1.0; } vectorlib_aux_rowechelon(v, 1, 1, epsilon); for (int r = 0; r < a->rows; r++) { if (ISZERO(v->data[r * v->columns + r])) { goto BAD; } } for (int r = 0; r < a->rows; r++) { long target = r * w->columns; long source = r * v->columns + a->columns; for (int c = 0; c < a->columns; c++) { w->data[target++] = v->data[source++]; } } } break; } } } return 1; } BAD: lua_pushnil(L); return 1; } static int vectorlib_rowechelon(lua_State *L) { vector a = vectorlib_aux_get(L, 1); int reduce = ! lua_toboolean(L, 2); if (a && a->rows == a->columns) { double epsilon = lmt_optdouble(L, 3, vector_epsilon); /* now, as we push */ vectorlib_aux_copy(L, 1); switch (a->type) { case identity_type: break; default: { a = vectorlib_aux_get(L, -1); vectorlib_aux_rowechelon(a, reduce, 0, epsilon); break; } } } else { lua_pushnil(L); } return 1; } static int vectorlib_crossproduct(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b) { if (a->columns == b->columns && a->rows == b->rows && (b->columns == 1 || b->rows == 1)) { switch (a->rows) { case 1: switch (a->columns) { case 1: lua_pushinteger(L, 0); return 1; case 2: lua_pushnumber(L, a->data[0] * b->data[1] - b->data[1] * a->data[0]); return 1; case 3: /*u \times v = (u2*v3 - u3*v2, u3*v1 - u1*v3, u1*v2 - u2*v1) */ { vector v = vectorlib_aux_push(L, 1, a->columns, a->stacking); v->data[0] = a->data[1] * b->data[2] - a->data[2] * b->data[1]; v->data[1] = a->data[2] * b->data[0] - a->data[0] * b->data[2]; v->data[2] = a->data[0] * b->data[1] - a->data[1] * b->data[0]; return 1; } default: break; /* maybe todo */ } break; case 2: /* u \times v = u1*v2 - u2*v1 */ lua_pushnumber(L, a->data[0] * b->data[1] - b->data[1] * a->data[0]); return 1; case 3: /*u \times v = (u2*v3 - u3*v2, u3*v1 - u1*v3, u1*v2 - u2*v1) */ { vector v = vectorlib_aux_push(L, a->rows, 1, a->stacking); v->data[0] = a->data[1] * b->data[2] - a->data[2] * b->data[1]; v->data[1] = a->data[2] * b->data[0] - a->data[0] * b->data[2]; v->data[2] = a->data[0] * b->data[1] - a->data[1] * b->data[0]; return 1; } default: break; /* maybe todo */ } } } lua_pushnil(L); return 1; } static int vectorlib_normalize(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { double d = 0.0; for (int i = 0; i < a->rows * a->columns; i++) { d += a->data[i] * a->data[i]; } if (d > 0.0) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); d = sqrt(d); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i] / d; } return 1; } } lua_pushnil(L); return 1; } static int vectorlib_homogenize(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a && a->columns > 1) { double epsilon = lmt_optdouble(L, 2, vector_epsilon); if (! vectorlib_aux_zero_in_column(a, a->columns - 1, epsilon)) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); for (int r = 0; r < a->rows; r++) { double d = a->data[r * a->columns + a->columns - 1]; long target = r * a->columns; long source = r * a->columns; for (int c = 0; c < a->columns - 1; c++) { v->data[target++] = a->data[source++] / d; } v->data[target] = 1.0; } return 1; } } lua_pushnil(L); return 1; } static int vectorlib_concat(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); int vertical = lua_toboolean(L, 3); if (a && b) { if (vertical) { if (b->columns == a->columns) { vector v = vectorlib_aux_push(L, a->rows + b->rows, a->columns, a->stacking); long index = a->rows * a->columns; vectorlib_aux_copy_data(v, a); for (int i = 0; i < b->rows * b->columns; i++) { v->data[index++] = b->data[i]; } return 1; } } else { if (b->rows == a->rows) { vector v = vectorlib_aux_push(L, a->rows, a->columns + b->columns, a->stacking); for (int r = 0; r < a->rows; r++) { long target = r * v->columns; long source = r * a->columns; for (int c = 0; c < a->columns; c++) { v->data[target++] = a->data[source++]; } } for (int r = 0; r < b->rows; r++) { long target = r * v->columns + a->columns; long source = r * b->columns; for (int c = 0; c < b->columns; c++) { v->data[target++ ] = b->data[source++]; } } return 1; } } } lua_pushnil(L); return 1; } static int vectorlib_slice(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { int fr = lmt_tointeger(L, 2); int fc = lmt_tointeger(L, 3); int nr = lmt_tointeger(L, 4); int nc = lmt_tointeger(L, 5); int tr = --fr + nr - 1; int tc = --fc + nc - 1; if ( (fr >= 0 && fr < a->rows) && (fc >= 0 && fc < a->columns) && (tr >= fr && tr < a->rows) && (tc >= fc && tc < a->columns)) { vector v = vectorlib_aux_push(L, nr, nc, a->stacking); long target = 0; for (int r = fr; r <= tr; r++) { long source = r * a->columns; for (int c = fc; c <= tc; c++) { v->data[target++] = a->data[source++]; } } return 1; } } lua_pushnil(L); return 1; } static int vectorlib_replace(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b) { int fr = lmt_tointeger(L, 3); int fc = lmt_tointeger(L, 4); int nr = b->rows; int nc = b->columns; int tr = --fr + nr - 1; int tc = --fc + nc - 1; if ( (fr >= 0 && fr < a->rows) && (fc >= 0 && fc < a->columns) && (tr >= fr && tr < a->rows) && (tc >= fc && tc < a->columns)) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); long source = 0; vectorlib_aux_copy_data(v, a); for (int r = fr; r <= tr; r++) { long target = r * v->columns + fc; for (int c = fc; c <= tc; c++) { v->data[target++] = b->data[source++]; } } return 1; } } lua_pushnil(L); return 1; } static int vectorlib_delete(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { int f = lmt_tointeger(L, 2); int n = lmt_tointeger(L, 3); int t = --f + n - 1; int vertical = lua_toboolean(L, 4); if (vertical) { if ((n <= a->rows) && (f >= 0 && f < a->rows) && (t >= f && t < a->rows)) { vector v = vectorlib_aux_push(L, a->rows - n, a->columns, a->stacking); long target = 0; for (int r = 0; r < a->rows; r++) { if (r < f || r > t) { long source = r * a->columns; for (int c = 0; c < a->columns; c++) { v->data[target++] = a->data[source++]; } } } return 1; } } else { if ((n <= a->columns) && (f >= 0 && f < a->columns) && (t >= f && t < a->columns)) { vector v = vectorlib_aux_push(L, a->rows, a->columns - n, a->stacking); long target = 0; for (int r = 0; r < a->rows; r++) { int base = r * a->columns; for (int c = 0; c < a->columns; c++) { if (c < f || c > t) { v->data[target++] = a->data[base + c]; } } } return 1; } } } lua_pushnil(L); return 1; } static int vectorlib_remove(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { int f = lmt_tointeger(L, 2); int n = lmt_tointeger(L, 3); int t = --f + n - 1; int vertical = lua_toboolean(L, 4); if (vertical) { if ((n <= a->rows) && (f >= 0 && f < a->rows) && (t >= f && t < a->rows)) { vector v = vectorlib_aux_push(L, a->rows - n, a->columns, a->stacking); vector w = vectorlib_aux_push(L, n, a->columns, a->stacking); long vtarget = 0; long wtarget = 0; for (int r = 0; r < a->rows; r++) { long source = r * a->columns; if (r < f || r > t) { for (int c = 0; c < a->columns; c++) { v->data[vtarget++] = a->data[source++]; } } else { for (int c = 0; c < a->columns; c++) { w->data[wtarget++] = a->data[source++]; } } } return 2; } } else { if ((n <= a->columns) && (f >= 0 && f < a->columns) && (t >= f && t < a->columns)) { vector v = vectorlib_aux_push(L, a->rows, a->columns - n, a->stacking); vector w = vectorlib_aux_push(L, a->rows, n, a->stacking); long vtarget = 0; long wtarget = 0; for (int r = 0; r < a->rows; r++) { long source = r * a->columns; for (int c = 0; c < a->columns; c++) { if (c < f || c > t) { v->data[vtarget++] = a->data[source++]; } else { w->data[wtarget++] = a->data[source++]; } } } return 2; } } } lua_pushnil(L); lua_pushnil(L); return 2; } static int vectorlib_insert(lua_State *L) { vector a = vectorlib_aux_get(L, 1); vector b = vectorlib_aux_get(L, 2); if (a && b) { int p = lmt_tointeger(L, 3); int vertical = lua_toboolean(L, 4); if (vertical) { if (a->columns == b->columns) { vector v = vectorlib_aux_push(L, a->rows + b->rows, a->columns, a->stacking); long target = 0; for (int r = 0; r < p; r++) { long source = r * a->columns; for (int c = 0; c < a->columns; c++) { v->data[target++] = a->data[source++]; } } for (int r = 0; r < b->rows; r++) { long source = r * b->columns; for (int c = 0; c < b->columns; c++) { v->data[target++] = b->data[source++]; } } for (int r = p; r < a->rows; r++) { long source = r * a->columns; for (int c = 0; c < a->columns; c++) { v->data[target++] = a->data[source++]; } } return 1; } } else { if (a->rows == b->rows) { vector v = vectorlib_aux_push(L, a->rows, a->columns + b->columns, a->stacking); long target = 0; for (int r = 0; r < a->rows; r++) { long source = r * a->columns; for (int c = 0; c < p; c++) { v->data[target++] = a->data[source++]; } source = r * b->columns; for (int c = 0; c < b->columns; c++) { v->data[target++] = b->data[source++]; } source = r * a->columns + p; for (int c = p; c < a->columns; c++) { v->data[target++] = a->data[source++]; } } return 1; } } } lua_pushnil(L); return 1; } static int vectorlib_append(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { double d = lua_tonumber(L, 2); int vertical = lua_toboolean(L, 3); if (vertical) { int row = a->rows + 1; vector v = vectorlib_aux_push(L, row, a->columns, a->stacking); vectorlib_aux_copy_data(v, a); for (int c = 0; c < a->columns; c++) { v->data[row + c] = d; } return 1; } else { vector v = vectorlib_aux_push(L, a->rows, a->columns + 1, a->stacking); long target = 0; long source = 0; for (int r = 0; r < a->rows; r++) { for (int c = 0; c < a->columns; c++) { v->data[target++] = a->data[source++]; } v->data[target++] = d; } return 1; } } lua_pushnil(L); return 1; } static int vectorlib_exchange(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { int p = lmt_tointeger(L, 2) - 1; int q = lmt_tointeger(L, 3) - 1; int vertical = lua_toboolean(L, 4); if (vertical) { if (p >= 0 && p < a->rows && q >= 0 && q < a->rows) { vector v = vectorlib_aux_push(L, a->rows , a->columns, a->stacking); vectorlib_aux_copy_data(v, a); p *= a->columns; q *= a->columns; for (int c = 0; c < a->columns; c++) { v->data[p] = a->data[q]; v->data[q] = a->data[p]; p++; q++; } return 1; } } else { if (p >= 0 && p < a->columns && q >= 0 && q < a->columns) { vector v = vectorlib_aux_push(L, a->rows , a->columns, a->stacking); vectorlib_aux_copy_data(v, a); for (int i = 0; i < a->rows * a->columns; i++) { v->data[i] = a->data[i]; } for (int r = 0; r < a->rows; r++) { v->data[p] = a->data[q]; v->data[q] = a->data[p]; p += a->columns; q += a->columns; } return 1; } } } lua_pushnil(L); return 1; } static int vectorlib_swap(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a && (a->columns == 1 || a->rows == 1)) { vector v = vectorlib_aux_push(L, a->rows, a->columns, a->stacking); v->rows = a->columns; v->columns = a->rows; vectorlib_aux_copy_data(v, a); } else { lua_pushnil(L); } return 1; } static int vectorlib_gettype(lua_State *L) { vector v = vectorlib_aux_get(L, 1); if (v) { lua_pushinteger(L, v->type); } else { lua_pushnil(L); } return 1; } static int vectorlib_getdimensions(lua_State *L) { vector v = vectorlib_aux_get(L, 1); if (v) { lua_pushinteger(L, v->rows); lua_pushinteger(L, v->columns); return 2; } else { return 0; } } static int vectorlib_setstacking(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { a->stacking = lmt_tointeger(L, 2); } return 0; } static int vectorlib_getstacking(lua_State *L) { vector a = vectorlib_aux_get(L, 1); if (a) { lua_pushinteger(L, a->stacking); } else { lua_pushnil(L); } return 1; } /* Meshes: These we use for some experiments with alternative approaches to contour graphics in the \LUAMETAFUN\ subsystem. They are for now not official. */ static inline unsigned short vectorlib_valid_point(lua_State *L, int index) { int p = lmt_tointeger(L, index); return p < 0 ? 0 : p > max_mesh ? max_mesh : p; } static mesh vectorlib_aux_maybe_ismesh(lua_State *L, int index) { mesh m = lua_touserdata(L, index); if (m && lua_getmetatable(L, index)) { lua_get_metatablelua(mesh_instance); if (! lua_rawequal(L, -1, -2)) { m = NULL; } lua_pop(L, 2); } return m; } static int vectorlib_ismesh(lua_State *L) { lua_pushboolean(L, vectorlib_aux_maybe_ismesh(L, 1) ? 1 : 0); return 1; } static int vectorlib_mesh_type(lua_State *L) { if (vectorlib_aux_maybe_ismesh(L, 1)) { lua_push_key(mesh); } else { lua_pushnil(L); } return 1; } static inline void vectorlib_mesh_wipe_entry(meshentry *entry) { for (int i = 0; i < 4; i++) { entry->points[i] = 0; } entry->average = 0.0; } static inline mesh vectorlib_mesh_aux_push(lua_State *L, int r) { mesh m = lua_newuserdatauv(L, 2 * sizeof(int) + r * sizeof(meshentry), 0); if (m && r > 0) { m->rows = r; m->type = triangle_mesh_type; lua_get_metatablelua(mesh_instance); lua_setmetatable(L, -2); } return m; } static int vectorlib_mesh_new(lua_State *L) { switch (lua_type(L, 1)) { case LUA_TNUMBER: { mesh m = vectorlib_mesh_aux_push(L, lmt_optinteger(L, 1, 1)); for (int i = 0; i < m->rows; i++) { vectorlib_mesh_wipe_entry(&(m->data[i])); } return 1; } case LUA_TTABLE: { int t = lua_rawgeti(L, 1, 1); lua_pop(L, 1); switch (t) { case LUA_TNUMBER: /* local v = vector.new( { 1,2,3 }, { 4,5,6 } ) */ /* n can determine quads */ { int rows = lua_gettop(L); if (rows) { mesh m = vectorlib_mesh_aux_push(L, rows); for (int i = 0; i < rows; i++) { meshentry *entry = &(m->data[i]); if (lua_type(L, i + 1) == LUA_TTABLE) { for (int j = 0; j < 4; j++) { entry->points[j] = lua_rawgeti(L, i + 1, j + 1) == LUA_TNUMBER ? vectorlib_valid_point(L, -1) : 0; lua_pop(L, 1); } entry->average = 0.0; } else { vectorlib_mesh_wipe_entry(entry); } } return 1; } else { break; } } case LUA_TTABLE: { /* local v = vector.new( { { 1,2,3 }, { 4,5,6 } } ) */ int rows = (int) lua_rawlen(L, 1); if (rows) { mesh m = vectorlib_mesh_aux_push(L, rows); for (int i = 0; i < rows; i++) { meshentry *entry = &(m->data[i]); if (lua_rawgeti(L, 1, i + 1) == LUA_TTABLE) { for (int j = 0; j < 4; j++) { entry->points[j] = lua_rawgeti(L, -1, j + 1) == LUA_TNUMBER ? vectorlib_valid_point(L, -1) : 0; lua_pop(L, 1); } entry->average = 0.0; } else { vectorlib_mesh_wipe_entry(entry); } lua_pop(L, 1); } return 1; } else { break; } } default: break; } break; } } lua_pushnil(L); return 0; } inline static mesh vectorlib_mesh_aux_get(lua_State *L, int index) { mesh m = lua_touserdata(L, index); if (m && lua_getmetatable(L, index)) { lua_get_metatablelua(mesh_instance); if (! lua_rawequal(L, -1, -2)) { m = NULL; } lua_pop(L, 2); } return m; } mesh vectorlib_get_mesh(lua_State *L, int index) { if (lua_type(L, index) == LUA_TUSERDATA) { return (mesh) luaL_checkudata(L, index, MESH_METATABLE); } else { return NULL; } } static int vectorlib_mesh_tostring(lua_State *L) { mesh v = vectorlib_mesh_aux_get(L, 1); if (v) { lua_pushfstring(L, "", v->rows, mesh_names[valid_mesh(v->type)], v); return 1; } else { return 0; } } static int vectorlib_mesh_totable(lua_State *L) { mesh m = vectorlib_aux_maybe_ismesh(L, 1); if (m) { long target = 1; int size = m->type == quad_mesh_type ? 4 : 3; if (lua_toboolean(L, 2)) { lua_createtable(L, m->rows * (size + 1), 0); for (int r = 0; r < m->rows; r++) { meshentry *triangle = &(m->data[r]); for (int i = 0; i < size; i++) { lua_pushinteger(L, triangle->points[i]); lua_rawseti(L, -2, target++); } lua_pushnumber(L, triangle->average); lua_rawseti(L, -2, target++); } } else { lua_createtable(L, m->rows, 0); for (int r = 0; r < m->rows; r++) { meshentry *triangle = &(m->data[r]); long index = 1; lua_createtable(L, size + 1, 0); for (int i = 0; i < size; i++) { lua_pushinteger(L, triangle->points[i]); lua_rawseti(L, -2, index++); } lua_pushnumber(L, triangle->average); lua_rawseti(L, -2, index); lua_rawseti(L, -2, target++); } } return 1; } else { return 0; } } static int vectorlib_mesh_index(lua_State *L) { mesh m = vectorlib_mesh_aux_get(L, 1); if (m) { int index = lmt_tointeger(L, 2); if (index > 0 && index <= m->rows) { lua_pushnumber(L, m->data[index - 1].average); return 1; } } return 0; } static int vectorlib_mesh_getvalue(lua_State *L) { mesh m = vectorlib_mesh_aux_get(L, 1); if (m) { int index = lmt_tointeger(L, 2); if (index > 0 && index <= m->rows) { meshentry *triangle = &(m->data[index-1]); int size = m->type == quad_mesh_type ? 4 : 3; if (lua_toboolean(L, 3)) { long target = 1; lua_createtable(L, size + 1, 0); for (int i = 0; i < size; i++) { lua_pushinteger(L, triangle->points[i]); lua_rawseti(L, -2, target++); } lua_pushnumber(L, triangle->average); lua_rawseti(L, -2, target); return 1; } else { for (int i = 0; i < size; i++) { lua_pushinteger(L, triangle->points[i]); } lua_pushnumber(L, triangle->average); return size + 1; } } } return 0; } static int vectorlib_mesh_setvalue(lua_State *L) { mesh m = vectorlib_mesh_aux_get(L, 1); if (m) { int index = lmt_tointeger(L, 2); if (index > 0 && index <= m->rows) { meshentry *triangle = &(m->data[index-1]); switch (lua_type(L, 3)) { case LUA_TNUMBER: { triangle->average = lua_tonumber(L, 3); break; } case LUA_TTABLE: { int size = m->type == quad_mesh_type ? 4 : 3; for (int i = 1; i <= size; i++) { if (lua_rawgeti(L, 3, i) == LUA_TNUMBER) { if (i < size) { triangle->points[i-1] = vectorlib_valid_point(L, -1); } else { triangle->average = lua_tonumber(L, -1); } } lua_pop(L, 1); } break; } } } } return 0; } static int vectorlib_mesh_getlength(lua_State *L) { mesh m = vectorlib_mesh_aux_get(L, 1); lua_pushinteger(L, m ? m->rows : 0); return 1; } static int vectorlib_mesh_getdimensions(lua_State *L) { mesh m = vectorlib_mesh_aux_get(L, 1); if (m) { lua_pushinteger(L, m->rows); } else { lua_pushnil(L); } return 1; } /* Contours: These we use for some experiments with alternative approaches to contour graphics in the \LUAMETAFUN\ subsystem. They are for now not official. */ static int vectorlib_contour_aux_okay(int condition, const char *where, const char *message) { if (! condition) { tex_formatted_error("vector lib", "error in vector.%s: %s\n", where, message); } return condition; } static int vectorlib_contour_aux_is_valid(lua_State *L, vector *v, mesh *l, const char *what) { *v = vectorlib_get(L, 1); if (vectorlib_contour_aux_okay(*v && (*v)->rows > 1 && (*v)->columns > 2, what, "point list expected (x,y,z,...)")) { *l = vectorlib_get_mesh(L, 2); if (vectorlib_contour_aux_okay(*l && valid_mesh((*l)->type), what, "mesh list expected ((p1 .. pN),average)")) { return 1; } } return 0; } static int vectorlib_contour_getmesh(lua_State *L) { vector v = NULL; mesh l = NULL; if (vectorlib_contour_aux_is_valid(L, &v, &l, "getmesh")) { int i = lmt_tointeger(L, 3) - 1; /* triangle index */ if (i >= 0 && i < l->rows) { int done = 0; int okay = 0; int size = valid_mesh(l->type); meshentry *triangle = &(l->data[i]); for (int j = 0; j < size; j++) { int r = triangle->points[j] - 1; if (r >= 0 && r < v->rows) { int k = r * v->columns; if (! okay) { lua_createtable(L, 2 * size, 0); okay = 1; } lua_pushnumber(L, v->data[k++]); lua_rawseti(L, -2, ++done); lua_pushnumber(L, v->data[k]); lua_rawseti(L, -2, ++done); } else { break; /* error */ } } if (okay) { lua_pushnumber(L, triangle->average); return 2; } else { /*tex We signal that we have a zero entry. */ lua_pushboolean(L, 0); return 1; } } } return 0; } static int vectorlib_contour_getarea(lua_State *L) { vector v = NULL; mesh l = NULL; if (vectorlib_contour_aux_is_valid(L, &v, &l, "getarea")) { int i = lmt_tointeger(L, 3) - 1; /* triangle index */ if (i >= 0 && i < l->rows) { meshentry *entry = &(l->data[i]); switch (l->type) { case line_mesh_type: lua_pushnumber(L, 0.0); return 1; case quad_mesh_type: { int p1 = entry->points[0] - 1; int p3 = entry->points[2] - 1; if (p1 >= 0 && p1 < v->rows && p3 >= 0 && p3 < v->rows) { double x1 = v->data[p1 * v->columns]; double y1 = v->data[p1 * v->columns + 1]; double x3 = v->data[p3 * v->columns]; double y3 = v->data[p3 * v->columns + 1]; lua_pushnumber(L, fabs(x3 - x1) * fabs(y3 - y1)); return 1; } else { break; } } case triangle_mesh_type: /* from wikipedia */ { int p1 = entry->points[0] - 1; int p2 = entry->points[1] - 1; int p3 = entry->points[2] - 1; if (p1 >= 0 && p1 < v->rows && p2 >= 0 && p2 < v->rows && p3 >= 0 && p3 < v->rows) { double x1 = v->data[p1 * v->columns]; double y1 = v->data[p1 * v->columns + 1]; double x2 = v->data[p2 * v->columns]; double y2 = v->data[p2 * v->columns + 1]; double x3 = v->data[p3 * v->columns]; double y3 = v->data[p3 * v->columns + 1]; double ab = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)); double bc = sqrt(pow(x2 - x3, 2) + pow(y2 - y3, 2)); double ca = sqrt(pow(x3 - x1, 2) + pow(y3 - y1, 2)); lua_pushnumber(L, sqrt ( ( ab + bc + ca) * (- ab + bc + ca) * ( ab - bc + ca) * ( ab + bc - ca) ) / 4); return 1; } else { break; } } } } } return 0; } /* see below, todo: optimize */ static int vectorlib_contour_aux_checkoverlap(vector v, mesh l, int U, int V, int method, double epsilon) { int u0 = l->data[U].points[0] - 1; int u1 = l->data[U].points[1] - 1; int u2 = l->data[U].points[2] - 1; int v0 = l->data[V].points[0] - 1; int v1 = l->data[V].points[1] - 1; int v2 = l->data[V].points[2] - 1; if ( u0 >= 0 && u1 >= 0 && u2 >= 0 && v0 >= 0 && v1 >= 0 && v2 >= 0 && u0 < v->rows && u1 < v->rows && u2 < v->rows && v0 < v->rows && v1 < v->rows && v2 < v->rows ) { if ( u0 == v0 || u1 == v0 || u2 == v0 || u0 == v1 || u1 == v1 || u2 == v1 || u0 == v2 || u1 == v2 || u2 == v2 ) { return triangles_intersection_nop_same_points; } else { double *U0 = &(v->data[u0 * v->columns]); double *U1 = &(v->data[u1 * v->columns]); double *U2 = &(v->data[u2 * v->columns]); double *V0 = &(v->data[v0 * v->columns]); double *V1 = &(v->data[v1 * v->columns]); double *V2 = &(v->data[v2 * v->columns]); if ( /* we can't memcmp due to small differences (epsilon) */ (ISZERO(U0[0] - V0[0]) && ISZERO(U0[1] - V0[1]) && ISZERO(U0[2] - V0[2])) || (ISZERO(U1[0] - V0[0]) && ISZERO(U1[1] - V0[1]) && ISZERO(U1[2] - V0[2])) || (ISZERO(U2[0] - V0[0]) && ISZERO(U2[1] - V0[1]) && ISZERO(U2[2] - V0[2])) || (ISZERO(U0[0] - V1[0]) && ISZERO(U0[1] - V1[1]) && ISZERO(U0[2] - V1[2])) || (ISZERO(U1[0] - V1[0]) && ISZERO(U1[1] - V1[1]) && ISZERO(U1[2] - V1[2])) || (ISZERO(U2[0] - V1[0]) && ISZERO(U2[1] - V1[1]) && ISZERO(U2[2] - V1[2])) || (ISZERO(U0[0] - V2[0]) && ISZERO(U0[1] - V2[1]) && ISZERO(U0[2] - V2[2])) || (ISZERO(U1[0] - V2[0]) && ISZERO(U1[1] - V2[1]) && ISZERO(U1[2] - V2[2])) || (ISZERO(U2[0] - V2[0]) && ISZERO(U2[1] - V2[1]) && ISZERO(U2[2] - V2[2])) ) { return triangles_intersection_nop_same_values; } else if (method == 2) { return triangles_intersect_gd(U0, U1, U2, V0, V1, V2, epsilon); } else { return triangles_intersect(U0, U1, U2, V0, V1, V2, epsilon); } } } return -1; } static int vectorlib_contour_checkoverlap(lua_State *L) { vector v = NULL; mesh l = NULL; if (vectorlib_contour_aux_is_valid(L, &v, &l, "checkoverlap")) { if (l->type == triangle_mesh_type) { int U = lmt_tointeger(L, 3) - 1; int V = lmt_tointeger(L, 4) - 1; if (U >= 0 && U < l->rows && V >= 0 && V < l->rows) { int method = lmt_optinteger(L, 5, 1); double epsilon = lmt_optdouble(L, 6, vector_epsilon); int overlapping = vectorlib_contour_aux_checkoverlap(v, l, U, V, method, epsilon); if (overlapping >= 0) { lua_pushinteger(L, overlapping); return 1; } } } else { /* we only check triangles */ } } return 0; } static int vectorlib_contour_collectoverlap(lua_State *L) { vector v = NULL; mesh l = NULL; if (vectorlib_contour_aux_is_valid(L, &v, &l, "collectoverlap")) { if (l->type == triangle_mesh_type) { int details = lua_toboolean(L, 3); int method = lmt_optinteger(L, 4, 1); double epsilon = lmt_optdouble(L, 5, vector_epsilon); int vr = v->rows; int vc = v->columns; int lr = l->rows; int m = 0; for (int i = 0; i < lr; i++) { meshentry *triangle = &(l->data[i]); int u0 = triangle->points[0]; int u1 = triangle->points[1]; int u2 = triangle->points[2]; if ( u0 >= 1 && u1 >= 1 && u2 >= 1 && u0 <= vr && u1 <= vr && u2 <= vr ) { } else { vectorlib_contour_aux_okay(0, "collectoverlap", "triangle list entries has invalid point references"); return 0; } } for (int i = 0; i < lr - 1; i++) { meshentry *triangle = &(l->data[i]); int u0 = triangle->points[0] - 1; int u1 = triangle->points[1] - 1; int u2 = triangle->points[2] - 1; double *U0 = &(v->data[u0 * vc]); double *U1 = &(v->data[u1 * vc]); double *U2 = &(v->data[u2 * vc]); for (int j = i + 1; j < lr; j++) { meshentry *triangle = &(l->data[j]); int v0 = triangle->points[0] - 1; if ( u0 == v0 || u1 == v0 || u2 == v0 ) { continue; /* triangles_intersection_nop_same_points */ } int v1 = triangle->points[1] - 1; if ( u0 == v1 || u1 == v1 || u2 == v1 ) { continue; /* triangles_intersection_nop_same_points */ } int v2 = triangle->points[2] - 1; if ( u0 == v2 || u1 == v2 || u2 == v2 ) { continue; /* triangles_intersection_nop_same_points */ } double *V0 = &(v->data[v0 * vc]); if ( (ISZERO(U0[0] - V0[0]) && ISZERO(U0[1] - V0[1]) && ISZERO(U0[2] - V0[2])) || (ISZERO(U1[0] - V0[0]) && ISZERO(U1[1] - V0[1]) && ISZERO(U1[2] - V0[2])) || (ISZERO(U2[0] - V0[0]) && ISZERO(U2[1] - V0[1]) && ISZERO(U2[2] - V0[2])) ) { continue; /* triangles_intersection_nop_same_values */ } double *V1 = &(v->data[v1 * vc]); if ( (ISZERO(U0[0] - V1[0]) && ISZERO(U0[1] - V1[1]) && ISZERO(U0[2] - V1[2])) || (ISZERO(U1[0] - V1[0]) && ISZERO(U1[1] - V1[1]) && ISZERO(U1[2] - V1[2])) || (ISZERO(U2[0] - V1[0]) && ISZERO(U2[1] - V1[1]) && ISZERO(U2[2] - V1[2])) ) { continue; /* triangles_intersection_nop_same_values */ } double *V2 = &(v->data[v2 * vc]); if ( (ISZERO(U0[0] - V2[0]) && ISZERO(U0[1] - V2[1]) && ISZERO(U0[2] - V2[2])) || (ISZERO(U1[0] - V2[0]) && ISZERO(U1[1] - V2[1]) && ISZERO(U1[2] - V2[2])) || (ISZERO(U2[0] - V2[0]) && ISZERO(U2[1] - V2[1]) && ISZERO(U2[2] - V2[2])) ) { continue; /* triangles_intersection_nop_same_values */ } if (details) { triangles_three Utimes, Vtimes; int state = method == 2 ? triangles_intersect_with_line_gd(U0, U1, U2, V0, V1, V2, Utimes, Vtimes, epsilon) : triangles_intersect_with_line (U0, U1, U2, V0, V1, V2, Utimes, Vtimes, epsilon); if (state > triangles_intersection_yes_bound) { long index = 1; if (! m) { lua_createtable(L, 8, 0); /* main table, how many makes sense */ } lua_createtable(L, 8, 0); // lua_createtable(L, 9, 0); lua_pushinteger(L, i + 1); lua_rawseti(L, -2, index++); lua_pushinteger(L, j + 1); lua_rawseti(L, -2, index++); for (int k = 0; k < 3; k++) { lua_pushnumber(L, Utimes[k]); lua_rawseti(L, -2, index++); } for (int k = 0; k < 3; k++) { lua_pushnumber(L, Vtimes[k]); lua_rawseti(L, -2, index++); } // lua_pushinteger(L, state); // lua_rawseti(L, -2, index++); lua_rawseti(L, -2, ++m); } } else { int state = method == 2 ? triangles_intersect_gd(U0, U1, U2, V0, V1, V2, epsilon) : triangles_intersect (U0, U1, U2, V0, V1, V2, epsilon); if (state > triangles_intersection_yes_bound) { if (! m) { lua_createtable(L, 8, 0); } lua_createtable(L, 2, 0); lua_pushinteger(L, i + 1); lua_rawseti(L, -2, 1); lua_pushinteger(L, j + 1); lua_rawseti(L, -2, 2); lua_rawseti(L, -2, ++m); /* maybe also store state */ } } } } return m ? 1 : 0; } else { /* we only check triangles */ } } return 0; } static int vectorlib_contour_average(lua_State *L) { vector v = NULL; mesh l = NULL; if (vectorlib_contour_aux_is_valid(L, &v, &l, "average")) { double minx = 0.0; double maxx = 0.0; double miny = 0.0; double maxy = 0.0; double minz = 0.0; double maxz = 0.0; int okay = 0; int done = 0; int size = valid_mesh(l->type); int tolerant = lua_toboolean(L, 3); int method = lmt_optinteger(L, 4, 1); // int first = lmt_optinteger(L, 5, 1); // int last = lmt_optinteger(L, 6, l->rows); // if (first <= 0) { // first = 0; // } else { // --first; // } // if (last == 0) { // last = l->rows; // } else if (last > l->rows) { // last = l->rows; // } else { // --last; // } // for (int i = first; i < last; i++) { for (int i = 0; i < l->rows; i++) { meshentry *entry = &(l->data[i]); double average = 0.0; double amin = 0; int a = 0; for (int j = 0; j < size; j++) { int r = entry->points[j]; if (r > 0 && r <= v->rows) { int k = (r - 1) * v->columns; double x = v->data[k++]; double y = v->data[k++]; double z = v->data[k]; if (! a || z < amin) { amin = z; } average += z; if (done) { if (x < minx) { minx = x; } else if (x > maxx) { maxx = x; } if (y < miny) { miny = y; } else if (y > maxy) { maxy = y; } } else { minx = x; miny = y; maxx = x; maxy = y; done = 1; } a++; } else if (! tolerant) { tex_formatted_error("vector lib", "error in vector.average, invalid point index"); a = 0; break; } } if (method == 2) { average = amin; } else { average = a > 0 ? (average / a) : 0.0; if (method == 3) { average += amin; } } entry->average = average; if (okay) { if (average < minz) { minz = average; } if (average > maxz) { maxz = average; } } else { minz = average; maxz = average; } okay++; } lua_createtable(L, 0, 7); lua_set_integer_by_key(L, "okay", okay); lua_set_number_by_key (L, "minx", minx); lua_set_number_by_key (L, "miny", miny); lua_set_number_by_key (L, "maxx", maxx); lua_set_number_by_key (L, "maxy", maxy); lua_set_number_by_key (L, "minz", minz); lua_set_number_by_key (L, "maxz", maxz); return 1; } else { return 0; } } static int vectorlib_contour_bounds(lua_State *L) { vector v = NULL; mesh l = NULL; if (vectorlib_contour_aux_is_valid(L, &v, &l, "bounds")) { double minx = 0.0; double maxx = 0.0; double miny = 0.0; double maxy = 0.0; int okay = 0; int size = valid_mesh(l->type); int first = lmt_optinteger(L, 3, 1); int last = lmt_optinteger(L, 4, l->rows); if (first <= 0) { first = 0; } else { --first; } if (last == 0) { last = l->rows; } else if (last > l->rows) { last = l->rows; } else { --last; } for (int i = first; i < last; i++) { meshentry *entry = &(l->data[i]); for (int j = 0; j < size; j++) { int r = entry->points[j]; if (r > 0 && r <= v->rows) { int k = (r - 1) * v->columns; double x = v->data[k++]; double y = v->data[k]; if (okay) { if (x < minx) { minx = x; } else if (x > maxx) { maxx = x; } if (y < miny) { miny = y; } else if (y > maxy) { maxy = y; } } else { minx = x; miny = y; maxx = x; maxy = y; } okay++; } } } lua_createtable(L, 0, 5); lua_set_integer_by_key(L, "okay", okay); lua_set_number_by_key (L, "minx", minx); lua_set_number_by_key (L, "miny", miny); lua_set_number_by_key (L, "maxx", maxx); lua_set_number_by_key (L, "maxy", maxy); return 1; } return 0; } int vectorlib_contour_compare_mesh_average(const void *entry_1, const void *entry_2) { const meshentry *value_1 = (const meshentry *) entry_1; const meshentry *value_2 = (const meshentry *) entry_2; if (value_1->average > value_2->average) { return 1; } else if (value_1->average < value_2->average) { return -1; } else { return 0; } } static int vectorlib_contour_sort(lua_State *L) { mesh m = vectorlib_get_mesh(L, 1); if (m && m->rows > 1) { qsort(m->data, m->rows, sizeof(meshentry), vectorlib_contour_compare_mesh_average); } return 0; } /* we can combine these two */ static int vectorlib_contour_makemesh(lua_State *L) { int columns = lmt_tointeger(L, 1); int rows = lmt_tointeger(L, 2); int size = columns * rows; int type = valid_mesh(lmt_optinteger(L, 3, triangle_mesh_type)); if (size > 0 && size <= max_mesh) { switch (type) { case triangle_mesh_type: size *= 2; break; case quad_mesh_type: break; case line_mesh_type: break; default: /*tex We silently recover. */ type = triangle_mesh_type; size *= 2; break; } /*tex When we arrived here we're okay. */ { mesh m = vectorlib_mesh_aux_push(L, size); int index = 0; int offset = columns + 1; m->type = type; for (int r = 1; r <= rows; r++) { for (int c = 1; c <= columns; c++) { int p1 = (r - 1) * offset + c; // left point of current row int p2 = r * offset + c; // left point of next row int p11 = p1 + 1; int p21 = p2 + 1; if (p11 > max_mesh || p21 > max_mesh) { /* we clip */ } else { switch (type) { case triangle_mesh_type: /* first */ m->data[index ].points[0] = (unsigned short) p1; m->data[index ].points[1] = (unsigned short) p11; m->data[index ].points[2] = (unsigned short) p21; m->data[index ].points[3] = 0; m->data[index++].average = 0.0; /* second */ m->data[index ].points[0] = (unsigned short) p1; m->data[index ].points[1] = (unsigned short) p21; m->data[index ].points[2] = (unsigned short) p2; m->data[index ].points[3] = 0; m->data[index++].average = 0.0; break; case quad_mesh_type: m->data[index ].points[0] = (unsigned short) p1; m->data[index ].points[1] = (unsigned short) p11; m->data[index ].points[2] = (unsigned short) p21; m->data[index ].points[3] = (unsigned short) p2; m->data[index++].average = 0.0; break; case line_mesh_type: m->data[index ].points[0] = (unsigned short) p1; m->data[index ].points[1] = (unsigned short) p2; m->data[index ].points[2] = 0; m->data[index ].points[3] = 0; m->data[index++].average = 0.0; break; } } } } } } else { /* message */ lua_pushnil(L); } return 1; } /* */ static const luaL_Reg vectorlib_vector_function_list[] = { /* management */ { "new", vectorlib_new }, { "isvector", vectorlib_isvector }, { "ismesh", vectorlib_ismesh }, { "onerow", vectorlib_onerow }, { "onecolumn", vectorlib_onecolumn }, { "copy", vectorlib_copy }, { "type", vectorlib_type }, { "tostring", vectorlib_tostring }, { "totable", vectorlib_totable }, { "get", vectorlib_getvalue }, { "set", vectorlib_setvalue }, { "getrow", vectorlib_getrow }, /* table */ { "getrc", vectorlib_getvaluerc }, { "setrc", vectorlib_setvaluerc }, { "setnext", vectorlib_setnext }, /* info */ { "gettype", vectorlib_gettype }, { "setstacking", vectorlib_setstacking }, { "getstacking", vectorlib_getstacking }, { "getdimensions", vectorlib_getdimensions }, { "setepsilon", vectorlib_setepsilon }, { "getepsilon", vectorlib_getepsilon }, { "iszero", vectorlib_iszero }, /* { "isidentity", vectorlib_isidentity }, */ /* todo */ /* operators */ { "add", vectorlib_add }, { "div", vectorlib_div }, { "mul", vectorlib_mul }, { "sub", vectorlib_sub }, { "negate", vectorlib_neg }, { "equal", vectorlib_eq }, /* functions */ { "round", vectorlib_round }, { "floor", vectorlib_floor }, { "ceiling", vectorlib_ceiling }, { "truncate", vectorlib_truncate }, { "inverse", vectorlib_inverse }, { "rowechelon", vectorlib_rowechelon }, { "identity", vectorlib_identity }, { "transpose", vectorlib_transpose }, { "normalize", vectorlib_normalize }, { "homogenize", vectorlib_homogenize }, { "determinant", vectorlib_determinant }, { "issingular", vectorlib_issingular }, { "inner", vectorlib_inner }, /* maybe: innerproduct */ { "product", vectorlib_product }, { "crossproduct", vectorlib_crossproduct }, /* manipulations */ { "concat", vectorlib_concat }, { "slice", vectorlib_slice }, { "delete", vectorlib_delete }, { "remove", vectorlib_remove }, { "insert", vectorlib_insert }, { "replace", vectorlib_replace }, { "swap", vectorlib_swap }, { "exchange", vectorlib_exchange }, { "append", vectorlib_append }, /* nothing more */ { NULL, NULL }, }; static const luaL_Reg vectorlib_mesh_function_list[] = { { "new", vectorlib_mesh_new }, { "ismesh", vectorlib_ismesh }, { "type", vectorlib_mesh_type }, { "tostring", vectorlib_mesh_tostring }, { "totable", vectorlib_mesh_totable }, { "getdimensions", vectorlib_mesh_getdimensions }, { "get", vectorlib_mesh_getvalue }, /* table when third is true */ { "set", vectorlib_mesh_setvalue }, /* nothing more */ { NULL, NULL }, }; static const luaL_Reg vectorlib_contour_function_list[] = { /* for experiments with mp */ { "average", vectorlib_contour_average }, { "bounds", vectorlib_contour_bounds }, { "makemesh", vectorlib_contour_makemesh }, { "sort", vectorlib_contour_sort }, { "getmesh", vectorlib_contour_getmesh }, { "getarea", vectorlib_contour_getarea }, { "checkoverlap", vectorlib_contour_checkoverlap }, { "collectoverlap", vectorlib_contour_collectoverlap }, /* nothing more */ { NULL, NULL }, }; static const luaL_Reg vectorlib_vector_metatable[] = { { "__len", vectorlib_getlength }, { "__index", vectorlib_getvalue }, { "__newindex", vectorlib_setvalue }, { "__tostring", vectorlib_tostring }, { "__add", vectorlib_add }, { "__div", vectorlib_div }, { "__mul", vectorlib_mul }, { "__sub", vectorlib_sub }, { "__unm", vectorlib_neg }, { "__eq", vectorlib_eq }, { "__concat", vectorlib_concat }, { "__call", vectorlib_setnext }, { NULL, NULL }, }; static const luaL_Reg vectorlib_mesh_metatable[] = { { "__len", vectorlib_mesh_getlength }, { "__index", vectorlib_mesh_index }, { "__newindex", vectorlib_mesh_setvalue }, { "__tostring", vectorlib_mesh_tostring }, { NULL, NULL }, }; int luaopen_vector(lua_State *L) { luaL_newmetatable(L, VECTOR_METATABLE_INSTANCE); luaL_setfuncs(L, vectorlib_vector_metatable, 0); luaL_newmetatable(L, MESH_METATABLE_INSTANCE); luaL_setfuncs(L, vectorlib_mesh_metatable, 0); /* vector.* */ lua_newtable(L); luaL_setfuncs(L, vectorlib_vector_function_list, 0); /* vector.mesh */ // lua_pushliteral(L, "mesh"); lua_pushstring(L, lua_key(mesh)); lua_newtable(L); luaL_setfuncs(L, vectorlib_mesh_function_list, 0); lua_rawset(L, -3); /* vector.contour */ // lua_pushstring(L, lua_key(contour)); lua_pushliteral(L, "contour"); lua_newtable(L); luaL_setfuncs(L, vectorlib_contour_function_list, 0); lua_rawset(L, -3); return 1; } luametatex-2.11.08/source/luarest/lmteffectslib.c0000644000175000017500000016537315063273560021004 0ustar hillehille/* See license.txt in the root of this project. */ /*tex Here we collect some graphical effects we like to play with and that can make documents more attractive. We start with perlin like noise as explored by Keith McKay who discussed it in articles and presentations. These are part of the (*luameta)fun explorations. */ # include # include /*tex Perlin noise: https://mrl.cs.nyu.edu/~perlin/noise/ Also discussed in: https://github.com/stegu/noiseisbeautiful/tree/main?tab=readme-ov-file https://adrianb.io/2014/08/09/perlinnoise.html Simplex noise: https://github.com/stegu/perlin-noise.git The simplex code is derived from code by Stefan Gustavson, 2003-2005 and is released in the public domain (GPL until 2011). Comment by Stefan: This implementation is "Simplex Noise" as presented by Ken Perlin at a relatively obscure and not often cited course session "Real-Time Shading" at Siggraph 2001 (before real time shading actually took off), under the title "hardware noise". The 3D function is numerically equivalent to his Java reference code available in the PDF course notes, although I re-implemented it from scratch to get more readable code. The 1D, 2D and 4D cases were implemented from scratch by me from Ken Perlin's text. Searching the web will bring you to more documents and articles by Stefan, including mesmerizing examples. Note: We kept our version of the perlin noise but might try the other variant that has no recursion. We also use the permutation table that we already entered and share that between the functions. Interfacing: More details can be found in the \LUAMETAFUN\ manual, articles and examples. We hook the noice generators into \METAPOST\ via \LUA. I wanted to get the terminology right so searched a bit and saw these comments in as answer on https://gamedev.stackexchange.com/ (message 197861): Persistence (also called gain) is a value in the range (0, 1) that controls how quickly the later octaves "die out". Something around 0.5 is pretty conventional here. Lacunarity is a value greater than 1 that controls how much finer a scale each subsequent octave should use. Something around 2.0 is a conventional choice. So we replaces "scale" in our code by "lacunarity" because it sounds better and is less confusing. There are a few more optimizations (for instance precalculated sin and cos) and we might at some point pass a struct instead of individual parameters / variables. Authors: Keith McKay Mikael Sundqvist Hans Hagen */ /* We use an byte table so that the binary doesn't grow by more Kbytes than needed. After all, keeping the binary small is a LuaMetaTeX objective. I don't expect a difference in performance on modern architectures and compilers. */ static const unsigned char p[512] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, /*tex We just copy so we don't need to initialize with a loop then. */ 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, }; /*tex Originally we had perlin noise codes in \LUA\ and the next is more of less the same as we had there. */ static inline double fade(double t) { return t * t * t * (t * (t * 6 - 15) + 10); } static inline double lerp(double t, double a, double b) { return a + t * (b - a); } /* Convert the lower 4 bits of hash code into 12 gradient directions: */ static double grad(int hash, double x, double y, double z) /* we can avoid one h check */ { int h = hash & 15; double u = h < 8 ? x : y; double v = h < 4 ? y : h == 12 || h == 14 ? x : z; return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); } static double effectslib_perlin_noise_3(double x, double y, double z) { /* Find unit cube that contains point: */ int X = lfloor(x) & 0xFF; int Y = lfloor(y) & 0xFF; int Z = lfloor(z) & 0xFF; /* Find relative x,y,z of point in cube: */ x -= floor(x); y -= floor(y); z -= floor(z); /* Compute fade curves for each of x, y, z: */ double u = fade(x); double v = fade(y); double w = fade(z); /* Hash coordinates of the 8 cube corners: */ int A = p[X ] + Y; int AA = p[A] + Z; int AB = p[A+1] + Z; int B = p[X+1] + Y; int BA = p[B] + Z; int BB = p[B+1] + Z; /* Add blended results from 8 corners of cube: */ return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ), grad(p[BA ], x-1, y , z )), lerp(u, grad(p[AB ], x , y-1, z ), grad(p[BB ], x-1, y-1, z ))), lerp(v, lerp(u, grad(p[AA+1], x , y , z-1), grad(p[BA+1], x-1, y , z-1)), lerp(u, grad(p[AB+1], x , y-1, z-1), grad(p[BB+1], x-1, y-1, z-1)))); } static int effectslib_perlinnoise(lua_State *L) { double x = lua_tonumber(L, 1); double y = lua_tonumber(L, 2); double z = lua_type(L, 3) == LUA_TNUMBER ? lua_tonumber(L, 3) : 0.0; lua_push_number(L, effectslib_perlin_noise_3(x, y, z)); return 1; } /*tex Original comment by Stefan: Helper functions to compute gradients-dot-residualvectors (1D to 4D). Note that these generate gradients of more than unit length. To make a close match with the value range of classic Perlin noise, the final noise values need to be rescaled to fit nicely within [-1,1]. The simplex noise functions as such also have different scaling.) Note also that these noise functions are the most practical and useful signed version of Perlin noise. To return values according to the RenderMan specification from the |SLnoise()| and |pnoise()| functions, the noise values need to be scaled and offset to [0,1], like this: |float SLnoise = (noise(x, y, z) + 1.0) * 0.5;|. */ /*tex The code has been adapted to doubles because that's what we use all over the place. I also reformatted it a bit. Is nowadays |FASTFLOOR| still faster than lfloor? Casting also comes at a price. */ /* # define FASTFLOOR(x) ( ((int) (x) <= (x)) ? ((int) x) : (((int) x) - 1) ) */ inline int FASTFLOOR(double x) { return (int) (x) <= x ? (int) x : (int) x - 1; } /* We get a gradient value 1.0, 2.0, ..., 8.0 with a random sign, multiplied with the distance. */ static inline double grad1(int hash, double x) { int h = hash & 15; double grad = 1.0 + (h & 7); if (h & 8) { grad = -grad; } return grad * x; } /* Convert low 3 bits of hash code into 8 simple gradient directions and compute the dot product with (x,y). */ static inline double grad2(int hash, double x, double y) { int h = hash & 7; double u = h < 4 ? x : y; double v = h < 4 ? y : x; return ((h & 1) ? -u : u) + ((h & 2) ? -2.0 * v : 2.0 * v); } /* Convert low 4 bits of hash code into 12 simple gradient directions and compute dot product. */ static inline double grad3(int hash, double x, double y , double z) { int h = hash & 15; double u = h < 8 ? x : y; double v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h = 12 to 15 return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); } /* Convert low 5 bits of hash code into 32 simple gradient directions and compute dot product. */ static inline double grad4(int hash, double x, double y, double z, double t) { int h = hash & 31; double u = h<24 ? x : y; double v = h<16 ? y : z; double w = h<8 ? z : t; return ((h & 1) ? -u : u) + ((h & 2) ? -v : v) + ((h & 4) ? -w : w); } /* A lookup table to traverse the simplex around a given point in 4D. Details can be found where this table is used, in the 4D noise method. */ static unsigned char simplex[64][4] = { {0,1,2,3}, {0,1,3,2}, {0,0,0,0}, {0,2,3,1}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {1,2,3,0}, {0,2,1,3}, {0,0,0,0}, {0,3,1,2}, {0,3,2,1}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {1,3,2,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {1,2,0,3}, {0,0,0,0}, {1,3,0,2}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {2,3,0,1}, {2,3,1,0}, {1,0,2,3}, {1,0,3,2}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {2,0,3,1}, {0,0,0,0}, {2,1,3,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {2,0,1,3}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {3,0,1,2}, {3,0,2,1}, {0,0,0,0}, {3,1,2,0}, {2,1,0,3}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {3,1,0,2}, {0,0,0,0}, {3,2,0,1}, {3,2,1,0} }; /*tex There are four variants of the simplex noise generator. */ /* The maximum value of this noise is 8*(3/4)^4 = 2.53125. A factor of 0.395 would scale to fit exactly within [-1,1], but we want to match PRMan's 1D noise, so we scale it down some more. */ static double effectslib_simplex_noise_1(double x) { int i0 = FASTFLOOR(x); int i1 = i0 + 1; double n0, n1; double x0 = x - i0; double x1 = x0 - 1.0; double t0 = 1.0 - x0 * x0; double t1 = 1.0 - x1 * x1; t0 *= t0; t1 *= t1; n0 = t0 * t0 * grad1(p[ i0 & 0xFF ], x0); n1 = t1 * t1 * grad1(p[ i1 & 0xFF ], x1); return 0.25 * (n0 + n1); } # define F2 0.366025403 // F2 = 0.5*(sqrt(3.0)-1.0) # define G2 0.211324865 // G2 = (3.0-Math.sqrt(3.0))/6.0 static double effectslib_simplex_noise_2(double x, double y) { /* noise contributions from the three corners */ double n0, n1, n2; /* skew the input space to determine which simplex cell we're in */ double s = (x + y) * F2; double xs = x + s; double ys = y + s; int i = FASTFLOOR(xs); int j = FASTFLOOR(ys); double t = (double) (i + j) * G2; /* unskew the cell origin back to (x,y) space */ double X0 = i - t; double Y0 = j - t; /* the x,y distances from the cell origin */ double x0 = x - X0; double y0 = y - Y0; /* For the 2D case, the simplex shape is an equilateral triangle. Determine which simplex we are in. Offsets for second (middle) corner of simplex in (i,j) coordinates: */ int i1, j1; if (x0 > y0) { /* lower triangle, XY order: (0,0)->(1,0)->(1,1) */ i1 = 1; j1 = 0; } else { /* upper triangle, YX order: (0,0)->(0,1)->(1,1) */ i1 = 0; j1 = 1; } /* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where c = (3-sqrt(3))/6 */ /* offsets for middle corner in (x,y) unskewed coords */ double x1 = x0 - i1 + G2; double y1 = y0 - j1 + G2; /* offsets for last corner in (x,y) unskewed coords */ double x2 = x0 - 1.0 + 2.0 * G2; double y2 = y0 - 1.0 + 2.0 * G2; /* wrapped integer indices at 256, to avoid indexing p[] out of bounds */ int ii = i & 0xFF; int jj = j & 0xFF; /* calculate the contribution from the three corners */ double t0 = 0.5 - x0 * x0 - y0 * y0; double t1 = 0.5 - x1 * x1 - y1 * y1; double t2 = 0.5 - x2 * x2 - y2 * y2; if (t0 < 0.0) { n0 = 0.0; } else { t0 *= t0; n0 = t0 * t0 * grad2(p[ ii + p[ jj ] ], x0, y0); } if (t1 < 0.0) { n1 = 0.0; } else { t1 *= t1; n1 = t1 * t1 * grad2(p[ ii + i1 + p[ jj + j1 ] ], x1, y1); } if (t2 < 0.0) { n2 = 0.0; } else { t2 *= t2; n2 = t2 * t2 * grad2(p[ ii + 1 + p[ jj + 1 ] ], x2, y2); } /* Add contributions from each corner to get the final noise value. The result is scaled to return values in the interval [-1,1]. TODO: The scale factor is preliminary! */ return 40.0 * (n0 + n1 + n2); } # define F3 0.333333333 # define G3 0.166666667 static double effectslib_simplex_noise_3(double x, double y, double z) { /* simple skewing factors for the 3D case; noise contributions from the four corners */ double n0, n1, n2, n3; /* skew the input space to determine which simplex cell we're in */ double s = (x + y + z) * F3; double xs = x + s; double ys = y + s; double zs = z + s; int i = FASTFLOOR(xs); int j = FASTFLOOR(ys); int k = FASTFLOOR(zs); double t = (double) (i + j + k) * G3; /* unskew the cell origin back to (x,y,z) space */ double X0 = i - t; double Y0 = j - t; double Z0 = k - t; /* the x,y,z distances from the cell origin */ double x0 = x - X0; double y0 = y - Y0; double z0 = z - Z0; /* For the 3D case, the simplex shape is a slightly irregular tetrahedron. Determine which simplex we are in. */ /* offsets for second corner of simplex in (i,j,k) coords */ int i1, j1, k1; /* offsets for third corner of simplex in (i,j,k) coords */ int i2, j2, k2; /* this code would benefit from a backport from the GLSL version */ if (x0 >= y0) { if (y0 >= z0) { /* X Y Z order */ i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } else if (x0 >= z0) { /* X Z Y order */ i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } else { /* Z X Y order */ i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } } else { if (y0 < z0) { /* Z Y X order */ i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } else if (x0 < z0) { /* Y Z X order */ i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } else { /* Y X Z order */ i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } } /* A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where c = 1/6. */ /* offsets for second corner in (x,y,z) coords */ double x1 = x0 - i1 + G3; double y1 = y0 - j1 + G3; double z1 = z0 - k1 + G3; /* offsets for third corner in (x,y,z) coords */ double x2 = x0 - i2 + 2.0 * G3; double y2 = y0 - j2 + 2.0 * G3; double z2 = z0 - k2 + 2.0 * G3; /* offsets for last corner in (x,y,z) coords */ double x3 = x0 - 1.0 + 3.0 * G3; double y3 = y0 - 1.0 + 3.0 * G3; double z3 = z0 - 1.0 + 3.0 * G3; /* wrap the integer indices at 256, to avoid indexing p[] out of bounds */ int ii = i & 0xFF; int jj = j & 0xFF; int kk = k & 0xFF; /* calculate the contribution from the four corners */ double t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0; double t1 = 0.5 - x1 * x1 - y1 * y1 - z1 * z1; double t2 = 0.5 - x2 * x2 - y2 * y2 - z2 * z2; double t3 = 0.5 - x3 * x3 - y3 * y3 - z3 * z3; if (t0 < 0.0) { n0 = 0.0; } else { t0 *= t0; n0 = t0 * t0 * grad3(p[ ii + p[ jj + p[ kk ] ] ], x0, y0, z0); } if (t1 < 0.0) { n1 = 0.0; } else { t1 *= t1; n1 = t1 * t1 * grad3(p[ ii + i1 + p[ jj + j1 + p[ kk + k1 ] ] ], x1, y1, z1); } if (t2 < 0.0) { n2 = 0.0; } else { t2 *= t2; n2 = t2 * t2 * grad3(p[ ii + i2 + p[ jj + j2 + p[ kk + k2 ] ] ], x2, y2, z2); } if (t3 < 0.0) { n3 = 0.0; } else { t3 *= t3; n3 = t3 * t3 * grad3(p[ ii + 1 + p[ jj + 1 + p[ kk + 1 ] ] ], x3, y3, z3); } /* Add contributions from each corner to get the final noise value. The result is scaled to stay just inside [-1,1] */ return 72.0 * (n0 + n1 + n2 + n3); } /* Original comment: For the 4D case, the simplex is a 4D shape I won't even try to describe. To find out which of the 24 possible simplices we're in, we need to determine the magnitude ordering of x0, y0, z0 and w0. The method below is a good way of finding the ordering of x,y,z,w and then find the correct traversal order for the simplex we're in. First, six pair-wise comparisons are performed between each possible pair of the four coordinates, and the results are used to add up binary bits for an integer index. In the code below simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. Many values of c will never occur, since e.g. x>y>z>w makes x y0) ? 32 : 0; int c2 = (x0 > z0) ? 16 : 0; int c3 = (y0 > z0) ? 8 : 0; int c4 = (x0 > w0) ? 4 : 0; int c5 = (y0 > w0) ? 2 : 0; int c6 = (z0 > w0) ? 1 : 0; int c = c1 + c2 + c3 + c4 + c5 + c6; /* the integer offsets for the second, third and fourth simplex corners */ int i1, j1, k1, l1; int i2, j2, k2, l2; int i3, j3, k3, l3; /* see comment above */ i1 = simplex[c][0] >= 3 ? 1 : 0; j1 = simplex[c][1] >= 3 ? 1 : 0; k1 = simplex[c][2] >= 3 ? 1 : 0; l1 = simplex[c][3] >= 3 ? 1 : 0; /* the number 2 in the "simplex" array is at the second largest coordinate */ i2 = simplex[c][0] >= 2 ? 1 : 0; j2 = simplex[c][1] >= 2 ? 1 : 0; k2 = simplex[c][2] >= 2 ? 1 : 0; l2 = simplex[c][3] >= 2 ? 1 : 0; /* the number 1 in the "simplex" array is at the second smallest coordinate */ i3 = simplex[c][0] >= 1 ? 1 : 0; j3 = simplex[c][1] >= 1 ? 1 : 0; k3 = simplex[c][2] >= 1 ? 1 : 0; l3 = simplex[c][3] >= 1 ? 1 : 0; /* the fifth corner has all coordinate offsets = 1, so no need to look that up */ /* */ /* offsets for second corner in (x,y,z,w) coords */ double x1 = x0 - i1 + G4; double y1 = y0 - j1 + G4; double z1 = z0 - k1 + G4; double w1 = w0 - l1 + G4; /* offsets for third corner in (x,y,z,w) coords */ double x2 = x0 - i2 + 2.0 * G4; double y2 = y0 - j2 + 2.0 * G4; double z2 = z0 - k2 + 2.0 * G4; double w2 = w0 - l2 + 2.0 * G4; /* offsets for fourth corner in (x,y,z,w) coords. */ double x3 = x0 - i3 + 3.0 * G4; double y3 = y0 - j3 + 3.0 * G4; double z3 = z0 - k3 + 3.0 * G4; double w3 = w0 - l3 + 3.0 * G4; /* offsets for last corner in (x,y,z,w) coords. */ double x4 = x0 - 1.0 + 4.0 * G4; double y4 = y0 - 1.0 + 4.0 * G4; double z4 = z0 - 1.0 + 4.0 * G4; double w4 = w0 - 1.0 + 4.0 * G4; /* Wrap the integer indices at 256, to avoid indexing p[] out of bounds */ int ii = i & 0xFF; int jj = j & 0xFF; int kk = k & 0xFF; int ll = l & 0xFF; /* calculate the contribution from the five corners */ double t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; double t1 = 0.5 - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; double t2 = 0.5 - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; double t3 = 0.5 - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; double t4 = 0.5 - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; if (t0 < 0.0) { n0 = 0.0; } else { t0 *= t0; n0 = t0 * t0 * grad4(p[ ii + p[ jj + p[ kk + p[ ll ] ] ] ], x0, y0, z0, w0); } if (t1 < 0.0) { n1 = 0.0; } else { t1 *= t1; n1 = t1 * t1 * grad4(p[ ii + i1 + p[ jj + j1 + p[ kk + k1 + p[ ll + l1 ] ] ] ], x1, y1, z1, w1); } if (t2 < 0.0) { n2 = 0.0; } else { t2 *= t2; n2 = t2 * t2 * grad4(p[ ii + i2 + p[ jj + j2 + p[ kk + k2 + p[ ll + l2 ] ] ] ], x2, y2, z2, w2); } if(t3 < 0.0) { n3 = 0.0; } else { t3 *= t3; n3 = t3 * t3 * grad4(p[ ii + i3 + p[ jj + j3 + p[ kk + k3 + p[ ll + l3 ] ] ] ], x3, y3, z3, w3); } if (t4 < 0.0) { n4 = 0.0; } else { t4 *= t4; n4 = t4 * t4 * grad4(p[ ii + 1 + p[ jj + 1 + p[ kk + 1 + p[ ll + 1 ] ] ] ], x4, y4, z4, w4); } /* sum up and scale the result to cover the range [-1,1] */ return 62.0 * (n0 + n1 + n2 + n3 + n4); } /* The code is a bit adapted and made a bit more conistent with the rest. Like NULL testing and clipping & 0xFF vs % 256). We also went double. */ /* This is an implementation of Perlin "simplex noise" over two dimensions (x,y) and three dimensions (x,y,z). One extra parameter 't' rotates the underlying gradients of the grid, which gives a swirling, flow-like motion. The derivative is returned, to make it possible to do pseudo-advection and implement "flow noise", as presented by Ken Perlin and Fabrice Neyret at Siggraph 2001. When not animated and presented in one octave only, this noise looks exactly the same as the plain version of simplex noise. It's nothing magical by itself, although the extra animation parameter 't' is useful. Fun stuff starts to happen when you do fractal sums of several octaves, with different rotation speeds and an advection of smaller scales by larger scales (or even the other way around it you feel adventurous). The gradient rotations that can be performed by this noise function and the true analytic derivatives are required to do flow noise. You can't do it properly with regular Perlin noise. The 3D version is my own creation. It's a hack, because unlike the 2D version the gradients rotate around different axes, and therefore they don't remain uncorrelated through the rotation, but it looks OK. */ /* Gradient tables. These could be programmed the Ken Perlin way with some clever bit-twiddling, but this is more clear, and not really slower. */ static double grad2m[8][2] = { { -1.0, -1.0 }, { 1.0, 0.0 }, { -1.0, 0.0 }, { 1.0, 1.0 }, { -1.0, 1.0 }, { 0.0, -1.0 }, { 0.0, 1.0 }, { 1.0, -1.0 }, }; /* For 3D, we define two orthogonal vectors in the desired rotation plane. These vectors are based on the midpoints of the 12 edges of a cube, they all rotate in their own plane and are never coincident or collinear. A larger array of random vectors would also do the job, but these 12 (including 4 repeats to make the array length a power of two) work better. They are not random, they are carefully chosen to represent a small isotropic set of directions for any rotation angle. */ # define a 0.81649658f /* a = sqrt(2)/sqrt(3) = 0.816496580 */ static double grad3u[16][3] = { { 1.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }, // 12 cube edges { -1.0, 0.0, 1.0 }, { 0.0, -1.0, 1.0 }, { 1.0, 0.0, -1.0 }, { 0.0, 1.0, -1.0 }, { -1.0, 0.0, -1.0 }, { 0.0, -1.0, -1.0 }, { a, a, a }, { -a, a, -a }, { -a, -a, a }, { a, -a, -a }, { -a, a, a }, { a, -a, a }, { a, -a, -a }, { -a, a, -a }, }; static double grad3v[16][3] = { { -a, a, a }, { -a, -a, a }, { a, -a, a }, { a, a, a }, { -a, -a, -a }, { a, -a, -a }, { a, a, -a }, { -a, a, -a }, { 1.0, -1.0, 0.0 }, { 1.0, 1.0, 0.0 }, { -1.0, 1.0, 0.0 }, { -1.0, -1.0, 0.0 }, { 1.0, 0.0, 1.0 }, { -1.0, 0.0, 1.0 }, // 4 repeats to make 16 { 0.0, 1.0, -1.0 }, { 0.0, -1.0, -1.0 }, }; # undef a /* Helper functions to compute rotated gradients and gradients-dot-residualvectors in 2D and 3D. */ static void gradrot2(int hash, double sin_t, double cos_t, double *gx, double *gy) { int h = hash & 7; double gx0 = grad2m[h][0]; double gy0 = grad2m[h][1]; *gx = cos_t * gx0 - sin_t * gy0; *gy = sin_t * gx0 + cos_t * gy0; return; } static void gradrot3(int hash, double sin_t, double cos_t, double *gx, double *gy, double *gz) { int h = hash & 15; double gux = grad3u[h][0]; double guy = grad3u[h][1]; double guz = grad3u[h][2]; double gvx = grad3v[h][0]; double gvy = grad3v[h][1]; double gvz = grad3v[h][2]; *gx = cos_t * gux + sin_t * gvx; *gy = cos_t * guy + sin_t * gvy; *gz = cos_t * guz + sin_t * gvz; return; } static double graddotp2(double gx, double gy, double x, double y) { return gx * x + gy * y; } static double graddotp3(double gx, double gy, double gz, double x, double y, double z) { return gx * x + gy * y + gz * z; } /* If the last two arguments are not null, the analytic derivative (the 2D gradient of the total noise field) is also calculated. */ /*tex Most comments have been removed because they are the same as above. */ static double effectslib_simplex_detail_2(double x, double y, double sin_t, double cos_t, double *dx, double *dy) { double n0, n1, n2; /* Noise contributions from the three simplex corners */ double gx0, gy0, gx1, gy1, gx2, gy2; /* Gradients at simplex corners */ double s = (x + y) * F2; /* Hairy factor for 2D */ double xs = x + s; double ys = y + s; int i = FASTFLOOR(xs); int j = FASTFLOOR(ys); double t = (double) (i + j) * G2; double X0 = i - t; double Y0 = j - t; double x0 = x - X0; double y0 = y - Y0; int i1, j1; if (x0 > y0) { i1 = 1; j1 = 0; } else { i1 = 0; j1 = 1; } double x1 = x0 - i1 + G2; double y1 = y0 - j1 + G2; double x2 = x0 - 1.0 + 2.0 * G2; double y2 = y0 - 1.0 + 2.0 * G2; int ii = i & 0xFF; int jj = j & 0xFF; double t0 = 0.5 - x0 * x0 - y0 * y0; double t20, t40; if (t0 < 0.0) { t40 = t20 = t0 = n0 = gx0 = gy0 = 0.0; } else { gradrot2(p[ ii + p[ jj ] ], sin_t, cos_t, &gx0, &gy0); t20 = t0 * t0; t40 = t20 * t20; n0 = t40 * graddotp2(gx0, gy0, x0, y0); } double t1 = 0.5 - x1 * x1 - y1 * y1; double t2 = 0.5 - x2 * x2 - y2 * y2; double t21, t41; double t22, t42; if (t1 < 0.0) { t21 = t41 = t1 = n1 = gx1 = gy1 = 0.0; } else { gradrot2(p[ ii + i1 + p[ jj + j1 ] ], sin_t, cos_t, &gx1, &gy1); t21 = t1 * t1; t41 = t21 * t21; n1 = t41 * graddotp2(gx1, gy1, x1, y1); } if (t2 < 0.0) { t42 = t22 = t2 = n2 = gx2 = gy2 = 0.0; } else { gradrot2(p[ ii + 1 + p[ jj + 1 ] ], sin_t, cos_t, &gx2, &gy2); t22 = t2 * t2; t42 = t22 * t22; n2 = t42 * graddotp2(gx2, gy2, x2, y2); } double noise = 40.0 * (n0 + n1 + n2); if (dx && dy) { double temp0 = t20 * t0 * graddotp2(gx0, gy0, x0, y0); double temp1 = t21 * t1 * graddotp2(gx1, gy1, x1, y1); double temp2 = t22 * t2 * graddotp2(gx2, gy2, x2, y2); *dx = temp0 * x0 + temp1 * x1 + temp2 * x2; *dy = temp0 * y0 + temp1 * y1 + temp2 * y2; *dx *= -8.0; *dy *= -8.0; *dx += t40 * gx0 + t41 * gx1 + t42 * gx2; *dy += t40 * gy0 + t41 * gy1 + t42 * gy2; *dx *= 40.0; *dy *= 40.0; } return noise; } /*tex Most comments have been removed because they are the same as above. */ static double effectslib_simplex_detail_3(double x, double y, double z, double sin_t, double cos_t, double *dx, double *dy, double *dz) { double n0, n1, n2, n3; double noise; double gx0, gy0, gz0, gx1, gy1, gz1; double gx2, gy2, gz2, gx3, gy3, gz3; double s = (x + y + z) * F3; double xs = x + s; double ys = y + s; double zs = z + s; int i = FASTFLOOR(xs); int j = FASTFLOOR(ys); int k = FASTFLOOR(zs); double t = (double) (i + j + k) * G3; double X0 = i - t; double Y0 = j - t; double Z0 = k - t; double x0 = x - X0; double y0 = y - Y0; double z0 = z - Z0; int i1, j1, k1; int i2, j2, k2; if (x0 >= y0) { if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } } else { if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } } double x1 = x0 - i1 + G3; double y1 = y0 - j1 + G3; double z1 = z0 - k1 + G3; double x2 = x0 - i2 + 2.0 * G3; double y2 = y0 - j2 + 2.0 * G3; double z2 = z0 - k2 + 2.0 * G3; double x3 = x0 - 1.0 + 3.0 * G3; double y3 = y0 - 1.0 + 3.0 * G3; double z3 = z0 - 1.0 + 3.0 * G3; int ii = i & 0xFF; int jj = j & 0xFF; int kk = k & 0xFF; double t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0; double t20, t40; if (t0 < 0.0) { n0 = t0 = t20 = t40 = gx0 = gy0 = gz0 = 0.0; } else { gradrot3(p[ ii + p[ jj + p[ kk ] ] ], sin_t, cos_t, &gx0, &gy0, &gz0); t20 = t0 * t0; t40 = t20 * t20; n0 = t40 * graddotp3(gx0, gy0, gz0, x0, y0, z0); } double t1 = 0.5 - x1*x1 - y1*y1 - z1*z1; double t2 = 0.5 - x2*x2 - y2*y2 - z2*z2; double t3 = 0.5 - x3*x3 - y3*y3 - z3*z3; double t21, t41; double t22, t42; double t23, t43; if (t1 < 0.0) { n1 = t1 = t21 = t41 = gx1 = gy1 = gz1 = 0.0; } else { gradrot3(p[ ii + i1 + p[ jj + j1 + p[ kk + k1 ] ] ], sin_t, cos_t, &gx1, &gy1, &gz1); t21 = t1 * t1; t41 = t21 * t21; n1 = t41 * graddotp3(gx1, gy1, gz1, x1, y1, z1); } if (t2 < 0.0) { n2 = t2 = t22 = t42 = gx2 = gy2 = gz2 = 0.0; } else { gradrot3(p[ ii + i2 + p[ jj + j2 + p[ kk + k2 ] ] ], sin_t, cos_t, &gx2, &gy2, &gz2); t22 = t2 * t2; t42 = t22 * t22; n2 = t42 * graddotp3(gx2, gy2, gz2, x2, y2, z2); } if (t3 < 0.0) { n3 = t3 = t23 = t43 = gx3 = gy3 = gz3 = 0.0; } else { gradrot3(p[ ii + 1 + p[ jj + 1 + p[ kk + 1 ] ] ], sin_t, cos_t, &gx3, &gy3, &gz3); t23 = t3 * t3; t43 = t23 * t23; n3 = t43 * graddotp3(gx3, gy3, gz3, x3, y3, z3); } /* add contributions from each corner to get the final noise value and scale down to [-1,1] */ noise = 72.0 * (n0 + n1 + n2 + n3); /* compute derivative, if requested by supplying non-null pointers for the last three arguments */ if (dx && dy && dz) { double temp0 = t20 * t0 * graddotp3(gx0, gy0, gz0, x0, y0, z0); double temp1 = t21 * t1 * graddotp3(gx1, gy1, gz1, x1, y1, z1); double temp2 = t22 * t2 * graddotp3(gx2, gy2, gz2, x2, y2, z2); double temp3 = t23 * t3 * graddotp3(gx3, gy3, gz3, x3, y3, z3); *dx = temp0 * x0 + temp1 * x1 + temp2 * x2 + temp3 * x3; *dy = temp0 * y0 + temp1 * y1 + temp2 * y2 + temp3 * y3; *dz = temp0 * z0 + temp1 * z1 + temp2 * z2 + temp3 * z3; *dx *= -8.0; *dy *= -8.0; *dz *= -8.0; *dx += t40 * gx0 + t41 * gx1 + t42 * gx2 + t43 * gx3; *dy += t40 * gy0 + t41 * gy1 + t42 * gy2 + t43 * gy3; *dz += t40 * gz0 + t41 * gz1 + t42 * gz2 + t43 * gz3; *dx *= 72.0; *dy *= 72.0; *dz *= 72.0; } return noise; } /*tex We've now come to the \LUA\ interfacing. */ /* x [ y [ z [ w ] ] ] */ static int effectslib_simplexnoise(lua_State *L) { int top = lua_gettop(L); double x = top == 1 ? lua_tonumber(L, 1) : 0.0; double y = top == 2 ? lua_tonumber(L, 2) : 0.0; double z = top == 3 ? lua_tonumber(L, 3) : 0.0; double w = top == 4 ? lua_tonumber(L, 4) : 0.0; double n ; switch (top) { case 4 : n = effectslib_simplex_noise_4(x, y, z, w); break; case 3 : n = effectslib_simplex_noise_3(x, y, z); break; case 2 : n = effectslib_simplex_noise_2(x, y); break; case 1 : n = effectslib_simplex_noise_1(x); break; default : n = 0.0; break; } lua_push_number(L, n); return 1; } /* angle x y [ z ] */ static int effectslib_simplexangle(lua_State *L) { int three = lua_type(L, 4) == LUA_TNUMBER; double angle = lua_tonumber(L, 1); double x = lua_tonumber(L, 2); double y = lua_tonumber(L, 3); double z = three ? lua_tonumber(L, 4) : 0.0; double sin_t = sin(angle); double cos_t = cos(angle); double noise; if (three) { noise = effectslib_simplex_detail_3(x, y, z, sin_t, cos_t, NULL, NULL, NULL); } else { noise = effectslib_simplex_detail_2(x, y, sin_t, cos_t, NULL, NULL); } lua_push_number(L, noise); return 1; } static int effectslib_simplexdetail(lua_State *L) { int three = lua_type(L, 4) == LUA_TNUMBER; double angle = lua_tonumber(L, 1); double x = lua_tonumber(L, 2); double y = lua_tonumber(L, 3); double z = three ? lua_tonumber(L, 4) : 0.0; double dx = 0.0; double dy = 0.0; double dz = 0.0; double sin_t = sin(angle); double cos_t = cos(angle); double noise; if (three) { noise = effectslib_simplex_detail_3(x, y, z, sin_t, cos_t, &dx, &dy, &dz); } else { noise = effectslib_simplex_detail_2(x, y, sin_t, cos_t, &dx, &dy); } lua_pushnumber(L, noise); lua_pushnumber(L, dx); lua_pushnumber(L, dy); if (three) { lua_push_number(L, dz); return 4; } else { return 3; } } # define OCTAVE_METATABLE "noise octave" typedef enum octave_method { octave_perlin = 1, octave_simplex = 2, octave_angle = 3, octave_detail = 4, } octave_method; # define first_octave_method octave_perlin # define last_octave_method octave_detail typedef enum octave_loop { /* same as bytemap_loop */ octave_loop_xy, octave_loop_yx, } octave_loop; # define first_octave_loop octave_loop_xy # define last_octave_loop octave_loop_yx typedef enum octave_variant { octave_perlin_noise_3 = 0, octave_simplex_noise_1 = 1, octave_simplex_noise_2 = 2, octave_simplex_noise_3 = 3, octave_simplex_noise_4 = 4, octave_simplex_detail_2 = 5, octave_simplex_detail_3 = 6, } octave_variant; typedef struct octave { /* properties */ int iterations; // 1 double amplitude; // 1.0 double frequency; // 1.0 double persistence; // 0.5 double lacunarity; // 2.0 double angle; // 0 double minimum; // 0 double maximum; // 255 int method; // 1 /* calculated */ int detail; int count; /* changes as we go */ double x; double y; double z; double w; /* */ int existing; double noise; int zset; int wset; int variant; int loop; /* */ double sin; double cos; /* */ double dx; double dy; double dz; /* */ int b1; int b2; int b3; } octave; static int effectslib_octave_methods(lua_State *L) { lua_createtable(L, 4, 0); lua_set_string_by_index(L, octave_perlin, "perlin"); lua_set_string_by_index(L, octave_simplex, "simplex"); lua_set_string_by_index(L, octave_angle, "angle"); lua_set_string_by_index(L, octave_detail, "detail"); return 1; } static int effectslib_octave_loops(lua_State *L) { lua_createtable(L, 2, 0); lua_set_string_by_index(L, octave_loop_xy, "xy"); lua_set_string_by_index(L, octave_loop_yx, "yx"); return 1; } static int effectslib_octave_variants(lua_State *L) { lua_createtable(L, 5, 2); lua_set_string_by_index(L, octave_perlin_noise_3, "perlin 3"); lua_set_string_by_index(L, octave_simplex_noise_1, "simplex 1"); lua_set_string_by_index(L, octave_simplex_noise_2, "simplex 2"); lua_set_string_by_index(L, octave_simplex_noise_3, "simplex 3"); lua_set_string_by_index(L, octave_simplex_noise_4, "simplex 4"); lua_set_string_by_index(L, octave_simplex_detail_2, "simplex 2 derivative"); lua_set_string_by_index(L, octave_simplex_detail_3, "simplex 3 derivative"); return 1; } static int effectslib_octave_aux_set(lua_State *L, octave *o, int direct) { /* todo: also accept a table */ o->method = lua_tointeger(L, 1); o->iterations = lua_tointeger(L, 2); o->amplitude = lua_tonumber(L, 3); o->frequency = lua_tonumber(L, 4); o->persistence = lua_tonumber(L, 5); o->lacunarity = lua_tonumber(L, 6); /* we used scale before */ o->angle = lua_tonumber(L, 7); o->minimum = lua_tonumber(L, 8); o->maximum = lua_tonumber(L, 9); o->loop = octave_loop_xy; o->variant = octave_perlin_noise_3; o->sin = sin(o->angle); o->cos = cos(o->angle); o->x = 0.0; o->y = 0.0; if (direct) { o->z = 0.0; o->w = 0.0; o->zset = 0; o->wset = 0; direct = 0; } else { o->z = lua_tonumber(L, 10); o->w = lua_tonumber(L, 11); o->zset = lua_type(L, 10) == LUA_TNUMBER; o->wset = lua_type(L, 11) == LUA_TNUMBER; direct = 11; // o->loop = lua_tointeger(L, 12); /* we then need to adapt elsewhere */ // direct = 12; } /* check */ if (o->loop < first_octave_loop || o->method > last_octave_loop) { o->loop = first_octave_loop; } if (o->method < first_octave_method || o->method > last_octave_method) { o->method = first_octave_method; } o->detail = o->method == octave_detail; o->count = 0; /* safeguards */ if (o->persistence < 0.0) { o->persistence = 1.0; } else if (o->persistence > 1.0) { o->persistence = 1.0; } if (o->amplitude <= 0.0) { o->amplitude = 1.0; } if (o->lacunarity < 1.0) { o->lacunarity = 1.0; } /* done */ return direct; } /*tex We can optimize this: We can even keep already set values. */ static void effectslib_octave_aux_use(lua_State *L, octave *o, int index, int count) { switch (count) { case 1: o->x = lua_tonumber(L, index++); o->y = 0.0; o->z = 0.0; o->w = 0.0; o->count = 1; break; case 2: o->x = lua_tonumber(L, index++); o->y = lua_tonumber(L, index++); o->z = 0.0; o->w = 0.0; o->count = 2; break; case 3: o->x = lua_tonumber(L, index++); o->y = lua_tonumber(L, index++); o->z = lua_tonumber(L, index++); o->w = 0.0; o->count = 3; break; case 4: o->x = lua_tonumber(L, index++); o->y = lua_tonumber(L, index++); o->z = lua_tonumber(L, index++); o->w = lua_tonumber(L, index++); o->count = 4; break; default: o->x = 0.0; o->y = 0.0; o->z = 0.0; o->w = 0.0; o->count = 0; break; } } static int effectslib_octave_aux_return(lua_State *L, octave *o) { lua_pushnumber(L, o->noise); if (o->detail) { switch (o->count) { case 1: lua_pushnumber(L, o->dx); return 2; case 2: lua_pushnumber(L, o->dx); lua_pushnumber(L, o->dy); return 3; case 3: lua_pushnumber(L, o->dx); lua_pushnumber(L, o->dy); lua_pushnumber(L, o->dz); return 4; } } return 1; } static int effectslib_octave_aux_push(lua_State *L, octave *o) { int n = 3; lua_pushnumber(L, o->noise); lua_pushnumber(L, o->x); lua_pushnumber(L, o->y); if (o->detail) { switch (o->count) { case 1: lua_pushnumber(L, o->dx); n += 1; break; case 2: case 3: /* todo dz */ case 4: /* todo dz */ lua_pushnumber(L, o->dx); lua_pushnumber(L, o->dy); n += 2; break; } } if (o->existing == 3) { lua_pushinteger(L, o->b1); lua_pushinteger(L, o->b2); lua_pushinteger(L, o->b3); n += 3; } else if (o->existing == 1) { lua_pushinteger(L, o->b1); n += 1; } return n; } static void effectslib_octave_aux_get(octave *o) { int variant = 2; double amplitude = o->amplitude; double frequency = o->frequency; double maxamplitude = 0.0; double noise = 0.0; switch (o->method) { case octave_perlin: variant = octave_perlin_noise_3; break; case octave_simplex: // octave_simplex_noise_1 .. octave_simplex_noise_4 variant = o->count; break; case octave_angle: case octave_detail: variant = o->count > 2 ? octave_simplex_detail_3 : octave_simplex_detail_2; break; } /*tex Optimizing for n=1 gives us some on extensive tests. */ // if (1) { if (o->iterations > 1) { for (int i = 0; i < o->iterations; i++) { double result; switch (variant) { case octave_perlin_noise_3: result = effectslib_perlin_noise_3 (o->x * frequency, o->y * frequency, o->z * frequency); break; case octave_simplex_noise_1: result = effectslib_simplex_noise_1(o->x * frequency); break; case octave_simplex_noise_2: result = effectslib_simplex_noise_2(o->x * frequency, o->y * frequency); break; case octave_simplex_noise_3: result = effectslib_simplex_noise_3(o->x * frequency, o->y * frequency, o->z * frequency); break; case octave_simplex_noise_4: result = effectslib_simplex_noise_4(o->x * frequency, o->y * frequency, o->z * frequency, o->w * frequency); break; case octave_simplex_detail_2: if (o->detail && i == o->iterations - 1) { result = effectslib_simplex_detail_2(o->x * frequency, o->y * frequency, o->sin, o->cos, NULL, NULL); } else { result = effectslib_simplex_detail_2(o->x * frequency, o->y * frequency, o->sin, o->cos, &o->dx, &o->dy); } break; case octave_simplex_detail_3: if (o->detail && i == o->iterations - 1) { result = effectslib_simplex_detail_3(o->x * frequency, o->y * frequency, o->z * frequency, o->sin, o->cos, NULL, NULL, NULL); } else { result = effectslib_simplex_detail_3(o->x * frequency, o->y * frequency, o->z * frequency, o->sin, o->cos, &o->dx, &o->dy, &o->dz); } break; default: result = 0.0; break; } noise += amplitude * result; maxamplitude += amplitude; amplitude *= o->persistence; frequency *= o->lacunarity; } noise = noise / maxamplitude; } else { switch (variant) { case octave_perlin_noise_3: noise = effectslib_perlin_noise_3 (o->x * frequency, o->y * frequency, o->z * frequency); break; case octave_simplex_noise_1: noise = effectslib_simplex_noise_1(o->x * frequency); break; case octave_simplex_noise_2: noise = effectslib_simplex_noise_2(o->x * frequency, o->y * frequency); break; case octave_simplex_noise_3: noise = effectslib_simplex_noise_3(o->x * frequency, o->y * frequency, o->z * frequency); break; case octave_simplex_noise_4: noise = effectslib_simplex_noise_4(o->x * frequency, o->y * frequency, o->z * frequency, o->w * frequency); break; case octave_simplex_detail_2: noise = effectslib_simplex_detail_2(o->x * frequency, o->y * frequency, o->sin, o->cos, NULL, NULL); break; case octave_simplex_detail_3: noise = effectslib_simplex_detail_3(o->x * frequency, o->y * frequency, o->z * frequency, o->sin, o->cos, NULL, NULL, NULL); break; default: noise = 0.0; break; } } /* we normalize the result to the range minimum .. maximum */ noise = noise * (o->maximum - o->minimum) + (o->maximum + o->minimum); /* can be precalculated: no gain */ noise = noise / 2; /* and make sure we fit inside the range */ if (noise > o->maximum) { noise = o->maximum; } else if (noise < o->minimum) { noise = o->minimum; } o->variant = variant; o->noise = noise; } static inline octave * effectslib_octave_aux_valid(lua_State *L, int i) { // we need a fast one for this return (octave *) luaL_checkudata(L, i, OCTAVE_METATABLE); } static int effectslib_octave_direct(lua_State *L) { octave o; int done = effectslib_octave_aux_set(L, &o, 1); effectslib_octave_aux_use(L, &o, done + 1, lua_gettop(L) - done); effectslib_octave_aux_get(&o); return effectslib_octave_aux_return(L, &o); } static inline int effectslib_octave_new(lua_State *L) { /* todo: also initialize from table */ octave *o = lua_newuserdatauv(L, sizeof(octave), 0); luaL_setmetatable(L, OCTAVE_METATABLE); /* The user data object now sits at the top! */ effectslib_octave_aux_set(L, o, 0); return 1; } static int effectslib_octave_step(lua_State *L) { octave *o = effectslib_octave_aux_valid(L, 1); if (o) { effectslib_octave_aux_use(L, o, 2, lua_gettop(L) - 1); effectslib_octave_aux_get(o); return effectslib_octave_aux_return(L, o); } else { return 0; } } static void effectslib_octave_aux_loop(lua_State *L, octave * o, int nx, int ny, int nz, unsigned char * bytemap, int slot) { int fn = lua_type(L, slot) == LUA_TFUNCTION; if (o->wset) { o->count = 4; } else if (o->zset) { o->count = 3; } else { o->count = 2; } if (o->loop == octave_loop_yx) { unsigned char * p = bytemap; for (int y = 0; y < ny; y++) { o->y = y; for (int x = 0; x < nx; x++) { o->x = x; effectslib_octave_aux_get(o); if (fn) { /* we need to retain the function */ lua_pushvalue(L, slot); /* pass to function */ if (o->existing == 3) { o->b1 = (int) *p; o->b2 = (int) *(p+1); o->b3 = (int) *(p+2); } else if (o->existing == 1) { o->b1 = (int) *p; } /* call function */ { int n = effectslib_octave_aux_push(L, o); if (lua_pcall(L, n, nz, 0) != 0) { tex_formatted_warning("effectslib", "run octave: %s", lua_tostring(L, -1)); // lua_pushliteral(L, "error running octave"); // lua_error(L); } } /* use results */ if (nz == 3) { *p++ = (unsigned char) lmt_roundnumber(L, -3); /* slot + 1 */ *p++ = (unsigned char) lmt_roundnumber(L, -2); /* slot + 2 */ // *p++ = (unsigned char) lmt_roundnumber(L, -3); /* slot + 3 */ } else { // *p++ = (unsigned char) lmt_roundnumber(L, -1); /* slot + 1 */ } *p++ = (unsigned char) lmt_roundnumber(L, -1); /* slot + . */ /* wrap up */ lua_settop(L, slot); } else { unsigned char c = (unsigned char) lround(o->noise); *p++ = c; if (nz == 3) { *p++ = c; *p++ = c; } } } } } else { for (int x = 0; x < nx; x++) { o->x = x; for (int y = 0; y < ny; y++) { int p = ((ny - y - 1) * nx * nz) + x * nz; o->y = y; effectslib_octave_aux_get(o); if (fn) { /* we need to retain the function */ lua_pushvalue(L, slot); /* pass to function */ if (o->existing == 3) { o->b1 = (int) bytemap[p ]; o->b2 = (int) bytemap[p+1]; o->b3 = (int) bytemap[p+2]; } else if (o->existing == 1) { o->b1 = (int) bytemap[p ]; } /* call function */ { int n = effectslib_octave_aux_push(L, o); if (lua_pcall(L, n, nz, 0) != 0) { // lua_pushliteral(L, "error running octave"); lua_error(L); } } /* use results */ if (nz == 3) { bytemap[p ] = (unsigned char) lmt_roundnumber(L, -3); /* slot + 1 */ bytemap[p+1] = (unsigned char) lmt_roundnumber(L, -2); /* slot + 2 */ bytemap[p+2] = (unsigned char) lmt_roundnumber(L, -1); /* slot + 3 */ } else { bytemap[p ] = (unsigned char) lmt_roundnumber(L, -1); /* slot + 1 */ } /* wrap up */ lua_settop(L, slot); } else { unsigned char c = (unsigned char) lround(o->noise); bytemap[p] = c; if (nz == 3) { bytemap[p+1] = c; bytemap[p+2] = c; } } } } } } static int effectslib_octave_bytemap(lua_State *L) { octave *o = effectslib_octave_aux_valid(L, 1); if (o) { int nx = lua_tointeger(L, 2); int ny = lua_tointeger(L, 3); int nz = lua_tointeger(L, 4); if (nx > 0 && ny > 0 && (nz == 1 || nz == 3)) { size_t length = nx * ny * nz; /* todo: check this for overflow */ unsigned char *bytemap = NULL; o->existing = 0; bytemap = lmt_memory_malloc(length); if (lua_type(L, 6) == LUA_TSTRING) { size_t l = 0; const char *s = lua_tolstring(L, 6, &l); if (l == length) { memcpy(bytemap, s, length); o->existing = nz; } else { bytemap = NULL; } } if (bytemap) { effectslib_octave_aux_loop(L, o, nx, ny, nz, bytemap, 5); } lua_pushlstring(L, (char *) bytemap, length); lua_pushinteger(L, length); lmt_memory_free(bytemap); return 2; } } return 0; } int effectslib_octave_bytemapped(lua_State * L, unsigned char * bytemap, int nx, int ny, int nz, int slot) { if (bytemap && nx > 0 && ny > 0 && (nz == 1 || nz == 3)) { octave *o = effectslib_octave_aux_valid(L, slot++); if (o) { o->existing = nz; effectslib_octave_aux_loop(L, o, nx, ny, nz, bytemap, slot); return 1; } } return 0; } static int effectslib_octave_getstatus(lua_State *L) { octave *o = effectslib_octave_aux_valid(L, 1); if (o) { lua_createtable(L, 0, 22); lua_set_integer_by_key(L, "iterations", o->iterations); lua_set_number_by_key (L, "amplitude", o->amplitude); lua_set_number_by_key (L, "frequency", o->frequency); lua_set_number_by_key (L, "persistence", o->persistence); lua_set_number_by_key (L, "lacunarity", o->lacunarity); lua_set_number_by_key (L, "angle", o->angle); lua_set_number_by_key (L, "maximum", o->maximum); lua_set_number_by_key (L, "minimum", o->minimum); lua_set_integer_by_key(L, "method", o->method); lua_set_integer_by_key(L, "detail", o->detail); lua_set_integer_by_key(L, "count", o->count); lua_set_integer_by_key(L, "variant", o->variant); lua_set_integer_by_key(L, "existing", o->existing); lua_set_boolean_by_key(L, "zset", o->zset); lua_set_boolean_by_key(L, "wset", o->wset); lua_set_number_by_key (L, "x", o->x); lua_set_number_by_key (L, "y", o->y); lua_set_number_by_key (L, "z", o->z); lua_set_number_by_key (L, "w", o->w); lua_set_number_by_key (L, "dx", o->dx); lua_set_number_by_key (L, "dy", o->dy); lua_set_number_by_key (L, "dz", o->dz); return 1; } else { return 0; } } // static int effectslib_test(lua_State *L) // { // /* // Calculating the sin and cos of an angle takes time. On one of our tests, the // 500x500 TEX logo with 1 iteration 100 pages went from 7 to 6 seconds. This gain // was confirmed by this test and actually a loop in \LUA\ wasn't that much worse. // // int n = lua_tointeger(L, 1); // double d = 0.0; // printf("testing n=%i ...", n); // for (int i = 0; i < n; i++) { // d += sin(i); // } // lua_pushnumber(L, d); // printf(" done\n"); // return 1; // // But of course I might be wrong. However, 100 * 500 * 500 * 2 == 50.000.000 so // a lot indeed. // */ // return 0; // } static int effectslib_octave_tostring(lua_State *L) { octave *o = effectslib_octave_aux_valid(L, 1); if (o) { lua_pushfstring(L, "", o); return 1; } else { return 0; } return 0; } static const luaL_Reg effectslib_octave_metatable[] = { /* { "__index", effectslib_octave_getvalue }, */ /* { "__newindex", effectslib_octave_setvalue }, */ { "__tostring", effectslib_octave_tostring }, { NULL, NULL }, }; static void effectslib_octave_initialize(lua_State *L) { luaL_newmetatable(L, OCTAVE_METATABLE); luaL_setfuncs(L, effectslib_octave_metatable, 0); } /* The library: (todo: namespaces) */ static struct luaL_Reg effectslib_function_list[] = { /* */ { "perlinnoise", effectslib_perlinnoise }, { "simplexnoise", effectslib_simplexnoise }, { "simplexangle", effectslib_simplexangle }, { "simplexdetail", effectslib_simplexdetail }, /* */ { "newoctave", effectslib_octave_new }, { "stepoctave", effectslib_octave_step }, { "octave", effectslib_octave_direct }, { "octavebytemap", effectslib_octave_bytemap }, { "getoctavestatus", effectslib_octave_getstatus }, { "getoctavemethods", effectslib_octave_methods }, { "getoctaveloops", effectslib_octave_loops }, { "getoctavevariants", effectslib_octave_variants }, /* */ // { "test", effectslib_test }, /* */ { NULL, NULL }, }; int luaopen_effects(lua_State *L) { effectslib_octave_initialize(L); lua_newtable(L); luaL_setfuncs(L, effectslib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtdecodelib.c0000644000175000017500000005422115063273560020575 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" /*tex Some png helpers, I could have introduced a userdata for blobs at some point but it's not that useful as strings are also sequences of bytes and lua handles those well. These are interfaces can change any time we like without notice till we like what we have. */ /* t xsize ysize bpp (includes mask) */ static int pnglib_applyfilter(lua_State *L) { size_t size; const char *s = luaL_checklstring(L, 1, &size); int xsize = lmt_tointeger(L, 2); int ysize = lmt_tointeger(L, 3); int slice = lmt_tointeger(L, 4); int len = xsize * slice + 1; /* filter byte */ int n = 0; int m = len - 1; unsigned char *t; if (ysize * len != (int) size) { tex_formatted_warning("png filter", "sizes don't match: %i expected, %i provided", ysize *len, size); return 0; } t = lmt_memory_malloc(size); if (! t) { tex_normal_warning("png filter", "not enough memory"); return 0; } memcpy(t, s, size); for (int i = 0; i < ysize; i++) { switch (t[n]) { case 0 : break; case 1 : for (int j = n + slice + 1; j <= n + m; j++) { t[j] = (unsigned char) (t[j] + t[j-slice]); } break; case 2 : if (i > 0) { for (int j = n + 1; j <= n + m; j++) { t[j] = (unsigned char) (t[j] + t[j-len]); } } break; case 3 : if (i > 0) { for (int j = n + 1; j <= n + slice; j++) { t[j] = (unsigned char) (t[j] + t[j-len]/2); } for (int j = n + slice + 1; j <= n + m; j++) { t[j] = (unsigned char) (t[j] + (t[j-slice] + t[j-len])/2); } } else { for (int j = n + slice + 1; j <= n + m; j++) { t[j] = (unsigned char) (t[j] + t[j-slice]/2); } } break; case 4 : if (i > 0) { for (int j = n + 1; j <= n + slice; j++) { int p = j - len; t[j] = (unsigned char) (t[j] + t[p]); } for (int j = n + slice + 1; j <= n + m; j++) { int p = j - len; unsigned char a = t[j-slice]; unsigned char b = t[p]; unsigned char c = t[p-slice]; int pa = b - c; int pb = a - c; int pc = pa + pb; if (pa < 0) { pa = - pa; } if (pb < 0) { pb = - pb; } if (pc < 0) { pc = - pc; } t[j] = (unsigned char) (t[j] + ((pa <= pb && pa <= pc) ? a : ((pb <= pc) ? b : c))); } } else { /* What to do here? */ /* for (int j = n + slice + 1; j <= n + m; j++) { int p = j - len; unsigned char a = t[j-slice]; unsigned char b = t[p]; unsigned char c = t[p-slice]; int pa = b - c; int pb = a - c; int pc = pa + pb; if (pa < 0) { pa = - pa; } if (pb < 0) { pb = - pb; } if (pc < 0) { pc = - pc; } t[j] = (unsigned char) (t[j] + ((pa <= pb && pa <= pc) ? a : ((pb <= pc) ? b : c))); } */ } break; default: break; } n = n + len; } /* wipe out filter byte */ { int j = 0; /* source */ int m = 0; /* target */ for (int i = 0; i < ysize; i++) { // (void) memcpy(&t[m], &t[j+1], len-1); /* target source size */ (void) memmove(&t[m], &t[j+1], (size_t)len - 1); /* target source size */ j += len; m += len - 1; } lua_pushlstring(L, (char *) t, size-ysize); /* int j = 0; luaL_Buffer b; luaL_buffinit(L, &b); for (int i = 0; i < ysize; i++) { luaL_addlstring(&b, (const char *)&t[j+1], len-1); j += len; } luaL_pushresult(&b); */ } lmt_memory_free(t); return 1; } /* t xsize ysize bpp (includes mask) bytes */ static int pnglib_splitmask(lua_State *L) { size_t size; const char *t = luaL_checklstring(L, 1, &size); int xsize = lmt_tointeger(L, 2); int ysize = lmt_tointeger(L, 3); int bpp = lmt_tointeger(L, 4); /* 1 or 3 */ int bytes = lmt_tointeger(L, 5); /* 1 or 2 */ int slice = (bpp + 1) * bytes; int len = xsize * slice; int blen = bpp * bytes; int mlen = bytes; int nt = 0; int nb = 0; int nm = 0; int bsize = ysize * xsize * blen; int msize = ysize * xsize * mlen; char *b, *m; /* we assume that the filter byte is gone */ if (ysize * len != (int) size) { tex_formatted_warning("png split", "sizes don't match: %i expected, %i provided", ysize * len, size); return 0; } b = lmt_memory_malloc(bsize); m = lmt_memory_malloc(msize); if (! (b && m)) { tex_normal_warning("png split mask", "not enough memory"); return 0; } /* a bit optimized */ switch (blen) { case 1: /* 8 bit gray or indexed graphics */ for (int i = 0; i < ysize * xsize; i++) { b[nb++] = t[nt++]; m[nm++] = t[nt++]; } break; case 3: /* 8 bit rgb graphics */ for (int i = 0; i < ysize * xsize; i++) { /* b[nb++] = t[nt++]; b[nb++] = t[nt++]; b[nb++] = t[nt++]; */ memcpy(&b[nb], &t[nt], 3); nt += 3; nb += 3; m[nm++] = t[nt++]; } break; default: /* everything else */ for (int i = 0; i < ysize * xsize; i++) { memcpy (&b[nb], &t[nt], blen); nt += blen; nb += blen; memcpy (&m[nm], &t[nt], mlen); nt += mlen; nm += mlen; } break; } lua_pushlstring(L, b, bsize); lmt_memory_free(b); lua_pushlstring(L, m, msize); lmt_memory_free(m); return 2; } /* output input xsize ysize slice pass filter */ static int pnglib_interlace(lua_State *L) { int xstarts[] = { 0, 4, 0, 2, 0, 1, 0 }; int ystarts[] = { 0, 0, 4, 0, 2, 0, 1 }; int xsteps[] = { 8, 8, 4, 4, 2, 2, 1 }; int ysteps[] = { 8, 8, 8, 4, 4, 2, 2 }; size_t isize = 0; size_t psize = 0; const char *inp; const char *pre; char *out; int xsize, ysize, xstep, ystep, xstart, ystart, slice, pass, nx, ny; int target, start, step, size; /* dimensions */ xsize = lmt_tointeger(L, 1); ysize = lmt_tointeger(L, 2); slice = lmt_tointeger(L, 3); pass = lmt_tointeger(L, 4); if (pass < 1 || pass > 7) { tex_formatted_warning("png interlace", "bass pass: %i (1..7)", pass); return 0; } pass = pass - 1; /* */ nx = (xsize + xsteps[pass] - xstarts[pass] - 1) / xsteps[pass]; ny = (ysize + ysteps[pass] - ystarts[pass] - 1) / ysteps[pass]; /* */ xstart = xstarts[pass]; xstep = xsteps[pass]; ystart = ystarts[pass]; ystep = ysteps[pass]; /* */ xstep = xstep * slice; xstart = xstart * slice; xsize = xsize * slice; target = ystart * xsize + xstart; ystep = ystep * xsize; /* */ step = nx * xstep; size = ysize * xsize; start = 0; /* */ inp = luaL_checklstring(L, 5, &isize); pre = NULL; out = NULL; if (pass > 0) { pre = luaL_checklstring(L, 6, &psize); if ((int) psize < size) { tex_formatted_warning("png interlace", "output sizes don't match: %i expected, %i provided", psize, size); return 0; } } /* todo: some more checking */ out = lmt_memory_malloc(size); if (out) { if (pass == 0) { memset(out, 0, size); } else { memcpy(out, pre, psize); } } else { tex_normal_warning("png interlace", "not enough memory"); return 0; } switch (slice) { case 1: for (int j = 0; j < ny; j++) { int t = target + j * ystep; for (int i = t; i < t + step; i += xstep) { out[i] = inp[start]; start = start + slice; } } break; case 2: for (int j = 0; j < ny; j++) { int t = target + j * ystep; for (int i = t; i < t + step; i += xstep) { out[i] = inp[start]; out[i+1] = inp[start+1]; start = start + slice; } } break; case 3: for (int j = 0; j < ny; j++) { int t = target + j * ystep; for (int i = t; i < t + step;i += xstep) { out[i] = inp[start]; out[i+1] = inp[start+1]; out[i+2] = inp[start+2]; start = start + slice; } } break; default: for (int j = 0; j < ny; j++) { int t = target + j * ystep; for (int i = t; i < t + step; i += xstep) { memcpy(&out[i], &inp[start], slice); start = start + slice; } } break; } lua_pushlstring(L, out, size); lmt_memory_free(out); return 1; } /* content xsize ysize parts run factor */ # define extract1(a,b) ((a >> b) & 0x01) # define extract2(a,b) ((a >> b) & 0x03) # define extract4(a,b) ((a >> b) & 0x0F) static int pnglib_expand(lua_State *L) { size_t tsize; const char *t = luaL_checklstring(L, 1, &tsize); char *o = NULL; int n = 0; int k = 0; int xsize = lmt_tointeger(L, 2); int ysize = lmt_tointeger(L, 3); int parts = lmt_tointeger(L, 4); int xline = lmt_tointeger(L, 5); int factor = lua_toboolean(L, 6); int size = ysize * xsize; int extra = ysize * xsize + 16; /* probably a few bytes is enough */ if (xline*ysize > (int) tsize) { tex_formatted_warning("png expand","expand sizes don't match: %i expected, %i provided",size,parts*tsize); return 0; } o = lmt_memory_malloc(extra); if (! o) { tex_normal_warning ("png expand", "not enough memory"); return 0; } /* we could use on branch and factor variables ,, saves code, costs cycles */ if (factor) { switch (parts) { case 4: for (int i = 0; i < ysize; i++) { k = i * xsize; for (int j = n; j < n + xline; j++) { unsigned char v = t[j]; o[k++] = (unsigned char) extract4 (v, 4) * 0x11; o[k++] = (unsigned char) extract4 (v, 0) * 0x11; } n = n + xline; } break; case 2: for (int i = 0; i < ysize; i++) { k = i * xsize; for (int j = n; j < n + xline; j++) { unsigned char v = t[j]; for (int b = 6; b >= 0; b -= 2) { o[k++] = (unsigned char) extract2 (v, b) * 0x55; } } n = n + xline; } break; default: for (int i = 0; i < ysize; i++) { k = i * xsize; for (int j = n; j < n + xline; j++) { unsigned char v = t[j]; for (int b = 7; b >= 0; b--) { o[k++] = (unsigned char) extract1 (v, b) * 0xFF; } } n = n + xline; } break; } } else { switch (parts) { case 4: for (int i = 0; i < ysize; i++) { k = i * xsize; for (int j = n; j < n + xline; j++) { unsigned char v = t[j]; o[k++] = (unsigned char) extract4 (v, 4); o[k++] = (unsigned char) extract4 (v, 0); } n = n + xline; } break; case 2: for (int i = 0; i < ysize; i++) { k = i * xsize; for (int j = n; j < n + xline; j++) { unsigned char v = t[j]; for (int b = 6; b >= 0; b -= 2) { o[k++] = (unsigned char) extract2 (v, b); } } n = n + xline; } break; default: for (int i = 0; i < ysize; i++) { k = i * xsize; for (int j = n; j < n + xline; j++) { unsigned char v = t[j]; for (int b = 7; b >= 0; b--) { o[k++] = (unsigned char) extract1 (v, b); } } n = n + xline; } break; } } lua_pushlstring(L, o, size); lmt_memory_free(o); return 1; } /*tex This is just a quick and dirty experiment. We need to satisfy pdf standards and simple graphics can be converted this way. Maybe add some more control over calculating |k|. */ static int pnglib_tocmyk(lua_State *L) { size_t tsize; const char *t = luaL_checklstring(L, 1, &tsize); int depth = lmt_optinteger(L, 2, 0); if ((tsize > 0) && (depth == 8 || depth == 16)) { size_t osize = 0; char *o = NULL; if (depth == 8) { o = lmt_memory_malloc(4 * (tfloor(tsize/3) + 1)); /*tex Plus some slack. */ } else { o = lmt_memory_malloc(8 * (tfloor(tsize/6) + 1)); /*tex Plus some slack. */ } if (! o) { tex_normal_warning ("png tocmyk", "not enough memory"); return 0; } else if (depth == 8) { /* for (size_t i = 0; i < tsize; i += 3) { o[osize++] = (const char) (0xFF - t[i]); o[osize++] = (const char) (0xFF - t[i + 1]); o[osize++] = (const char) (0xFF - t[i + 2]); o[osize++] = '\0'; } */ for (size_t i = 0; i < tsize; ) { o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = '\0'; } } else { /*tex This needs checking! */ /* for (size_t i = 0; i < tsize; i += 6) { o[osize++] = (const char) (0xFF - t[i]); o[osize++] = (const char) (0xFF - t[i + 1]); o[osize++] = (const char) (0xFF - t[i + 2]); o[osize++] = (const char) (0xFF - t[i + 3]); o[osize++] = (const char) (0xFF - t[i + 4]); o[osize++] = (const char) (0xFF - t[i + 5]); o[osize++] = '\0'; o[osize++] = '\0'; } */ for (size_t i = 0; i < tsize; ) { o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = (const char) (0xFF - t[i++]); o[osize++] = '\0'; o[osize++] = '\0'; } } lua_pushlstring(L, o, osize-1); lmt_memory_free(o); } else { lua_pushnil(L); } return 1; } /*tex Make a mask for a pallete. */ static int pnglib_tomask(lua_State *L) /* for palette */ { size_t tsize, ssize; const char *t = luaL_checklstring(L, 1, &tsize); const char *s = luaL_checklstring(L, 2, &ssize); size_t xsize = lmt_tosizet(L, 3); size_t ysize = lmt_tosizet(L, 4); int colordepth = lmt_tointeger(L, 5); size_t osize = xsize * ysize; if (osize == tsize) { char *o = lmt_memory_malloc(osize); char *v = lmt_memory_calloc(256,1); size_t len = xsize * colordepth / 8; // ceil size_t k = 0; memset(v, 0xFF, 256); memcpy(v, s, ssize > 256 ? 256 : ssize); for (size_t i = 0; i < ysize; i++) { size_t f = i * len; size_t l = f + len; switch (colordepth) { case 8: for (size_t j = f; j < l; j++) { int c = t[j]; o[k++] = (unsigned char) v[c]; } break; case 4: for (size_t j = f; j < l; j++) { int c = t[j]; o[k++] = (unsigned char) v[(c >> 4) & 0x0F]; o[k++] = (unsigned char) v[(c >> 0) & 0x0F]; } break; case 2: for (size_t j = f; j < l; j++) { int c = t[j]; o[k++] = (unsigned char) v[(c >> 6) & 0x03]; o[k++] = (unsigned char) v[(c >> 4) & 0x03]; o[k++] = (unsigned char) v[(c >> 2) & 0x03]; o[k++] = (unsigned char) v[(c >> 0) & 0x03]; } break; default: for (size_t j = f; j < l; j++) { int c = t[j]; o[k++] = (unsigned char) v[(c >> 7) & 0x01]; o[k++] = (unsigned char) v[(c >> 6) & 0x01]; o[k++] = (unsigned char) v[(c >> 5) & 0x01]; o[k++] = (unsigned char) v[(c >> 4) & 0x01]; o[k++] = (unsigned char) v[(c >> 3) & 0x01]; o[k++] = (unsigned char) v[(c >> 2) & 0x01]; o[k++] = (unsigned char) v[(c >> 1) & 0x01]; o[k++] = (unsigned char) v[(c >> 0) & 0x01]; } break; } } lua_pushlstring(L, o, osize); lmt_memory_free(o); } else { lua_pushnil(L); } return 1; } static int pnglib_makemask(lua_State *L) /* for palette */ { size_t size; const char *content = luaL_checklstring(L, 1, &size); char mapping[256] = { 0x00 }; char *mask = lmt_memory_malloc(size); switch (lua_type(L, 2)) { case LUA_TNUMBER: { int n = (int) lua_tointeger(L, 2); n = n < 0 ? 0 : n > 255 ? 255 : n; for (int i = 0; i <= n; i++) { mapping[i] = 0xFF; } } break; case LUA_TTABLE: { int n = (int) lua_rawlen(L, 2); for (int i = 1; i <= n; i++) { if (lua_rawgeti(L, 2, i) == LUA_TTABLE) { int m = (int) lua_rawlen(L, -1); if (m == 3) { int b, e, v; lua_rawgeti(L, -1, 1); lua_rawgeti(L, -2, 2); lua_rawgeti(L, -3, 3); b = (int) lua_tointeger(L, -3); e = (int) lua_tointeger(L, -2); v = (int) lua_tointeger(L, -1); b = b < 0 ? 0 : b > 255 ? 255 : b; e = e < 0 ? 0 : e > 255 ? 255 : e; v = v < 0 ? 0 : v > 255 ? 255 : v; for (int i = b; i <= e; i++) { mapping[i] = (char) v; } lua_pop(L, 3); } } lua_pop(L, 1); } } case LUA_TSTRING: { size_t l = 0; const char *m = luaL_checklstring(L, 1, &l); memcpy(mask, m, l > size ? size : l); } break; default: break; } for (int i = 0; i < (int) size; i++) { mask[i] = (unsigned char) mapping[(unsigned char) content[i]]; } lua_pushlstring(L, mask, size); lua_pushlstring(L, mapping, 256); lmt_memory_free(mask); return 2; } static const struct luaL_Reg pngdecodelib_function_list[] = { { "applyfilter", pnglib_applyfilter }, { "splitmask", pnglib_splitmask }, { "interlace", pnglib_interlace }, { "expand", pnglib_expand }, { "tocmyk", pnglib_tocmyk }, { "tomask", pnglib_tomask }, { "makemask", pnglib_makemask }, { NULL, NULL }, }; int luaopen_pngdecode(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, pngdecodelib_function_list, 0); return 1; } /*tex This is a placeholder! */ static const struct luaL_Reg pdfdecodelib_function_list[] = { { NULL, NULL } }; int luaopen_pdfdecode(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, pdfdecodelib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtqrcodegen.c0000644000175000017500000000370115063273560020627 0ustar hillehille/* See license.txt in the root of this project. */ /*tex We use some of qrcodegen: Copyright (c) Project Nayuki. (MIT License) Currently we have a rather minimal interface. */ # include # include /* generate(data) generate(data,yesbyte,nopbyte) generate(data,yesbyte,nopbyte,newlines) */ static int qrcodegenlib_generate(lua_State *L) { const char *text = lua_tostring(L, 1); if (text) { uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; uint8_t buffer[qrcodegen_BUFFER_LEN_MAX]; bool ok = qrcodegen_encodeText( text, buffer, qrcode, qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true ); if (ok) { unsigned yes = lmt_optinteger(L, 2, 0); unsigned nop = lmt_optinteger(L, 3, yes ? 0 : 255); unsigned nln = lua_toboolean(L, 4); int size = qrcodegen_getSize(qrcode); int length = (nln ? size + 1 : size) * size; char *bytemap = lmt_memory_malloc(length); char *p = bytemap; if (yes > 255) { yes = 255; } if (nop > 255) { nop = 255; } for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { *p++ = (unsigned char) qrcodegen_getModule(qrcode, x, y) ? yes : nop; } if (nln) { *p++ = '\n'; } } lua_pushlstring(L, bytemap, length); lua_pushinteger(L, size); lmt_memory_free(bytemap); return 2; } } return 0; } static struct luaL_Reg qrcodegenlib_function_list[] = { { "generate", qrcodegenlib_generate }, { NULL, NULL }, }; int luaopen_qrcodegen(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, qrcodegenlib_function_list, 0); return 1; }luametatex-2.11.08/source/luarest/lmtbytemaplib.h0000644000175000017500000000045615063273560021021 0ustar hillehille/* See license.txt in the root of this project. */ # ifndef LUABYTEMAPLIB_H # define LUABYTEMAPLIB_H extern int bytemaplib_bytemapped( lua_State * L, unsigned char * bytemap, int nx, int ny, int nz, int slot ); # endif luametatex-2.11.08/source/luarest/lmtaeslib.c0000644000175000017500000000653715063273560020131 0ustar hillehille/* See license.txt in the root of this project. */ # include "luametatex.h" # include // AES_HAS_IV AES_INLINE_IV AES_CONTINUE AES_NULL_PADDING static const uint8_t nulliv[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; typedef size_t aes_coder ( const void *input, size_t length, void *output, const void *key, size_t keylength, const void *iv, int flags ); /* data key [block] [inline] [padding] */ /* key : 16 24 32 */ /* random_bytes is taken from pplib */ static int aeslib_aux_code(lua_State *L, aes_coder code) { size_t inputlength = 0; const char *input = lua_tolstring(L, 1, &inputlength); if (inputlength) { size_t keylength = 0; const char *key = lua_tolstring(L, 2, &keylength); if (keylength == 16 || keylength == 24 || keylength == 32) { luaL_Buffer buffer; /* always */ int flags = 0; /* the same length as input plus optional 16 from iv */ char *output = NULL; size_t outputlength = 0; /* this is optional, iv get copied in aes */ const uint8_t *iv = NULL; switch (lua_type(L, 3)) { case LUA_TSTRING: { size_t ivlength = 0; iv = (const uint8_t *) lua_tolstring(L, 3, &ivlength); if (ivlength != 16) { iv = nulliv; } break; } case LUA_TBOOLEAN: if (lua_toboolean(L, 3)) { uint8_t randiv[16]; random_bytes(randiv, 16); iv = (const uint8_t *) randiv; break; } // fall through default: iv = nulliv; } if (lua_toboolean(L, 4)) { flags |= AES_INLINE_IV; } if (! lua_toboolean(L, 5)) { flags |= AES_NULL_PADDING; } /* always multiples of 16 and we might have the iv too */ output = luaL_buffinitsize(L, &buffer, inputlength + 32); outputlength = code(input, inputlength, output, key, keylength, iv, flags); if (outputlength) { luaL_pushresultsize(&buffer, outputlength); return 1; } } else { luaL_error(L, "aeslib: key of length 16, 24 or 32 expected"); } } lua_pushnil(L); return 1; } static int aeslib_encode(lua_State *L) { return aeslib_aux_code(L, &aes_encode_data); } static int aeslib_decode(lua_State *L) { return aeslib_aux_code(L, &aes_decode_data); } static int aeslib_random(lua_State *L) { uint8_t iv[32]; int n = (int) luaL_optinteger(L, 1, 16); if (n > 32) { n = 32; } random_bytes(iv, n); lua_pushlstring(L, (const char *) iv, n); return 1; } static struct luaL_Reg aeslib_function_list[] = { /*tex We started out with this: */ { "encode", aeslib_encode }, { "decode", aeslib_decode }, { "random", aeslib_random }, { NULL, NULL }, }; int luaopen_aes(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, aeslib_function_list, 0); return 1; } luametatex-2.11.08/source/luarest/lmtpotrace.c0000644000175000017500000004676315063273560020334 0ustar hillehille/* See license.txt in the root of this project. */ /*tex We use the library part of potrace: Copyright (C) 2001-2019 Peter Selinger. This file is part of potrace. It is free software and it is covered by the GNU General Public License. See the file COPYING for details. For the following code we used some of: A simple and self-contained demo of the potracelib API. that comes with the file set. We can use a minimal set of files because potrace has been very table for a while! In case one wonders why we need it: one can think of vectorizing logos, old fonts, shapes of any kind that can be used anywhere in \CONTEXT\ and \METAFUN. Just stay tuned. */ # include # include # include # define POTRACE_METATABLE "potracer" #define BM_WORDSIZE ((int)sizeof(potrace_word)) #define BM_WORDBITS (8*BM_WORDSIZE) #define BM_HIBIT (((potrace_word)1)<<(BM_WORDBITS-1)) #define bm_scanline(bm, y) ((bm)->map + (y)*(bm)->dy) #define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS]) #define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1))) #define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a)) #define bm_safe(bm, x, y) (bm_range(x, (bm)->w) && bm_range(y, (bm)->h)) #define BM_USET(bm, x, y) (*bm_index(bm, x, y) |= bm_mask(x)) #define BM_UCLR(bm, x, y) (*bm_index(bm, x, y) &= ~bm_mask(x)) #define BM_UPUT(bm, x, y, b) ((b) ? BM_USET(bm, x, y) : BM_UCLR(bm, x, y)) #define BM_PUT(bm, x, y, b) (bm_safe(bm, x, y) ? BM_UPUT(bm, x, y, b) : 0) /* also internal frees */ static potrace_bitmap_t *new_bitmap(int w, int h) { int dy = (w + BM_WORDBITS - 1) / BM_WORDBITS; potrace_bitmap_t *bitmap = (potrace_bitmap_t *) lmt_memory_malloc(sizeof(potrace_bitmap_t)); if (! bitmap) { return NULL; } bitmap->w = w; bitmap->h = h; bitmap->dy = dy; bitmap->map = (potrace_word *) lmt_memory_calloc(h, dy * BM_WORDSIZE); if (! bitmap->map) { lmt_memory_free(bitmap); return NULL; } else { return bitmap; } } static void free_bitmap(potrace_bitmap_t *bitmap) { if (bitmap) { lmt_memory_free(bitmap->map); } lmt_memory_free(bitmap); } static const char* const policies[] = { "black", "white", "left", "right", "minority", "majority", "random", NULL }; typedef struct potracer { potrace_state_t *state; potrace_param_t *parameters; potrace_bitmap_t *bitmap; const char *bytes; int width; int height; int swap; int nx; int ny; unsigned char value; unsigned char match; /* 7 bytes padding */ } potracer; static potracer *potracelib_aux_maybe_ispotracer(lua_State *L) { return (potracer *) luaL_checkudata(L, 1, POTRACE_METATABLE); } static unsigned char lmt_tochar(lua_State *L, int index) { const char *s = lua_tostring(L, index); return s ? (unsigned char) s[0] : '0'; } static void potracelib_aux_get_parameters(lua_State *L, int index, potracer *p) { if (lua_type(L, index) == LUA_TTABLE) { if (lua_getfield(L, index, "size") == LUA_TNUMBER ) { p->parameters->turdsize = lmt_tointeger(L, -1); } lua_pop(L, 1); if (lua_getfield(L, index, "threshold") == LUA_TNUMBER ) { p->parameters->alphamax = lua_tonumber (L, -1); } lua_pop(L, 1); if (lua_getfield(L, index, "tolerance") == LUA_TNUMBER ) { p->parameters->opttolerance = lua_tonumber (L, -1); } lua_pop(L, 1); if (lua_getfield(L, index, "optimize") == LUA_TBOOLEAN) { p->parameters->opticurve = lua_toboolean(L, -1); } lua_pop(L, 1); if (lua_getfield(L, index, "value") == LUA_TSTRING ) { p->value = lmt_tochar (L, -1); } lua_pop(L, 1); if (lua_getfield(L, index, "negate") == LUA_TBOOLEAN) { p->match = ! lua_toboolean(L, -1); } lua_pop(L, 1); if (lua_getfield(L, index, "policy") == LUA_TSTRING ) { p->parameters->turnpolicy = luaL_checkoption(L, -1, "minority", policies); } lua_pop(L, 1); } } static void potracelib_get_bitmap(potracer *p, unsigned char match) { /* Kind of suboptimal but it might change anyway so let the compiler worry about it. */ const char *bytes = p->bytes; if (bytes) { unsigned char c = p->value; if (p->swap) { if (p->nx != 1 || p->ny != 1) { /* maybe a 3x3 fast one */ for (int x = 0; x < p->width; x += p->nx) { int bp = (p->height/p->ny) * (x/p->nx); /* yet unchecked */ for (int y = 0; y < p->height; y += p->ny) { unsigned char b = (unsigned char) bytes[bp++] == c ? 1 : 0; if (b) { int dy = p->height - y - 1; for (int xn = 0; xn < p->nx; xn++) { for (int yn = 0; yn < p->ny; yn++) { BM_PUT(p->bitmap, x + xn, dy - yn, b); } } } } } } else { /* fast one */ for (int x = 0; x < p->width; x++) { int bp = p->height * x; int dy = p->height - 1; for (int y = 0; y < p->height; y++) { unsigned char b = (unsigned char) bytes[bp++] == c ? 1 : 0; if (b) { BM_PUT(p->bitmap, x, dy - y, b); } } } } } else { if (p->nx != 1 || p->ny != 1) { /* maybe a 3x3 fast one and also when one of them is 1 */ for (int y = 0; y < p->height; y += p->ny) { int bp = (p->width/p->nx) * (y/p->ny); for (int x = 0; x < p->width; x += p->nx) { unsigned char b = (unsigned char) bytes[bp++] == c ? 1 : 0; if (b) { int dy = p->height - y - 1; for (int xn = 0; xn < p->nx; xn++) { for (int yn = 0; yn < p->ny; yn++) { BM_PUT(p->bitmap, x + xn, dy - yn, b); } } } } } } else { /* fast one */ for (int y = 0; y < p->height; y++) { int bp = p->width * y; int dy = p->height - y - 1; for (int x = 0; x < p->width; x++) { unsigned char b = ((unsigned char) bytes[bp++] == c ? 1 : 0) == match; if (b) { BM_PUT(p->bitmap, x, dy, b); } } } } } } } # define max_explode 4 static int potracelib_getnewfields(lua_State *L) { lua_createtable(L, 0, 8); lua_set_string_by_key(L, "bytes", "string"); lua_set_string_by_key(L, "width", "integer"); lua_set_string_by_key(L, "height", "integer"); lua_set_string_by_key(L, "nx", "integer"); lua_set_string_by_key(L, "ny", "integer"); lua_set_string_by_key(L, "swap", "boolean"); lua_set_string_by_key(L, "value", "character"); lua_set_string_by_key(L, "negate", "boolean"); return 1; } static int potracelib_getprocessfields(lua_State *L) { lua_createtable(L, 0, 8); lua_set_string_by_key(L, "size", "integer"); lua_set_string_by_key(L, "threshold", "number"); lua_set_string_by_key(L, "tolerance", "number"); lua_set_string_by_key(L, "optimize", "boolean"); lua_set_string_by_key(L, "value", "characetr"); lua_set_string_by_key(L, "negate", "boolean"); lua_set_string_by_key(L, "policy", "string"); return 1; } static int potracelib_getpolicyvalues(lua_State *L) { lua_createtable(L, 7, 0); lua_set_string_by_index(L, 1, "black"); lua_set_string_by_index(L, 2, "white"); lua_set_string_by_index(L, 3, "left"); lua_set_string_by_index(L, 4, "right"); lua_set_string_by_index(L, 5, "minority"); lua_set_string_by_index(L, 6, "majority"); lua_set_string_by_index(L, 7, "random"); return 1; } static int potracelib_new(lua_State *L) { if (lua_type(L, 1) == LUA_TTABLE) { potracer p = { .state = NULL, .parameters = NULL, .bitmap = NULL, .bytes = NULL, .height = 0, .width = 0, .swap = 0, .nx = 1, .ny = 1, .value = '1', .match = 1, }; size_t length = 0; if (lua_getfield(L, 1, "bytes") == LUA_TSTRING) { p.bytes = lua_tolstring(L, -1, &length); } lua_pop(L, 1); if (lua_getfield(L, 1, "width") == LUA_TNUMBER) { p.width = lmt_tointeger(L, -1); } lua_pop(L, 1); if (lua_getfield(L, 1, "height") == LUA_TNUMBER) { p.height = lmt_tointeger(L, -1); } lua_pop(L, 1); if (lua_getfield(L, 1, "nx") == LUA_TNUMBER) { p.nx = lmt_tointeger(L, -1); } lua_pop(L, 1); if (lua_getfield(L, 1, "ny") == LUA_TNUMBER) { p.ny = lmt_tointeger(L, -1); } lua_pop(L, 1); if (lua_getfield(L, 1, "swap") == LUA_TBOOLEAN) { p.swap = lua_toboolean(L, -1); } lua_pop(L, 1); if (lua_getfield(L, 1, "value") == LUA_TSTRING) { p.value = lmt_tochar (L, -1); } lua_pop(L, 1); if (lua_getfield(L, 1, "negate") == LUA_TBOOLEAN) { p.match = ! lua_toboolean(L, -1); } lua_pop(L, 1); if (! p.bytes) { return 0; } if ((size_t) (p.width * p.height) > length) { return 0; } p.nx = p.nx < 1 ? 1 : (p.nx > max_explode ? max_explode : p.nx); p.ny = p.ny < 1 ? 1 : (p.ny > max_explode ? max_explode : p.ny); p.width *= p.nx; p.height *= p.ny; if (p.swap) { int tmp = p.width; p.width = p.height; p.height = tmp; tmp = p.nx; p.nx = p.ny; p.ny = tmp; } p.parameters = potrace_param_default(); if (! p.parameters) { free_bitmap(p.bitmap); return 0; } potracelib_aux_get_parameters(L, 1, &p); lua_pop(L, 1); { potracer *pp = (potracer *) lua_newuserdatauv(L, sizeof(potracer), 0); if (pp) { *pp = p; luaL_getmetatable(L, POTRACE_METATABLE); lua_setmetatable(L, -2); return 1; } } } return 0; } static void potracelib_aux_free(potracer *p) { if (p) { if (p->state) { potrace_state_free(p->state); p->state = NULL; } if (p->parameters) { potrace_param_free(p->parameters); p->parameters = NULL; } if (p->bitmap) { free_bitmap(p->bitmap); p->bitmap = NULL; } } } static int potracelib_free(lua_State *L) { potracelib_aux_free(potracelib_aux_maybe_ispotracer(L)); return 0; } static int aux_potracelib_entries(potracer *p) { potrace_path_t *entry = p->state->plist; int entries = 0; while (entry) { entries++; entry = entry->next; } return entries; } /* maybe also - last*/ static potrace_path_t *aux_potrace_goto_first(potracer *p, int nofentries, int *first, int *last, int *used) { potrace_path_t *entry = p->state->plist; if (*first && ! *last) { *last = nofentries; } if (*last < 0) { *last = nofentries - *last; if (*last < 0) { *last = 1; } } if (*first <= 0) { *first = 1; } if ((! *last) || (*last > nofentries)) { *last = nofentries; } if (*first > *last) { *first = *last; } for (int i = 1; i < *first; i++) { entry = entry->next; } *used = *last - *first + 1; return entry; } static int potracelib_totable_normal(lua_State *L, potracer *p, int first, int last) { int entries = 0; int nofentries = aux_potracelib_entries(p); int used = nofentries; potrace_path_t *entry = aux_potrace_goto_first(p, nofentries, &first, &last, &used); lua_createtable(L, used, 0); while (entry) { int segments = 0; int n = entry->curve.n; int m = n + 1; int *tag = entry->curve.tag; // int sign = (entry->next == NULL || entry->next->sign == '+') ? 1 : 0; int sign = (entry->sign == '+') ? 1 : 0; potrace_dpoint_t (*c)[3] =entry->curve.c; lua_createtable(L, m, sign ? 2 : 1); if (sign) { lua_push_boolean_at_key(L, sign, 1); } lua_push_integer_at_key(L, index, first + entries); /* for tracing when we select */ lua_createtable(L, 2, 0); lua_push_number_at_index(L, 1, c[n-1][2].x); lua_push_number_at_index(L, 2, c[n-1][2].y); lua_rawseti(L, -2, ++segments); for (int i = 0; i < n; i++) { switch (tag[i]) { case POTRACE_CORNER: lua_createtable(L, 2, 0); lua_push_number_at_index(L, 1, c[i][1].x); lua_push_number_at_index(L, 2, c[i][1].y); lua_rawseti(L, -2, ++segments); lua_createtable(L, 2, 0); lua_push_number_at_index(L, 1, c[i][2].x); lua_push_number_at_index(L, 2, c[i][2].y); lua_rawseti(L, -2, ++segments); break; case POTRACE_CURVETO: lua_createtable(L, 6, 0); lua_push_number_at_index(L, 1, c[i][2].x); lua_push_number_at_index(L, 2, c[i][2].y); lua_push_number_at_index(L, 3, c[i][0].x); lua_push_number_at_index(L, 4, c[i][0].y); lua_push_number_at_index(L, 5, c[i][1].x); lua_push_number_at_index(L, 6, c[i][1].y); lua_rawseti(L, -2, ++segments); break; } } lua_rawseti(L, -2, ++entries); if (first + entries > last) { break; } else { entry = entry->next; } } return 1; } /*tex These intermediate state tables are based on the debugger in |backend_eps.c|. There is no need to speed them up. */ static int potracelib_totable_debug(lua_State *L, potracer *p, int first, int last) { int entries = 0; int nofentries = aux_potracelib_entries(p); int used = nofentries; potrace_path_t *entry = aux_potrace_goto_first(p, nofentries, &first, &last, &used); lua_createtable(L, used, 0); while (entry) { point_t *pt = entry->priv->pt; int segments = 0; // int sign = (entry->next == NULL || entry->next->sign == '+') ? 1 : 0; int sign = (entry->sign == '+') ? 1 : 0; lua_newtable(L); if (sign) { lua_push_boolean_at_key(L, sign, 1); } lua_push_integer_at_key(L, index, first + entries); /* for tracing when we select */ /*tex We can get a redundant point 0 when we go left and come back right on the same line, but we can simplify that at the receiving end. */ if (sign) { point_t cur = pt[entry->priv->len - 1]; point_t prev = cur; lua_push_integer_at_index(L, ++segments, cur.x); lua_push_integer_at_index(L, ++segments, cur.y); for (int i = 0; i < entry->priv->len; i++) { if (pt[i].x != cur.x && pt[i].y != cur.y) { cur = prev; lua_push_integer_at_index(L, ++segments, cur.x); lua_push_integer_at_index(L, ++segments, cur.y); } prev = pt[i]; } lua_push_integer_at_index(L, ++segments, pt[entry->priv->len-1].x); lua_push_integer_at_index(L, ++segments, pt[entry->priv->len-1].y); } else { point_t cur = pt[0]; point_t prev = cur; lua_push_integer_at_index(L, ++segments, cur.x); lua_push_integer_at_index(L, ++segments, cur.y); for (int i = entry->priv->len - 1; i >= 0; i--) { if (pt[i].x != cur.x && pt[i].y != cur.y) { cur = prev; lua_push_integer_at_index(L, ++segments, cur.x); lua_push_integer_at_index(L, ++segments, cur.y); } prev = pt[i]; } lua_push_integer_at_index(L, ++segments, pt[0].x); lua_push_integer_at_index(L, ++segments, pt[0].y); } lua_rawseti(L, -2, ++entries); if (first + entries > last) { break; } else { entry = entry->next; } } return 1; } static int potracelib_totable(lua_State *L) { int debug = lua_toboolean(L, 2); int first = lmt_optinteger(L, 3, 0); int last = lmt_optinteger(L, 4, first); lua_settop(L, 1); { potracer *p = potracelib_aux_maybe_ispotracer(L); if (p) { return debug ? potracelib_totable_debug(L, p, first, last) : potracelib_totable_normal(L, p, first, last); } else { return 0; } } } static int potracelib_process(lua_State *L) { potracer *p = potracelib_aux_maybe_ispotracer(L); if (p) { potracelib_aux_get_parameters(L, 2, p); if (p->bitmap) { free_bitmap(p->bitmap); } p->bitmap = new_bitmap(p->width, p->height); if (p->bitmap) { potracelib_get_bitmap(p, p->match); p->state = potrace_trace(p->parameters, p->bitmap); if (p->state && p->state->status == POTRACE_STATUS_OK) { lua_pushboolean(L, 1); return 1; } } } lua_pushboolean(L, 0); return 1; } static int potracelib_tostring(lua_State * L) { potracer *p = potracelib_aux_maybe_ispotracer(L); if (p) { (void) lua_pushfstring(L, "", p); } else { lua_pushnil(L); } return 1; } /*tex We keep the interface simple because we glue via \LUA\ and have to connect to \METAPOST\ too. */ static const struct luaL_Reg potracelib_instance_metatable[] = { { "__tostring", potracelib_tostring }, { "__gc", potracelib_free }, { NULL, NULL }, }; static const luaL_Reg potracelib_function_list[] = { { "new", potracelib_new }, { "free", potracelib_free }, { "process", potracelib_process }, { "totable", potracelib_totable }, { "getnewfields", potracelib_getnewfields }, { "getprocessfields", potracelib_getprocessfields }, { "getpolicyvalues", potracelib_getpolicyvalues }, { NULL, NULL }, }; int luaopen_potrace(lua_State *L) { luaL_newmetatable(L, POTRACE_METATABLE); luaL_setfuncs(L, potracelib_instance_metatable, 0); lua_newtable(L); luaL_setfuncs(L, potracelib_function_list, 0); return 1; }luametatex-2.11.08/source/luarest/lmtmd5lib.c0000644000175000017500000000445715063273560020045 0ustar hillehille/* See license.txt in the root of this project. */ # include # include # include # include # include "luametatex.h" /* # define wrapped_md5(message,len,output) md5_digest(message,len,(unsigned char *) output, 0) static int md5lib_sum(lua_State *L) { char buf[16]; size_t l; const char *message = luaL_checklstring(L, 1, &l); wrapped_md5(message, l, buf); lua_pushlstring(L, buf, 16L); return 1; } static int md5lib_hex(lua_State *L) { char buf[16]; char hex[32]; iof *inp = iof_filter_string_reader(buf, 16); iof *out = iof_filter_string_writer(hex, 32); size_t l; const char *message = luaL_checklstring(L, 1, &l); wrapped_md5(message, l, buf); base16_encode_lc(inp, out); lua_pushlstring(L, hex, iof_size(out)); iof_free(inp); iof_free(out); return 1; } static int md5lib_HEX(lua_State *L) { char buf[16]; char hex[32]; iof *inp = iof_filter_string_reader(buf, 16); iof *out = iof_filter_string_writer(hex, 32); size_t l; const char *message = luaL_checklstring(L, 1, &l); wrapped_md5(message, l, buf); base16_encode_uc(inp, out); lua_pushlstring(L, hex, iof_size(out)); iof_free(inp); iof_free(out); return 1; } */ # define MD5_RESULT_LENGTH (MD5_STRING_LENGTH-1) # define md5_body(MD5_LENGTH, CONVERSION, RESULT_LENGTH) do { \ if (lua_type(L, 1) == LUA_TSTRING) { \ uint8_t result[MD5_LENGTH]; \ size_t size = 0; \ const char *data = lua_tolstring(L, 1, &size); \ md5_digest(data, size, (unsigned char *) result, CONVERSION); \ lua_pushlstring(L, (const char *) result, RESULT_LENGTH); \ return 1; \ } \ return 0; \ } while (0) static int md5lib_sum(lua_State *L) { md5_body(MD5_DIGEST_LENGTH, MD5_BYTES, MD5_DIGEST_LENGTH); } static int md5lib_hex(lua_State *L) { md5_body(MD5_STRING_LENGTH, MD5_LCHEX, MD5_RESULT_LENGTH); } static int md5lib_HEX(lua_State *L) { md5_body(MD5_STRING_LENGTH, MD5_UCHEX, MD5_RESULT_LENGTH); } static struct luaL_Reg md5lib_function_list[] = { { "sum", md5lib_sum }, { "hex", md5lib_hex }, { "HEX", md5lib_HEX }, { NULL, NULL }, }; int luaopen_md5(lua_State *L) { lua_newtable(L); luaL_setfuncs(L, md5lib_function_list, 0); return 1; } luametatex-2.11.08/source/libraries/0000775000175000017500000000000015077444116016277 5ustar hillehilleluametatex-2.11.08/source/libraries/triangles/0000775000175000017500000000000015077444116020267 5ustar hillehilleluametatex-2.11.08/source/libraries/triangles/triangles.c0000644000175000017500000011707315063273560022430 0ustar hillehille/* Triangle/triangle intersection test routine, by Tomas Moller, 1997. See article "A Fast Triangle-Triangle Intersection Test", Journal of Graphics Tools, 2(2), 1997 */ /* Copyright 2020 Tomas Akenine-Moller 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. */ /*tex When we were playing with vectors, matrices and mesh rendering in \METAPOST\ we ran into the code below. We use this code to improve the contour graphic generation where triangles in meshes can overlap. The code has been reformatted (so that we can better understand it) and adapted to interfacing with the vector code that we have. The code has been adapted to doubles instead of floats and also to get rid of some compiler warnings. Because we didn't get the expected results, we reshuffled some bits and pieces in order to make tracing a bit easier. We use the updated 2001-06-20 version and default to the variant without division. We also use a more granular response. triangles_intersection_states triangles_intersect ( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2 ) triangles_intersection_states triangles_intersect_with_line ( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, triangles_three isectpt1, // endpoint 1 triangles_three isectpt2 // endpoint 2 ); We shuffled the variables a bit so that we can see more clearly which ones are temporary. Of course we can use more inline functions. If there are errors, just blame: Mikael Sundqvist (same department as the author - Lund SV) Hans Hagen */ # include # include # include /* A nice coincidence is that we also use this value in the vector library. Maybe using that iszero test is faster as we don't need to fabs. We have to use a much higher epsilon in the caller because otherwise we get too many false positives here. (HH) */ // # if 0 // // # define EPSILON 0.000001 // # define ISZERO(d) (d > -EPSILON && d < EPSILON) // # define USEZERO(d) (d > -EPSILON && d < EPSILON) // // # else // // # define EPSILON 0.000001 // // # define EPSILON 1.0e-16 // # define ISZERO(d) (d == 0.0) // # define USEZERO(d) (fabs(d) < EPSILON) // // # endif /*tex We started out with the Swedish EPSILON being \im {0.000001{$} but then the French one was \im {1.0e-16} which made us, also observing random false positives (which also relates to the numbers involved), decide to make it a parameter. */ # if 0 # define ISZERO(d) (d > -epsilon && d < epsilon) # define USEZERO(d) (d > -epsilon && d < epsilon) # else # define ISZERO(d) (d == 0.0) # define USEZERO(d) (fabs(d) < epsilon) # endif /* Here macros are faster than inline functions so we keep them. (HH) */ # define CROSS(dest,v1,v2) \ dest[0] = v1[1] * v2[2] - v1[2] * v2[1]; \ dest[1] = v1[2] * v2[0] - v1[0] * v2[2]; \ dest[2] = v1[0] * v2[1] - v1[1] * v2[0]; # define DOT(v1,v2) \ ( v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] ) # define SUB(dest,v1,v2) \ dest[0] = v1[0] - v2[0]; \ dest[1] = v1[1] - v2[1]; \ dest[2] = v1[2] - v2[2]; # define ADD(dest,v1,v2) \ dest[0] = v1[0] + v2[0]; \ dest[1] = v1[1] + v2[1]; \ dest[2] = v1[2] + v2[2]; # define MULT(dest,v,factor) \ dest[0] = factor * v[0]; \ dest[1] = factor * v[1]; \ dest[2] = factor * v[2]; # define SET(dest,src) \ dest[0] = src[0]; \ dest[1] = src[1]; \ dest[2] = src[2]; /* sort so that a <= b */ # define SORT(a,b) \ if (a > b) { \ double c = a; \ a = b; \ b = c; \ } # define SORT2(a,b,smallest) \ smallest = a > b; \ if (smallest) { \ double c = a; \ a = b; \ b = c; \ } /* This edge to edge test is based on Franlin Antonio's gem: "Faster Line Segment Intersection", in Graphics Gems III, pp. 199-202 */ # define EDGE_EDGE_TEST(V0,U0,U1) \ Bx = U0[i0] - U1[i0]; \ By = U0[i1] - U1[i1]; \ Cx = V0[i0] - U0[i0]; \ Cy = V0[i1] - U0[i1]; \ f = Ay * Bx - Ax * By; \ d = By * Cx - Bx * Cy; \ if ((f > 0.0 && d >= 0.0 && d <= f) || (f < 0.0 && d <= 0.0 && d >= f)) { \ e = Ax * Cy - Ay * Cx; \ if (f > 0.0) { \ if (e >= 0.0 && e <= f) { \ return 1; \ } \ } else { \ if (e <= 0.0 && e >= f) { \ return 1; \ } \ } \ } # define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2,i0,i1) \ { \ double Bx, By, Cx, Cy, e, d, f; \ double Ax = V1[i0] - V0[i0];\ double Ay = V1[i1] - V0[i1]; \ /* test edge U0,U1 against V0,V1 */ \ EDGE_EDGE_TEST(V0,U0,U1); \ /* test edge U1,U2 against V0,V1 */ \ EDGE_EDGE_TEST(V0,U1,U2); \ /* test edge U2,U0 against V0,V1 */ \ EDGE_EDGE_TEST(V0,U2,U0); \ } # define POINT_IN_TRI(V0,U0,U1,U2,i0,i1) \ { \ double a, b, c, d0, d1, d2; \ /* is T1 completely inside T2? check if V0 is inside tri(U0,U1,U2) */ \ a = U1[i1] - U0[i1]; \ b = - (U1[i0] - U0[i0]); \ c = - a * U0[i0] - b * U0[i1]; \ d0 = a * V0[i0] + b * V0[i1] + c; \ /* */ \ a = U2[i1] - U1[i1]; \ b = - (U2[i0] - U1[i0]); \ c = - a * U1[i0] - b * U1[i1]; \ d1 = a * V0[i0] + b * V0[i1] + c; \ /* */ \ a = U0[i1] - U2[i1]; \ b = - (U0[i0] - U2[i0]); \ c = - a * U2[i0] - b * U2[i1]; \ d2 = a * V0[i0] + b * V0[i1] + c; \ /* */ \ if ((d0 * d1 > 0.0) && (d0 * d2 > 0.0)) { \ return 1; \ } \ } static inline int triangles_are_coplanar( triangles_three N, triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2 ) { triangles_three A; int i0, i1; /* first project onto an axis-aligned plane, that maximizes the area */ /* of the triangles, compute indices i0 and i1 */ A[0] = fabs(N[0]); A[1] = fabs(N[1]); A[2] = fabs(N[2]); if (A[0] > A[1]) { if (A[0] > A[2]) { i0 = 1; i1 = 2; } else { i0 = 0; i1 = 1; } } else { if (A[2] > A[1]) { i0 = 0; i1 = 1; } else { i0 = 0; i1 = 2; } } /* test all edges of triangle 1 against the edges of triangle 2 */ EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2,i0,i1); EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2,i0,i1); EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2,i0,i1); /* finally, test if tri1 is totally contained in tri2 or vice versa */ POINT_IN_TRI(V0,U0,U1,U2,i0,i1); POINT_IN_TRI(U0,V0,V1,V2,i0,i1); return 0; } /* D1D2 added for cleaner code ... there is no gain in avoiding it */ # define INTERVALS_2(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ { \ A = VV[2]; B = (VV[0] - VV[2]) * DD[2]; C = (VV[1] - VV[2]) * DD[2]; X0 = DD[2] - DD[0]; X1 = DD[2] - DD[1]; \ } # define INTERVALS_1(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ { \ A = VV[1]; B = (VV[0] - VV[1]) * DD[1]; C = (VV[2] - VV[1]) * DD[1]; X0 = DD[1] - DD[0]; X1 = DD[1] - DD[2]; \ } # define INTERVALS_0(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ { \ A = VV[0]; B = (VV[1] - VV[0]) * DD[0]; C = (VV[2] - VV[0]) * DD[0]; X0 = DD[0] - DD[1]; X1 = DD[0] - DD[2]; \ } # define COMPUTE_INTERVALS(VV,DD,D0D1,D0D2,D1D2,A,B,C,X0,X1,V0,V1,V2,U0,U1,U2) \ { \ if (D0D1 > 0.0) { \ INTERVALS_2(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ } else if (D0D2 > 0.0) { \ INTERVALS_1(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ } else if (D1D2 > 0.0) { \ INTERVALS_0(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ } else if (! ISZERO(DD[0])) { \ INTERVALS_0(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ } else if (! ISZERO(DD[1])) { \ INTERVALS_1(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ } else if (! ISZERO(DD[2])) { \ INTERVALS_2(VV,DD,D0D1,D0D2,A,B,C,X0,X1) \ } else if (triangles_are_coplanar(N1, V0, V1, V2, U0, U1, U2)) {\ return triangles_intersection_yes_coplanar; \ } else { \ return triangles_intersection_nop_coplanar; \ } \ } int triangles_intersect( /* We use the no_div variant! */ triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, double epsilon ) { triangles_three N1, N2; triangles_three dv, du; triangles_two isect1, isect2; double du0du1, du0du2, du1du2, dv0dv1, dv0dv2, dv1dv2; int index; /* compute plane equation of triangle(V0,V1,V2) */ { double d1; triangles_three E1, E2; SUB(E1,V1,V0); SUB(E2,V2,V0); CROSS(N1,E1,E2); d1 = -DOT(N1,V0); /* plane equation 1: N1.X + d1 = 0 */ /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/ du[0] = DOT(N1,U0) + d1; du[1] = DOT(N1,U1) + d1; du[2] = DOT(N1,U2) + d1; if (USEZERO(du[0])) du[0] = 0.0; if (USEZERO(du[1])) du[1] = 0.0; if (USEZERO(du[2])) du[2] = 0.0; du0du1 = du[0] * du[1]; du0du2 = du[0] * du[2]; du1du2 = du[1] * du[2]; /* if same sign on all of them + not equal 0 then no intersection occurs */ if (du0du1 > 0.0 && du0du2 > 0.0) { return triangles_intersection_nop_plane_one; } } /* compute plane of triangle (U0,U1,U2) */ { double d2; triangles_three E1, E2; SUB(E1,U1,U0); SUB(E2,U2,U0); CROSS(N2,E1,E2); d2 = -DOT(N2,U0); /* plane equation 2: N2.X + d2 = 0 */ /* put V0, V1, V2 into plane equation 2 */ dv[0] = DOT(N2,V0) + d2; dv[1] = DOT(N2,V1) + d2; dv[2] = DOT(N2,V2) + d2; if (USEZERO(dv[0])) dv[0] = 0.0; if (USEZERO(dv[1])) dv[1] = 0.0; if (USEZERO(dv[2])) dv[2] = 0.0; dv0dv1 = dv[0] * dv[1]; dv0dv2 = dv[0] * dv[2]; dv1dv2 = dv[1] * dv[2]; /* if same sign on all of them + not equal 0 then no intersection occurs */ if (dv0dv1 > 0.0 && dv0dv2 > 0.0) { return triangles_intersection_nop_plane_two; } } { /* compute direction of intersection line and index to the largest component of D */ triangles_three D; CROSS(D,N1,N2); D[0] = fabs(D[0]); D[1] = fabs(D[1]); D[2] = fabs(D[2]); if (D[2] > D[0]) { index = D[2] > D[0] ? 2 : 1; } else { index = D[2] > D[0] ? 2 : 0; } } /* this is the simplified projection onto L */ { double a, b, c, x0, x1; double d, e, f, y0, y1; /* compute interval for triangle 1 */ { triangles_three vp; vp[0] = V0[index]; vp[1] = V1[index]; vp[2] = V2[index]; COMPUTE_INTERVALS(vp,dv,dv0dv1,dv0dv2,dv1dv2,a,b,c,x0,x1,V0,V1,V2,U0,U1,U2); } /* compute interval for triangle 2 */ { triangles_three up; up[0] = U0[index]; up[1] = U1[index]; up[2] = U2[index]; COMPUTE_INTERVALS(up,du,du0du1,du0du2,du1du2,d,e,f,y0,y1,V0,V1,V2,U0,U1,U2); } /* we fall through */ { double xx = x0 * x1; double yy = y0 * y1; double xxyy = xx * yy; { double tmp = a * xxyy; isect1[0] = tmp + b * x1 * yy; isect1[1] = tmp + c * x0 * yy; } { double tmp = d * xxyy; isect2[0] = tmp + e * xx * y1; isect2[1] = tmp + f * xx * y0; } } } SORT(isect1[0],isect1[1]); SORT(isect2[0],isect2[1]); return (isect1[1] < isect2[0] || isect2[1] < isect1[0]) ? triangles_intersection_nop_final : triangles_intersection_yes_final; } static inline void check_isect( triangles_three VTX0, triangles_three VTX1, triangles_three VTX2, double VV0, double VV1, double VV2, double D0, double D1, double D2, double *isect0, double *isect1, triangles_three isectpoint0, triangles_three isectpoint1 ) { double tmp = D0 / (D0 - D1); triangles_three diff; *isect0 = VV0 + (VV1 - VV0) * tmp; SUB(diff,VTX1,VTX0); MULT(diff,diff,tmp); ADD(isectpoint0,diff,VTX0); tmp = D0 / (D0 - D2); *isect1 = VV0 + (VV2 - VV0) * tmp; SUB(diff,VTX2,VTX0); MULT(diff,diff,tmp); ADD(isectpoint1,VTX0,diff); } static inline int compute_intervals_coplanar( triangles_three VERT0, triangles_three VERT1, triangles_three VERT2, triangles_three VV, triangles_three D, double D0D1, double D0D2, double D1D2, double *isect0, double *isect1, triangles_three isectpoint0, triangles_three isectpoint1 ) { if (D0D1 > 0.0) { check_isect(VERT2, VERT0, VERT1, VV[2], VV[0], VV[1], D[2], D[0], D[1], isect0, isect1, isectpoint0, isectpoint1); } else if (D0D2 > 0.0) { check_isect(VERT1, VERT0, VERT2, VV[1], VV[0], VV[2], D[1], D[0], D[2], isect0, isect1, isectpoint0, isectpoint1); } else if (D1D2 > 0.0) { check_isect(VERT0, VERT1, VERT2, VV[0], VV[1], VV[2], D[0], D[1], D[2], isect0, isect1, isectpoint0, isectpoint1); } else if (! ISZERO(D[0])) { check_isect(VERT0, VERT1, VERT2, VV[0], VV[1], VV[2], D[0], D[1], D[2], isect0, isect1, isectpoint0, isectpoint1); } else if (! ISZERO(D[1])) { check_isect(VERT1, VERT0, VERT2, VV[1], VV[0], VV[2], D[1], D[0], D[2], isect0, isect1, isectpoint0, isectpoint1); } else if (! ISZERO(D[2])) { check_isect(VERT2, VERT0, VERT1, VV[2], VV[0], VV[1], D[2], D[0], D[1], isect0, isect1, isectpoint0, isectpoint1); } else { return 1; /* triangles are coplanar */ } return 0; } /* If we use this as follow up it can best be more the same a the above one. The coplanar return value is kind of weird because it can be true while there is also this check, so one should check */ int triangles_intersect_with_line( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, triangles_three isectpt1, triangles_three isectpt2, double epsilon ) { triangles_three N1, N2; triangles_three du, dv; triangles_two isect1 = { 0.0, 0.0 }; /* compiler initialization warning when unset */ triangles_two isect2 = { 0.0, 0.0 }; triangles_three isectpointA1 = { 0.0, 0.0, 0.0 }; /* compiler initialization warning when unset */ triangles_three isectpointA2 = { 0.0, 0.0, 0.0 }; triangles_three isectpointB1 = { 0.0, 0.0, 0.0 }; triangles_three isectpointB2 = { 0.0, 0.0, 0.0 }; double du0du1, du0du2, du1du2, dv0dv1, dv0dv2, dv1dv2; int index; /* compute plane equation of triangle(V0,V1,V2) */ { double d1; triangles_three E1, E2; SUB(E1,V1,V0); SUB(E2,V2,V0); CROSS(N1,E1,E2); d1 = -DOT(N1,V0); /* plane equation 1: N1.X + d1 = 0 */ /* put U0, U1, U2 into plane equation 1 to compute signed distances to the plane */ du[0] = DOT(N1,U0) + d1; du[1] = DOT(N1,U1) + d1; du[2] = DOT(N1,U2) + d1; /* coplanarity robustness check */ if (USEZERO(du[0])) du[0] = 0.0; if (USEZERO(du[1])) du[1] = 0.0; if (USEZERO(du[2])) du[2] = 0.0; du0du1 = du[0] * du[1]; du0du2 = du[0] * du[2]; du1du2 = du[1] * du[2]; /* same sign on all of them + not equal 0 then no intersection occurs */ if (du0du1 > 0.0 && du0du2 > 0.0) { return triangles_intersection_nop_plane_one; } } /* compute plane of triangle (U0,U1,U2) */ { double d2; triangles_three E1, E2; SUB(E1,U1,U0); SUB(E2,U2,U0); CROSS(N2,E1,E2); d2 = -DOT(N2,U0); /* plane equation 2: N2.X + d2 = 0 */ /* put V0, V1, V2 into plane equation 2 */ dv[0] = DOT(N2,V0) + d2; dv[1] = DOT(N2,V1) + d2; dv[2] = DOT(N2,V2) + d2; if (USEZERO(dv[0])) dv[0] = 0.0; if (USEZERO(dv[1])) dv[1] = 0.0; if (USEZERO(dv[2])) dv[2] = 0.0; dv0dv1 = dv[0] * dv[1]; dv0dv2 = dv[0] * dv[2]; dv1dv2 = dv[1] * dv[2]; /* same sign on all of them + not equal 0 then no intersection occurs */ if (dv0dv1 > 0.0 && dv0dv2 > 0.0) { return triangles_intersection_nop_plane_two; } } { /* compute direction of intersection line and index to the largest component of D */ triangles_three D; CROSS(D,N1,N2); D[0] = fabs(D[0]); D[1] = fabs(D[1]); D[2] = fabs(D[2]); if (D[1] > D[0]) { index = D[2] > D[0] ? 2 : 1; } else { index = D[2] > D[0] ? 2 : 0; } } /* this is the simplified projection onto L */ { triangles_three vp; vp[0] = V0[index]; vp[1] = V1[index]; vp[2] = V2[index]; /* compute interval for triangle 1 */ if (compute_intervals_coplanar(V0, V1, V2, vp, dv, dv0dv1, dv0dv2, dv1dv2, &isect1[0], &isect1[1], isectpointA1, isectpointA2)) { return triangles_are_coplanar(N1, V0, V1, V2, U0, U1, U2) ? triangles_intersection_yes_coplanar : triangles_intersection_nop_coplanar; } } /* compute interval for triangle 2 */ { triangles_three up; up[0] = U0[index]; up[1] = U1[index]; up[2] = U2[index]; if (compute_intervals_coplanar(U0, U1, U2, up, du, du0du1, du0du2, du1du2, &isect2[0], &isect2[1], isectpointB1, isectpointB2)) { /* We should never end up here but as we have it in the non_div version too we added this redundant coplanar check if only because we have these possible return values. */ return triangles_are_coplanar(N1, V0, V1, V2, U0, U1, U2) ? triangles_intersection_yes_coplanar : triangles_intersection_nop_coplanar; } } { int smallest1, smallest2; SORT2(isect1[0],isect1[1],smallest1); SORT2(isect2[0],isect2[1],smallest2); if (isect1[1] < isect2[0] || isect2[1] < isect1[0]) { return triangles_intersection_nop_final; } /* at this point, we know that the triangles intersect */ if (isect2[0] < isect1[0]) { if (smallest1 == 0.0) { SET(isectpt1,isectpointA1); } else { SET(isectpt1,isectpointA2); } if (isect2[1] < isect1[1]) { if (smallest2 == 0.0) { SET(isectpt2,isectpointB2); } else { SET(isectpt2,isectpointB1); } } else { if (smallest1 == 0.0) { SET(isectpt2,isectpointA2); }else { SET(isectpt2,isectpointA1); } } } else { if (smallest2 == 0.0) { SET(isectpt1,isectpointB1); } else { SET(isectpt1,isectpointB2); } if (isect2[1] > isect1[1]) { if (smallest1 == 0.0) { SET(isectpt2,isectpointA2); } else { SET(isectpt2,isectpointA1); } } else { if (smallest2 == 0.0) { SET(isectpt2,isectpointB2); } else { SET(isectpt2,isectpointB1); } } } return triangles_intersection_yes_final; } } /* Triangle-Triangle Overlap Test Routines July, 2002 Updated December 2003 http://www.acm.org/jgt/papers/GuigueDevillers03/ https://github.com/erich666/jgt-code/blob/master/Volume_08/Number_1/Guigue2003/tri_tri_intersect.c http://www.philippe-guigue.de/data/triangle_triangle_intersection.html This file contains C implementation of algorithms for performing two and three-dimensional triangle-triangle intersection test. The algorithms and underlying theory are described in Fast and Robust Triangle-Triangle Overlap Test Using Orientation Predicates" P. Guigue - O. Devillers Journal of Graphics Tools, 8(1), 2003 Several geometric predicates are defined. Their parameters are all points. Each point is an array of two or three double precision floating point numbers. The geometric predicates implemented in this file are: int triangles_intersect_gd (p1,q1,r1,p2,q2,r2) int triangles_intersect_two_gd (p1,q1,r1,p2,q2,r2) int triangles_intersect_with_line_gd (p1,q1,r1,p2,q2,r2,source,target) Each function returns 1 if the triangles (including their boundary) intersect, otherwise 0. */ /* The code has reformatted by HH because (1) we want to see what happens, (2) we need to interface it to our own code, (3) we don't want to cast doubles to 0.0f and above all (4) we want to see the differences between several methods. */ /* Three-dimensional Triangle-Triangle Overlap Test. It additionally computes the segment of intersection of the two triangles if it exists. The coplanar variable returns whether the triangles are coplanar, source and target are the endpoints of the line segment of intersection. */ /* The optional EPSILON test (controlled by USE_EPSILON_TEST) has been replaced by USEZERO that we use in the Moller variant above. Here 1e-16 was used while Moller uses a larger value. We also share some macros with the previous definitions; SCALAR is like MUL but with a different parameter order. */ # define SCALAR(dest,alpha,v) \ dest[0] = alpha * v[0]; \ dest[1] = alpha * v[1]; \ dest[2] = alpha * v[2]; # define CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2) { \ SUB(v1,p2,q1) \ SUB(v2,p1,q1) \ CROSS(N1,v1,v2) \ SUB(v1,q2,q1) \ if (DOT(v1,N1) > 0.0) { \ return triangles_intersection_nop_final; \ } \ SUB(v1,p2,p1) \ SUB(v2,r1,p1) \ CROSS(N1,v1,v2) \ SUB(v1,r2,p1) \ if (DOT(v1,N1) > 0.0) { \ return triangles_intersection_nop_final; \ } else { \ return triangles_intersection_yes_final; \ } \ } static int triangles_are_coplanar_gd( triangles_three p1, triangles_three q1, triangles_three r1, triangles_three p2, triangles_three q2, triangles_three r2, triangles_three normal_1, double epsilon ) { triangles_two P1, Q1, R1; triangles_two P2, Q2, R2; double n_x = normal_1[0] < 0.0 ? -normal_1[0] : normal_1[0]; double n_y = normal_1[1] < 0.0 ? -normal_1[1] : normal_1[1]; double n_z = normal_1[2] < 0.0 ? -normal_1[2] : normal_1[2]; /* Projection of the triangles in 3D onto 2D such that the area of the projection is maximized. */ if (n_x > n_z && n_x >= n_y) { /* Project onto plane YZ */ P1[0] = q1[2]; P1[1] = q1[1]; Q1[0] = p1[2]; Q1[1] = p1[1]; R1[0] = r1[2]; R1[1] = r1[1]; P2[0] = q2[2]; P2[1] = q2[1]; Q2[0] = p2[2]; Q2[1] = p2[1]; R2[0] = r2[2]; R2[1] = r2[1]; } else if (n_y > n_z && n_y >= n_x) { /* Project onto plane XZ */ P1[0] = q1[0]; P1[1] = q1[2]; Q1[0] = p1[0]; Q1[1] = p1[2]; R1[0] = r1[0]; R1[1] = r1[2]; P2[0] = q2[0]; P2[1] = q2[2]; Q2[0] = p2[0]; Q2[1] = p2[2]; R2[0] = r2[0]; R2[1] = r2[2]; } else { /* Project onto plane XY */ P1[0] = p1[0]; P1[1] = p1[1]; Q1[0] = q1[0]; Q1[1] = q1[1]; R1[0] = r1[0]; R1[1] = r1[1]; P2[0] = p2[0]; P2[1] = p2[1]; Q2[0] = q2[0]; Q2[1] = q2[1]; R2[0] = r2[0]; R2[1] = r2[1]; } return triangles_intersect_two_gd(P1,Q1,R1,P2,Q2,R2,epsilon); }; /* Permutation in a canonical form of T2's vertices */ # define TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) { \ if (dp2 > 0.0) { \ if (dq2 > 0.0) { \ CHECK_MIN_MAX(p1,r1,q1,r2,p2,q2) \ } else if (dr2 > 0.0) { \ CHECK_MIN_MAX(p1,r1,q1,q2,r2,p2) \ } else { \ CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2) \ } \ } else if (dp2 < 0.0) { \ if (dq2 < 0.0) { \ CHECK_MIN_MAX(p1,q1,r1,r2,p2,q2)\ } else if (dr2 < 0.0) { \ CHECK_MIN_MAX(p1,q1,r1,q2,r2,p2)\ } else { \ CHECK_MIN_MAX(p1,r1,q1,p2,q2,r2) \ } \ } else if (dq2 < 0.0) { \ if (dr2 >= 0.0) { \ CHECK_MIN_MAX(p1,r1,q1,q2,r2,p2) \ } else { \ CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2) \ } \ } else if (dq2 > 0.0) { \ if (dr2 > 0.0) { \ CHECK_MIN_MAX(p1,r1,q1,p2,q2,r2) \ } else { \ CHECK_MIN_MAX(p1,q1,r1,q2,r2,p2) \ } \ } else if (dr2 > 0.0) { \ CHECK_MIN_MAX(p1,q1,r1,r2,p2,q2) \ } else if (dr2 < 0.0) { \ CHECK_MIN_MAX(p1,r1,q1,r2,p2,q2) \ } else { \ return triangles_are_coplanar_gd(p1,q1,r1,p2,q2,r2,N1,epsilon) \ ? triangles_intersection_yes_coplanar \ : triangles_intersection_nop_coplanar; \ } \ } /* Three-dimensional Triangle-Triangle Overlap Test */ int triangles_intersect_gd( triangles_three p1, triangles_three q1, triangles_three r1, triangles_three p2, triangles_three q2, triangles_three r2, double epsilon ) { double dp1, dq1, dr1, dp2, dq2, dr2; triangles_three v1, v2; triangles_three N1, N2; /* Compute distance signs of p1, q1 and r1 to the plane of triangle(p2,q2,r2) */ SUB(v1,p2,r2) SUB(v2,q2,r2) CROSS(N2,v1,v2) SUB(v1,p1,r2) dp1 = DOT(v1,N2); SUB(v1,q1,r2) dq1 = DOT(v1,N2); SUB(v1,r1,r2) dr1 = DOT(v1,N2); /* coplanarity robustness check */ if (USEZERO(dp1)) dp1 = 0.0; if (USEZERO(dq1)) dq1 = 0.0; if (USEZERO(dr1)) dr1 = 0.0; if (dp1 * dq1 > 0.0 && dp1 * dr1 > 0.0) { return triangles_intersection_nop_plane_one; } /* Compute distance signs of p2, q2 and r2 to the plane of triangle(p1,q1,r1) */ SUB(v1,q1,p1) SUB(v2,r1,p1) CROSS(N1,v1,v2) SUB(v1,p2,r1) dp2 = DOT(v1,N1); SUB(v1,q2,r1) dq2 = DOT(v1,N1); SUB(v1,r2,r1) dr2 = DOT(v1,N1); if (USEZERO(dp2)) dp2 = 0.0; if (USEZERO(dq2)) dq2 = 0.0; if (USEZERO(dr2)) dr2 = 0.0; if (dp2 * dq2 > 0.0 && dp2 * dr2 > 0.0) { return triangles_intersection_nop_plane_two; } /* Permutation in a canonical form of T1's vertices */ if (dp1 > 0.0) { if (dq1 > 0.0) { TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) } else if (dr1 > 0.0) { TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) } else { TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) } } else if (dp1 < 0.0) { if (dq1 < 0.0) { TRI_TRI_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) } else if (dr1 < 0.0) { TRI_TRI_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) } else { TRI_TRI_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) } } else if (dq1 < 0.0) { if (dr1 >= 0.0) { TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) } else { TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) } } else if (dq1 > 0.0) { if (dr1 > 0.0) { TRI_TRI_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) } else { TRI_TRI_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) } } else if (dr1 > 0.0) { TRI_TRI_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) } else if (dr1 < 0.0) { TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) } else { return triangles_are_coplanar_gd(p1,q1,r1,p2,q2,r2,N1,epsilon) ? triangles_intersection_nop_coplanar : triangles_intersection_yes_coplanar; } } /* Three-dimensional Triangle-Triangle Intersection */ /* This macro is called when the triangles surely intersect. It constructs the segment of intersection of the two triangles if they are not coplanar. NOTE: a faster, but possibly less precise, method of computing point B is described in: https://github.com/erich666/jgt-code/issues/5 The if and else branches shared some (final) code so that has been moved out and is shared (HH). */ # define CONSTRUCT_INTERSECTION(p1,q1,r1,p2,q2,r2) { \ double alpha; \ SUB(v1,q1,p1) \ SUB(v2,r2,p1) \ CROSS(N,v1,v2) \ SUB(v,p2,p1) \ if (DOT(v,N) > 0.0) { \ SUB(v1,r1,p1) \ CROSS(N,v1,v2) \ if (DOT(v,N) <= 0.0) { \ SUB(v2,q2,p1) \ CROSS(N,v1,v2) \ if (DOT(v,N) > 0.0) { \ SUB(v1,p1,p2) \ SUB(v2,p1,r1) \ alpha = DOT(v1,N2) / DOT(v2,N2); \ SCALAR(v1,alpha,v2) \ SUB(source,p1,v1) \ } else { \ SUB(v1,p2,p1) \ SUB(v2,p2,q2) \ alpha = DOT(v1,N1) / DOT(v2,N1); \ SCALAR(v1,alpha,v2) \ SUB(source,p2,v1) \ } \ SUB(v1,p2,p1) \ SUB(v2,p2,r2) \ alpha = DOT(v1,N1) / DOT(v2,N1); \ SCALAR(v1,alpha,v2) \ SUB(target,p2,v1) \ return triangles_intersection_yes_final; \ } else { \ return triangles_intersection_nop_final; \ } \ } else { \ SUB(v2,q2,p1) \ CROSS(N,v1,v2) \ if (DOT(v,N) < 0.0) { \ return triangles_intersection_nop_final; \ } else { \ SUB(v1,r1,p1) \ CROSS(N,v1,v2) \ if (DOT(v,N) >= 0.0) { \ SUB(v1,p1,p2) \ SUB(v2,p1,r1) \ alpha = DOT(v1,N2) / DOT(v2,N2); \ SCALAR(v1,alpha,v2) \ SUB(source,p1,v1) \ } else { \ SUB(v1,p2,p1) \ SUB(v2,p2,q2) \ alpha = DOT(v1,N1) / DOT(v2,N1); \ SCALAR(v1,alpha,v2) \ SUB(source,p2,v1) \ } \ SUB(v1,p1,p2) \ SUB(v2,p1,q1) \ alpha = DOT(v1,N2) / DOT(v2,N2); \ SCALAR(v1,alpha,v2) \ SUB(target,p1,v1) \ return triangles_intersection_yes_final; \ } \ } \ } # define TRI_TRI_INTER_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) { \ if (dp2 > 0.0) { \ if (dq2 > 0.0) { \ CONSTRUCT_INTERSECTION(p1,r1,q1,r2,p2,q2) \ } else if (dr2 > 0.0) { \ CONSTRUCT_INTERSECTION(p1,r1,q1,q2,r2,p2) \ } else { \ CONSTRUCT_INTERSECTION(p1,q1,r1,p2,q2,r2) \ } \ } else if (dp2 < 0.0) { \ if (dq2 < 0.0) { \ CONSTRUCT_INTERSECTION(p1,q1,r1,r2,p2,q2) \ } else if (dr2 < 0.0) { \ CONSTRUCT_INTERSECTION(p1,q1,r1,q2,r2,p2) \ } else { \ CONSTRUCT_INTERSECTION(p1,r1,q1,p2,q2,r2) \ } \ } else if (dq2 < 0.0) { \ if (dr2 >= 0.0) { \ CONSTRUCT_INTERSECTION(p1,r1,q1,q2,r2,p2) \ } else { \ CONSTRUCT_INTERSECTION(p1,q1,r1,p2,q2,r2) \ } \ } else if (dq2 > 0.0) { \ if (dr2 > 0.0) { \ CONSTRUCT_INTERSECTION(p1,r1,q1,p2,q2,r2) \ } else { \ CONSTRUCT_INTERSECTION(p1,q1,r1,q2,r2,p2) \ } \ } else if (dr2 > 0.0) { \ CONSTRUCT_INTERSECTION(p1,q1,r1,r2,p2,q2) \ } else if (dr2 < 0.0) { \ CONSTRUCT_INTERSECTION(p1,r1,q1,r2,p2,q2) \ } else { \ return triangles_are_coplanar_gd(p1,q1,r1,p2,q2,r2,N1,epsilon) \ ? triangles_intersection_nop_coplanar \ : triangles_intersection_yes_coplanar; \ } \ } /* The following version computes the segment of intersection of the two triangles if it exists. coplanar returns whether the triangles are coplanar source and target are the endpoints of the line segment of intersection. */ int triangles_intersect_with_line_gd( triangles_three p1, triangles_three q1, triangles_three r1, triangles_three p2, triangles_three q2, triangles_three r2, triangles_three source, triangles_three target, double epsilon ) { double dp1, dq1, dr1, dp2, dq2, dr2; triangles_three v1, v2, v; triangles_three N1, N2, N; /* Compute distance signs of p1, q1 and r1 to the plane of triangle(p2,q2,r2) */ SUB(v1,p2,r2) SUB(v2,q2,r2) CROSS(N2,v1,v2) SUB(v1,p1,r2) dp1 = DOT(v1,N2); SUB(v1,q1,r2) dq1 = DOT(v1,N2); SUB(v1,r1,r2) dr1 = DOT(v1,N2); /* coplanarity robustness check */ if (USEZERO(dp1)) dp1 = 0.0; if (USEZERO(dq1)) dq1 = 0.0; if (USEZERO(dr1)) dr1 = 0.0; if (dp1 * dq1 > 0.0 && dp1 * dr1 > 0.0) { return triangles_intersection_nop_plane_one; } // Compute distance signs of p2, q2 and r2 to the plane of triangle(p1,q1,r1) SUB(v1,q1,p1) SUB(v2,r1,p1) CROSS(N1,v1,v2) SUB(v1,p2,r1) dp2 = DOT(v1,N1); SUB(v1,q2,r1) dq2 = DOT(v1,N1); SUB(v1,r2,r1) dr2 = DOT(v1,N1); if (USEZERO(dp2)) dp2 = 0.0; if (USEZERO(dq2)) dq2 = 0.0; if (USEZERO(dr2)) dr2 = 0.0; if (dp2 * dq2 > 0.0 && dp2 * dr2 > 0.0) { return triangles_intersection_nop_plane_two; } /* Permutation in a canonical form of T1's vertices. */ if (dp1 > 0.0) { if (dq1 > 0.0) { TRI_TRI_INTER_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) } else if (dr1 > 0.0) { TRI_TRI_INTER_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) } else { TRI_TRI_INTER_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) } } else if (dp1 < 0.0) { if (dq1 < 0.0) { TRI_TRI_INTER_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) } else if (dr1 < 0.0) { TRI_TRI_INTER_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) } else { TRI_TRI_INTER_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) } } else if (dq1 < 0.0) { if (dr1 >= 0.0) { TRI_TRI_INTER_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) } else { TRI_TRI_INTER_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2) } } else if (dq1 > 0.0) { if (dr1 > 0.0) { TRI_TRI_INTER_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2) } else { TRI_TRI_INTER_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2) } } else if (dr1 > 0.0) { TRI_TRI_INTER_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2) } else if (dr1 < 0.0) { TRI_TRI_INTER_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2) } else { return triangles_are_coplanar_gd(p1,q1,r1,p2,q2,r2,N1,epsilon) \ ? triangles_intersection_nop_coplanar \ : triangles_intersection_yes_coplanar; \ } } /* Two dimensional Triangle-Triangle Overlap Test */ # define ORIENT_2D(a, b, c) ((a[0] - c[0]) * (b[1] - c[1]) - (a[1] - c[1]) * (b[0] - c[0])) # define INTERSECTION_TEST_VERTEX(P1,Q1,R1,P2,Q2,R2) { \ if (ORIENT_2D(R2,P2,Q1) >= 0.0) { \ if (ORIENT_2D(R2,Q2,Q1) <= 0.0) { \ if (ORIENT_2D(P1,P2,Q1) > 0.0) { \ if (ORIENT_2D(P1,Q2,Q1) <= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else if (ORIENT_2D(P1,P2,R1) >= 0.0) { \ if (ORIENT_2D(Q1,R1,P2) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } else if (ORIENT_2D(P1,Q2,Q1) <= 0.0) { \ if (ORIENT_2D(R2,Q2,R1) <= 0.0) { \ if (ORIENT_2D(Q1,R1,Q2) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } else if (ORIENT_2D(R2,P2,R1) >= 0.0) { \ if (ORIENT_2D(Q1,R1,R2) >= 0.0) { \ if (ORIENT_2D(P1,P2,R1) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else if (ORIENT_2D(Q1,R1,Q2) >= 0.0) { \ if (ORIENT_2D(R2,R1,Q2) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } # define INTERSECTION_TEST_EDGE(P1,Q1,R1,P2,Q2,R2) { \ if (ORIENT_2D(R2,P2,Q1) >= 0.0) { \ if (ORIENT_2D(P1,P2,Q1) >= 0.0) { \ if (ORIENT_2D(P1,Q1,R2) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else if (ORIENT_2D(Q1,R1,P2) >= 0.0) { \ if (ORIENT_2D(R1,P1,P2) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } else if (ORIENT_2D(R2,P2,R1) >= 0.0) { \ if (ORIENT_2D(P1,P2,R1) >= 0.0) { \ if (ORIENT_2D(P1,R1,R2) >= 0.0) { \ return 1; \ } else if (ORIENT_2D(Q1,R1,R2) >= 0.0) { \ return 1; \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } else { \ return 0; \ } \ } static int triangles_intersection_2d( triangles_two p1, triangles_two q1, triangles_two r1, triangles_two p2, triangles_two q2, triangles_two r2, double epsilon ) { (void) epsilon; if (ORIENT_2D(p2,q2,p1) >= 0.0) { if (ORIENT_2D(q2,r2,p1) >= 0.0) { if (ORIENT_2D(r2,p2,p1) >= 0.0) { return 1; } else { INTERSECTION_TEST_EDGE(p1,q1,r1,p2,q2,r2) } } else { if (ORIENT_2D(r2,p2,p1) >= 0.0) { INTERSECTION_TEST_EDGE(p1,q1,r1,r2,p2,q2) } else { INTERSECTION_TEST_VERTEX(p1,q1,r1,p2,q2,r2) } } } else { if (ORIENT_2D(q2,r2,p1) >= 0.0) { if (ORIENT_2D(r2,p2,p1) >= 0.0) { INTERSECTION_TEST_EDGE(p1,q1,r1,q2,r2,p2) } else { INTERSECTION_TEST_VERTEX(p1,q1,r1,q2,r2,p2) } } else { INTERSECTION_TEST_VERTEX(p1,q1,r1,r2,p2,q2) } } } int triangles_intersect_two_gd( triangles_two p1, triangles_two q1, triangles_two r1, triangles_two p2, triangles_two q2, triangles_two r2, double epsilon ) { if (ORIENT_2D(p1,q1,r1) < 0.0) { return ORIENT_2D(p2,q2,r2) < 0.0 ? triangles_intersection_2d(p1,r1,q1,p2,r2,q2,epsilon) : triangles_intersection_2d(p1,r1,q1,p2,q2,r2,epsilon); } else { return ORIENT_2D(p2,q2,r2) < 0.0 ? triangles_intersection_2d(p1,q1,r1,p2,r2,q2,epsilon) : triangles_intersection_2d(p1,q1,r1,p2,q2,r2,epsilon); } } luametatex-2.11.08/source/libraries/triangles/triangles.h0000644000175000017500000001022215063273560022421 0ustar hillehille/*tex This triangle library is mostly a by-product of some experiments by Mikael Sundqvist and Hans Hagen with (pseudo) 3D rendering in \METAPOST. We wanted to detect intersecting triangles in meshing and ran into a few solutions. We did some test in \LUA\ and for performance reasons decided to go for \CCODE, also because we were working on a related vector library. So, this code is somewhat alien to \LUAMETATEX\ but occasionally we permit ourselves some deviation from our \quotation {keep the engine lean and mean} principles. We also want to document experiments in a way that doesn't demand the use of some external library when it comes to \METAPOST. We took the code from the resources mentioned below but adapted it to our needs, that is: a bit different interfaces, some more granular return values, reformatting macros and c so that we could better understand (and maybe optimize) some; we also made sure all was double okay. If we introduced errors, blame us. */ /* For the Moller variant, see license comment in the triangles.c file! https://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/tritri_isectline.txt For Guigue & Devillers see: http://www.acm.org/jgt/papers/GuigueDevillers03/ https://github.com/erich666/jgt-code/blob/master/Volume_08/Number_1/Guigue2003/tri_tri_intersect.c http://www.philippe-guigue.de/data/triangle_triangle_intersection.html There is overlap between the code, the main difference is in the part where the comparison happens after the initial tests fell trough. */ # ifndef TRIANGLES_H # define TRIANGLES_H /*tex For practical purposes we added more detailed feedback about the coplanar and overlap states so that we can report on them later on. We also need more info in order to play with this. So the interfaces are different than the original. We found that the right setting of |EPSILON| played a huge rule in false positives so we decided to make that a parameter. MS & HH */ # define triangles_epsilon 1.0e-06 // 0.000001 # define triangles_epsilon_gd 1.0e-16 typedef double triangles_two [2] ; typedef double triangles_three[3] ; typedef enum triangles_intersection_states { /* we don't intersect: */ triangles_intersection_nop_bound = 0x00, triangles_intersection_nop_plane_one = 0x01, triangles_intersection_nop_plane_two = 0x02, triangles_intersection_nop_coplanar = 0x03, triangles_intersection_nop_final = 0x04, triangles_intersection_nop_same_points = 0x0E, triangles_intersection_nop_same_values = 0x0F, /* we intersect: */ triangles_intersection_yes_bound = 0x10, triangles_intersection_yes_unused_1 = 0x11, triangles_intersection_yes_unused_2 = 0x12, triangles_intersection_yes_coplanar = 0x13, triangles_intersection_yes_final = 0x14, /* */ } triangles_intersection_states; /* Moller */ extern int triangles_intersect ( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, double epsilon ); extern int triangles_intersect_with_line ( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, triangles_three isectpt1, triangles_three isectpt2, double epsilon ); /* Guigue & Devillers */ extern int triangles_intersect_gd ( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, double epsilon ); extern int triangles_intersect_with_line_gd ( triangles_three V0, triangles_three V1, triangles_three V2, triangles_three U0, triangles_three U1, triangles_three U2, triangles_three source, triangles_three target, double epsilon ); extern int triangles_intersect_two_gd ( /* todo: return values */ triangles_two V0, triangles_two V1, triangles_two V2, triangles_two U0, triangles_two U1, triangles_two U2, double epsilon ); # endif luametatex-2.11.08/source/libraries/softposit/0000775000175000017500000000000015077444116020331 5ustar hillehilleluametatex-2.11.08/source/libraries/softposit/build/0000775000175000017500000000000015077444116021430 5ustar hillehilleluametatex-2.11.08/source/libraries/softposit/build/Linux-x86_64-GCC/0000775000175000017500000000000015077444344024060 5ustar hillehilleluametatex-2.11.08/source/libraries/softposit/build/Linux-x86_64-GCC/Makefile0000644000175000017500000001450215063273560025513 0ustar hillehille#============================================================================ # #This C source file is part of the SoftPosit Posit Arithmetic Package #by S. H. Leong (Cerlane). # #Copyright 2017, 2018 A*STAR. All rights reserved. # #This C source file was based on SoftFloat IEEE Floating-Point Arithmetic #Package, Release 3d, by John R. Hauser. # # # Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the # University of California. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the University nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE # DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # #============================================================================= SOURCE_DIR ?= ../../source PYTHON_DIR ?= ../../python SPECIALIZE_TYPE ?= 8086-SSE COMPILER ?= gcc SOFTPOSIT_OPTS ?= \ -DINLINE_LEVEL=5 #\ -DSOFTPOSIT_QUAD -lquadmath COMPILE_PYTHON = \ $(COMPILER) -fPIC -c $(PYTHON_DIR)/softposit_python_wrap.c \ -I/usr/include/python \ -I$(SOURCE_DIR)/include -I. COMPILE_PYTHON3 = \ $(COMPILER) -fPIC -c $(PYTHON_DIR)/softposit_python_wrap.c \ -I/usr/include/python3 \ -I$(SOURCE_DIR)/include -I. LINK_PYTHON = \ ld -shared *.o -o $(PYTHON_DIR)/_softposit.so ifeq ($(OS),Windows_NT) DELETE = del /Q /F else DELETE = rm -f endif C_INCLUDES = -I. -I$(SOURCE_DIR)/$(SPECIALIZE_TYPE) -I$(SOURCE_DIR)/include OPTIMISATION = -O2 #-march=core-avx2 COMPILE_C = \ $(COMPILER) -c -Werror-implicit-function-declaration -DSOFTPOSIT_FAST_INT64 \ $(SOFTPOSIT_OPTS) $(C_INCLUDES) $(OPTIMISATION) \ -o $@ MAKELIB = ar crs $@ MAKESLIB = $(COMPILER) -shared $^ OBJ = .o LIB = .a SLIB = .so .PHONY: all all: softposit$(LIB) quad: SOFTPOSIT_OPTS+= -DSOFTPOSIT_QUAD -lquadmath quad: all python2: SOFTPOSIT_OPTS+= -fPIC python2: all $(COMPILE_PYTHON) $(LINK_PYTHON) python3: SOFTPOSIT_OPTS+= -fPIC python3: all $(COMPILE_PYTHON3) $(LINK_PYTHON) julia: SOFTPOSIT_OPTS+= -fPIC julia: softposit$(SLIB) OBJS_PRIMITIVES = OBJS_SPECIALIZE = OBJS_OTHERS = \ s_addMagsP8$(OBJ) \ s_subMagsP8$(OBJ) \ s_mulAddP8$(OBJ) \ p8_add$(OBJ) \ p8_sub$(OBJ) \ p8_mul$(OBJ) \ p8_div$(OBJ) \ p8_sqrt$(OBJ) \ p8_to_p16$(OBJ) \ p8_to_p32$(OBJ) \ p8_to_pX2$(OBJ) \ p8_to_i32$(OBJ) \ p8_to_i64$(OBJ) \ p8_to_ui32$(OBJ) \ p8_to_ui64$(OBJ) \ p8_roundToInt$(OBJ) \ p8_mulAdd$(OBJ) \ p8_eq$(OBJ) \ p8_le$(OBJ) \ p8_lt$(OBJ) \ quire8_fdp_add$(OBJ) \ quire8_fdp_sub$(OBJ) \ ui32_to_p8$(OBJ) \ ui64_to_p8$(OBJ) \ i32_to_p8$(OBJ) \ i64_to_p8$(OBJ) \ s_addMagsP16$(OBJ) \ s_subMagsP16$(OBJ) \ s_mulAddP16$(OBJ) \ p16_to_ui32$(OBJ) \ p16_to_ui64$(OBJ) \ p16_to_i32$(OBJ) \ p16_to_i64$(OBJ) \ p16_to_p8$(OBJ) \ p16_to_p32$(OBJ) \ p16_to_pX2$(OBJ) \ p16_roundToInt$(OBJ) \ p16_add$(OBJ) \ p16_sub$(OBJ) \ p16_mul$(OBJ) \ p16_mulAdd$(OBJ) \ p16_div$(OBJ) \ p16_eq$(OBJ) \ p16_le$(OBJ) \ p16_lt$(OBJ) \ p16_sqrt$(OBJ) \ quire16_fdp_add$(OBJ) \ quire16_fdp_sub$(OBJ) \ quire_helper$(OBJ) \ ui32_to_p16$(OBJ) \ ui64_to_p16$(OBJ) \ i32_to_p16$(OBJ) \ i64_to_p16$(OBJ) \ s_addMagsP32$(OBJ) \ s_subMagsP32$(OBJ) \ s_mulAddP32$(OBJ) \ p32_to_ui32$(OBJ) \ p32_to_ui64$(OBJ) \ p32_to_i32$(OBJ) \ p32_to_i64$(OBJ) \ p32_to_p8$(OBJ) \ p32_to_p16$(OBJ) \ p32_to_pX2$(OBJ) \ p32_roundToInt$(OBJ) \ p32_add$(OBJ) \ p32_sub$(OBJ) \ p32_mul$(OBJ) \ p32_mulAdd$(OBJ) \ p32_div$(OBJ) \ p32_eq$(OBJ) \ p32_le$(OBJ) \ p32_lt$(OBJ) \ p32_sqrt$(OBJ) \ quire32_fdp_add$(OBJ) \ quire32_fdp_sub$(OBJ) \ ui32_to_p32$(OBJ) \ ui64_to_p32$(OBJ) \ i32_to_p32$(OBJ) \ i64_to_p32$(OBJ) \ s_approxRecipSqrt_1Ks$(OBJ) \ c_convertDecToPosit8$(OBJ) \ c_convertPosit8ToDec$(OBJ) \ c_convertDecToPosit16$(OBJ) \ c_convertPosit16ToDec$(OBJ) \ c_convertQuire8ToPosit8$(OBJ) \ c_convertQuire16ToPosit16$(OBJ) \ c_convertQuire32ToPosit32$(OBJ) \ c_convertDecToPosit32$(OBJ) \ c_convertPosit32ToDec$(OBJ) \ c_int$(OBJ) \ s_addMagsPX2$(OBJ) \ s_subMagsPX2$(OBJ) \ s_mulAddPX2$(OBJ) \ pX2_add$(OBJ) \ pX2_sub$(OBJ) \ pX2_mul$(OBJ) \ pX2_div$(OBJ) \ pX2_mulAdd$(OBJ) \ pX2_roundToInt$(OBJ) \ pX2_sqrt$(OBJ) \ pX2_eq$(OBJ) \ pX2_le$(OBJ) \ pX2_lt$(OBJ) \ ui32_to_pX2$(OBJ) \ ui64_to_pX2$(OBJ) \ i32_to_pX2$(OBJ) \ i64_to_pX2$(OBJ) \ c_convertQuireX2ToPositX2$(OBJ) OBJS_ALL := $(OBJS_PRIMITIVES) $(OBJS_SPECIALIZE) $(OBJS_OTHERS) $(OBJS_ALL): \ platform.h \ $(SOURCE_DIR)/include/primitives.h $(OBJS_SPECIALIZE) $(OBJS_OTHERS): \ $(SOURCE_DIR)/include/softposit_types.h $(SOURCE_DIR)/include/internals.h \ $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/specialize.h \ $(SOURCE_DIR)/include/softposit.h $(OBJS_PRIMITIVES) $(OBJS_OTHERS): %$(OBJ): $(SOURCE_DIR)/%.c $(COMPILE_C) $(SOURCE_DIR)/$*.c $(OBJS_SPECIALIZE): %$(OBJ): $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/%.c $(COMPILE_C) $(SOURCE_DIR)/$(SPECIALIZE_TYPE)/$*.c softposit$(LIB): $(OBJS_ALL) $(MAKELIB) $^ softposit$(SLIB): $(OBJS_ALL) $(MAKESLIB) -o $@ .PHONY: clean clean: $(DELETE) $(OBJS_ALL) softposit_python_wrap.o softposit$(LIB) softposit$(SLIB) luametatex-2.11.08/source/libraries/softposit/build/Linux-x86_64-GCC/platform.h0000644000175000017500000000432215063273560026047 0ustar hillehille /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define LITTLEENDIAN 1 /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #ifdef __GNUC_STDC_INLINE__ #define INLINE inline #else #define INLINE extern inline #endif luametatex-2.11.08/source/libraries/softposit/LICENSE0000644000175000017500000000327215063273560021336 0ustar hillehilleBSD 3-Clause License This is part of the SoftPosit Posit Arithmetic Package by S. H. Leong (Cerlane). Copyright 2017 2018 A*STAR. All rights reserved. Many of the C source files design were based on SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. luametatex-2.11.08/source/libraries/softposit/source/0000775000175000017500000000000015077444116021631 5ustar hillehilleluametatex-2.11.08/source/libraries/softposit/source/s_mulAddPX2.c0000644000175000017500000001747115063273560024065 0ustar hillehille /*============================================================================ This C source file is part of the SoftPosit Posit Arithmetic Package by S. H. Leong (Cerlane). Copyright 2017, 2018 A*STAR. All rights reserved. This C source file was based on SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include "platform.h" #include "internals.h" //a*b+c posit_2_t softposit_mulAddPX2( uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC, uint_fast32_t op, int x ){ union ui32_pX2 uZ; int regZ; uint_fast32_t fracA, fracZ, regime, tmp; bool signA, signB, signC, signZ, regSA, regSB, regSC, regSZ, bitNPlusOne=0, bitsMore=0, rcarry; int_fast32_t expA, expC, expZ; int_fast16_t kA=0, kC=0, kZ=0, shiftRight; uint_fast64_t frac64C, frac64Z; if (x<2 || x>32){ uZ.ui = 0x80000000; return uZ.p; } //NaR if ( uiA==0x80000000 || uiB==0x80000000 || uiC==0x80000000 ){ uZ.ui = 0x80000000; return uZ.p; } else if (uiA==0 || uiB==0){ if (op == softposit_mulAdd_subC) uZ.ui = -uiC; else uZ.ui = uiC; return uZ.p; } signA = signP32UI( uiA ); signB = signP32UI( uiB ); signC = signP32UI( uiC );//^ (op == softposit_mulAdd_subC); signZ = signA ^ signB;// ^ (op == softposit_mulAdd_subProd); if(signA) uiA = (-uiA & 0xFFFFFFFF); if(signB) uiB = (-uiB & 0xFFFFFFFF); if(signC) uiC = (-uiC & 0xFFFFFFFF); regSA = signregP32UI(uiA); regSB = signregP32UI(uiB); regSC = signregP32UI(uiC); if (x==2){ uZ.ui = (regSA®SB) ? (0x40000000) : (0x0); if (signZ){// i.e. negative prod if (signC){ uZ.ui |= uiC; uZ.ui = -uZ.ui & 0xFFFFFFFF; } else{//prod is negative if (uiC==uZ.ui) uZ.ui = 0; else uZ.ui =(uZ.ui>0)?( 0xC0000000):(0x40000000); } } else{ //prod : same sign signZ=0 if (signC){ if (uiC==uZ.ui) uZ.ui = 0; else uZ.ui = (uZ.ui>0) ? (0x40000000) : (0xC0000000); } else{//C is positive uZ.ui |= uiC; } } return uZ.p; } else{ tmp = (uiA<<2)&0xFFFFFFFF; if (regSA){ while (tmp>>31){ kA++; tmp= (tmp<<1) & 0xFFFFFFFF; } } else{ kA=-1; while (!(tmp>>31)){ kA--; tmp= (tmp<<1) & 0xFFFFFFFF; } tmp&=0x7FFFFFFF; } expA = tmp>>29; //to get 2 bits fracA = ((tmp<<2) | 0x80000000) & 0xFFFFFFFF; tmp = (uiB<<2)&0xFFFFFFFF; if (regSB){ while (tmp>>31){ kA++; tmp= (tmp<<1) & 0xFFFFFFFF; } } else{ kA--; while (!(tmp>>31)){ kA--; tmp= (tmp<<1) & 0xFFFFFFFF; } tmp&=0x7FFFFFFF; } expA += tmp>>29; frac64Z = (uint_fast64_t) fracA * (((tmp<<2) | 0x80000000) & 0xFFFFFFFF); if (expA>3){ kA++; expA&=0x3; // -=4 } rcarry = frac64Z>>63;//1st bit of frac64Z if (rcarry){ expA++; if (expA>3){ kA ++; expA&=0x3; } frac64Z>>=1; } if (uiC!=0){ tmp = (uiC<<2)&0xFFFFFFFF; if (regSC){ while (tmp>>31){ kC++; tmp= (tmp<<1) & 0xFFFFFFFF; } } else{ kC=-1; while (!(tmp>>31)){ kC--; tmp= (tmp<<1) & 0xFFFFFFFF; } tmp&=0x7FFFFFFF; } expC = tmp>>29; //to get 2 bits frac64C = (((tmp<<1) | 0x40000000ULL) & 0x7FFFFFFFULL)<<32; shiftRight = ((kA-kC)<<2) + (expA-expC); if (shiftRight<0){ // |uiC| > |Prod| if (shiftRight<=-63){ bitsMore = 1; frac64Z = 0; //set bitsMore to one? } else if ((frac64Z<<(64+shiftRight))!=0) bitsMore = 1; if (signZ==signC) frac64Z = frac64C + (frac64Z>>-shiftRight); else {//different signs frac64Z = frac64C - (frac64Z>>-shiftRight) ; signZ=signC; if (bitsMore) frac64Z-=1; } kZ = kC; expZ = expC; } else if (shiftRight>0){// |uiC| < |Prod| //if (frac32C&((1<=63) { bitsMore = 1; frac64C = 0; } else if ((frac64C<<(64-shiftRight))!=0) bitsMore = 1; if (signZ==signC) frac64Z = frac64Z + (frac64C>>shiftRight); else{ frac64Z = frac64Z - (frac64C>>shiftRight); if (bitsMore) frac64Z-=1; } kZ = kA; expZ = expA; } else{ if(frac64C==frac64Z && signZ!=signC ){ //check if same number uZ.ui = 0; return uZ.p; } else{ if (signZ==signC) frac64Z += frac64C; else{ if (frac64Z>63; //first left bit if(rcarry){ expZ++; if (expZ>3){ kZ++; expZ&=0x3; } frac64Z=(frac64Z>>1)&0x7FFFFFFFFFFFFFFF; } else { //for subtract cases if (frac64Z!=0){ while((frac64Z>>59)==0){ kZ--; frac64Z<<=4; } while((frac64Z>>62)==0){ expZ--; frac64Z<<=1; if (expZ<0){ kZ--; expZ=3; } } } } } else{ kZ = kA; expZ=expA; } if(kZ<0){ regZ = -kZ; regSZ = 0; regime = 0x40000000>>regZ; } else{ regZ = kZ+1; regSZ=1; regime = 0x7FFFFFFF - (0x7FFFFFFF>>regZ); } if(regZ>(x-2)){ //max or min pos. exp and frac does not matter. uZ.ui=(regSZ) ? (0x7FFFFFFF & ((int32_t)0x80000000>>(x-1)) ): (0x1 << (32-x)); } else{ if (regZ