More rendering fixes and Hypseus nonsense.

This commit is contained in:
Scott Duensing 2026-09-10 19:03:29 -05:00
parent b4376c0cfc
commit 18bdd0a1e3
33 changed files with 7874 additions and 20 deletions

View file

@ -649,12 +649,57 @@ API Changes
- navAgentNew keeps the radius and height at 0.01 or more, as navNew - navAgentNew keeps the radius and height at 0.01 or more, as navNew
does, so onNavArrived fires for an agent given a radius of zero. does, so onNavArrived fires for an agent given a radius of zero.
- Three Hypseus names the bytecode-only games turned out to need.
controllerSetPadding(boolean) and controllerGetPadding() are accepted;
the getter always answers 0, because Hypseus's offset marks a switch
code as having come from a gamepad and Singe's mapped switches carry no
such mark. videoGetVolume() with no argument answers the laserdisc's
volume on Hypseus's 0 to 64 scale, which its games double into
musicSetVolume. require("md5") gives the PUC-Rio md5 library Hypseus
bundles, all five of sum, hexsum, exor, crypt and decrypt, so a game
written against it behaves the same here; note that library names its
sumhexa hexsum.
- The manual now says plainly that the Hypseus API is for compatibility
and not for new games, in the Lua API Reference introduction and again
at the head of the Hypseus Compatibility section. Every Hypseus name,
and every Hypseus argument form on a function that otherwise takes
Singe's own, says so in its own entry.
- videoSetVolume(volume), with one argument instead of three, sets the
laserdisc's volume on Hypseus's 0 to 64 scale, the twin of the bare
videoGetVolume(). A level outside that range is ignored rather than
fatal, as in Hypseus.
- drawTransparent(boolean), getUserString(), mouseGetPadding() and
spriteBlend(boolean, sprite) are registered, completing the set of
names Hypseus's engine exposes. All four are compatibility answers:
Singe carries transparency in the alpha channel rather than a colour
key, sends no statistics and so has no machine ID to report, adds no
offset to mouse input codes, and never has blending switched off.
- allowSocketCall() and setOverlayFullAlpha() are registered so a game
that calls them does not stop on a missing function. The first always
answers false: Hypseus reports whether the user let it send data to a
stats server, and Singe sends nothing anywhere. The second is accepted
and ignored: it asks for an overlay that blends its alpha channel
rather than thresholding it, which Singe's overlay has always done.
- The other Lua modules Hypseus exposes are here too, whether or not a
game asks for them: require("bit") is LuaBitOp, require("random") a
Mersenne Twister generator, require("cjson") Lua CJSON and
require("lpeg") LPeg. Singe already had the rest of Hypseus's list
(lfs, socket, rs232) and opens every standard Lua library besides.
- materialSetCutoff(material, cutoff) discards the texels whose base - materialSetCutoff(material, cutoff) discards the texels whose base
colour alpha falls below the cutoff, in the lit pass and in the shadow colour alpha falls below the cutoff, in the lit pass and in the shadow
pass alike, so cutout foliage casts cutout shadows. glTF's MASK alpha pass alike, so cutout foliage casts cutout shadows. What survives the
mode now sets it from the file's alphaCutoff instead of warning that cutoff is drawn fully opaque, which is what glTF means by MASK as
the material would be drawn opaque; BLEND and OPAQUE are unchanged. against BLEND: the sampled alpha is not passed on, so nothing behind
Materials that never set a cutoff keep drawing every texel. the scene shows through a leaf. glTF's MASK alpha mode now sets the
cutoff from the file's alphaCutoff instead of warning that the material
would be drawn opaque; BLEND and OPAQUE are unchanged. Materials that
never set a cutoff keep drawing every texel.
- --deterministic[=MS] runs the engine on a virtual clock stepped MS - --deterministic[=MS] runs the engine on a virtual clock stepped MS
milliseconds (default 15) once a frame instead of on real time, steps milliseconds (default 15) once a frame instead of on real time, steps

View file

@ -338,6 +338,48 @@ set(LUA_FILESYSTEM_SOURCE
thirdparty/luafilesystem/src/lfs.h thirdparty/luafilesystem/src/lfs.h
) )
# The PUC-Rio md5 library, as Hypseus bundles it (its sumhexa is named hexsum), so the games that
# require("md5") get the same five functions with the same behaviour.
set(LUA_MD5_SOURCE
thirdparty/md5/md5.c
thirdparty/md5/md5.h
thirdparty/md5/md5lib.c
)
# The rest of the Lua modules Hypseus exposes, so a game written against it finds them here too:
# LuaBitOp, lrandom, Lua CJSON and LPeg.
set(LUA_BITOP_SOURCE
thirdparty/luabitop/lbit.c
)
set(LUA_RANDOM_SOURCE
thirdparty/lrandom/lrandom.c
)
set(LUA_CJSON_SOURCE
thirdparty/lua-cjson/fpconv.c
thirdparty/lua-cjson/fpconv.h
thirdparty/lua-cjson/lua_cjson.c
thirdparty/lua-cjson/strbuf.c
thirdparty/lua-cjson/strbuf.h
)
set(LPEG_SOURCE
thirdparty/lpeg/lpcap.c
thirdparty/lpeg/lpcap.h
thirdparty/lpeg/lpcode.c
thirdparty/lpeg/lpcode.h
thirdparty/lpeg/lpcset.c
thirdparty/lpeg/lpcset.h
thirdparty/lpeg/lpprint.c
thirdparty/lpeg/lpprint.h
thirdparty/lpeg/lptree.c
thirdparty/lpeg/lptree.h
thirdparty/lpeg/lptypes.h
thirdparty/lpeg/lpvm.c
thirdparty/lpeg/lpvm.h
)
set(LUA_SOCKET_SOURCE set(LUA_SOCKET_SOURCE
thirdparty/luasocket/src/auxiliar.c thirdparty/luasocket/src/auxiliar.c
thirdparty/luasocket/src/auxiliar.h thirdparty/luasocket/src/auxiliar.h
@ -436,6 +478,11 @@ add_executable(${CMAKE_PROJECT_NAME}
${ARG_PARSER_SOURCE} ${ARG_PARSER_SOURCE}
${LUA_SOURCE} ${LUA_SOURCE}
${LUA_FILESYSTEM_SOURCE} ${LUA_FILESYSTEM_SOURCE}
${LUA_MD5_SOURCE}
${LUA_BITOP_SOURCE}
${LUA_RANDOM_SOURCE}
${LUA_CJSON_SOURCE}
${LPEG_SOURCE}
${SQLITE_SOURCE} ${SQLITE_SOURCE}
${LUA_SOCKET_SOURCE} ${LUA_SOCKET_SOURCE}
${LUASEC_SOURCE} ${LUASEC_SOURCE}

View file

@ -1981,6 +1981,9 @@ Beyond that:
and chain link are drawn: one quad, most of it gone. Unlike blending it and chain link are drawn: one quad, most of it gone. Unlike blending it
needs no sorting and it still casts a shadow, and the shadow is cut out needs no sorting and it still casts a shadow, and the shadow is cut out
too, so a tree throws leaf shadows rather than the shadow of its quad. too, so a tree throws leaf shadows rather than the shadow of its quad.
What survives the cutoff is opaque: a half-transparent texel is either
kept whole or dropped, never blended, so nothing behind the scene (the
disc picture, most visibly) tints a leaf.
A cutoff of 0 (the default) turns masking off. A model loaded from glTF A cutoff of 0 (the default) turns masking off. A model loaded from glTF
brings its own: `MASK` sets the cutoff from the file, `BLEND` turns brings its own: `MASK` sets the cutoff from the file, `BLEND` turns
blending on, and `OPAQUE` does neither. blending on, and `OPAQUE` does neither.
@ -3127,10 +3130,17 @@ install any additional software:
| LuaSocket | TCP and UDP | LuaSocket | TCP and UDP
| LuaRS232 | RS232 serial port access | LuaRS232 | RS232 serial port access
| lsqlite3 | SQLite databases, `require("sqlite3")` | lsqlite3 | SQLite databases, `require("sqlite3")`
| md5 | `require("md5")` for `sum`, `hexsum`, `exor`, `crypt` and `decrypt`; the PUC-Rio library Hypseus bundles, whose `sumhexa` it names `hexsum`
| LuaBitOp | `require("bit")` for the bitwise operations of Lua 5.1, which 5.4 has as operators
| lrandom | `require("random")` for a Mersenne Twister generator, separate from `math.random`
| Lua CJSON | `require("cjson")` for JSON encoding and decoding, beside the `json` module above
| LPeg | `require("lpeg")` for parsing expression grammars
| RmlUi | The GUI's own object model, the `rmlui` global (see <<gui,GUI>>) | RmlUi | The GUI's own object model, the `rmlui` global (see <<gui,GUI>>)
|=== |===
Their usage is beyond the scope of this document. Their usage is beyond the scope of this document. The last five are there
because Hypseus exposes them, so a game written against Hypseus finds the same
modules under the same names; nothing in Singe needs them.
[#audiosync] [#audiosync]
=== Audio Sync === Audio Sync
@ -3247,6 +3257,20 @@ Every API entry below follows the same structure:
* *See also* -- related functions you will likely use in the same call site. * *See also* -- related functions you will likely use in the same call site.
* *Example* -- a short, realistic snippet in the shape of real game code. * *Example* -- a short, realistic snippet in the shape of real game code.
An entry that begins *Hypseus extension* is there so that a game written for
Hypseus Singe runs here unchanged. The same goes for an argument form marked as
Hypseus's on a function that otherwise takes Singe's own.
IMPORTANT: *Do not write new games against the Hypseus API.* Those entries exist
for compatibility, not as a recommendation. Several of them answer a fixed value
because the thing they describe does not exist in Singe, some are accepted and
ignored, and others carry scales and argument orders inherited from another
engine -- `videoGetVolume()` counts to `64` where the rest of Singe counts to
`100`, and the `spriteAnim` names take the sprite last where every Singe sprite
call takes it first. Each entry names the Singe equivalent to use instead. New
code that sticks to the Singe API is shorter, consistent with itself, and will
not be surprised when a compatibility answer stays constant.
A few rules apply across the whole API: A few rules apply across the whole API:
* *Colors* are 8-bit per channel: red, green, blue, and opacity are each integers from `0` to `255`. * *Colors* are 8-bit per channel: red, green, blue, and opacity are each integers from `0` to `255`.
@ -3271,6 +3295,19 @@ morph target weights are all driven. See the Animation part of
<<scenes3d,3D Scenes>>. <<scenes3d,3D Scenes>>.
[#animationgettime] [#animationgettime]
==== allowSocketCall
[source,text]
----
allowed = allowSocketCall()
----
Hypseus extension, always `false` in Singe. Hypseus answers whether the user let it send data to a stats server, which its `-noserversend` turns off; the sending itself is commented out there. Singe sends nothing anywhere, so nothing is permitted and the answer never changes. It exists so a game that asks does not stop on a missing function.
*Returns:* a boolean, always `false`.
*Since:* 3.00
==== animationGetTime ==== animationGetTime
[source,text] [source,text]
@ -4706,6 +4743,20 @@ end
---- ----
[#controllerhowmany] [#controllerhowmany]
==== controllerGetPadding
[source,text]
----
padding = controllerGetPadding()
----
Hypseus extension, always `0` in Singe. Hypseus adds this offset to a switch code that came from a gamepad, so a game can tell which device pressed what and still recover the switch by subtracting it. Singe delivers gamepad input as ordinary mapped switches carrying no such mark, so it answers `0`: a game testing for the padded range takes its other branch and reads the switch as it stands.
*Returns:* an integer, always `0`.
*Since:* 3.00
*See also:* <<controllersetpadding,controllerSetPadding>>
==== controllerHowMany ==== controllerHowMany
[source,text] [source,text]
@ -4769,6 +4820,20 @@ end
Two calls for seeing what a script is doing: `debugPrint` writes text, and `lineDraw` draws a line over the 3D scene for one frame (`physicsSetDebug` and `navDraw` draw through the same lines). Printed output goes to the console Singe was started from, so it is visible during development and harmless in a cabinet, where `--noconsole` silences it. When Singe runs with `--trace`, every API call including this one is also written with its arguments to `trace.txt` in the data directory, which is the way to get a permanent record. Command line options are listed in the chapter on running Singe; the ZeroBrane Studio integration in `zbstudio/` offers a debugger when printing is not enough. Two calls for seeing what a script is doing: `debugPrint` writes text, and `lineDraw` draws a line over the 3D scene for one frame (`physicsSetDebug` and `navDraw` draw through the same lines). Printed output goes to the console Singe was started from, so it is visible during development and harmless in a cabinet, where `--noconsole` silences it. When Singe runs with `--trace`, every API call including this one is also written with its arguments to `trace.txt` in the data directory, which is the way to get a permanent record. Command line options are listed in the chapter on running Singe; the ZeroBrane Studio integration in `zbstudio/` offers a debugger when printing is not enough.
[[traceheader]] [[traceheader]]
==== controllerSetPadding
[source,text]
----
controllerSetPadding(boolean)
----
Hypseus extension, accepted and ignored. See <<controllergetpadding,controllerGetPadding>> for why the offset it asks for does not exist in Singe. Turning it on without marking the events would be worse than leaving it off, because the game would then subtract an offset from switch codes that never carried one.
*Returns:* nothing.
*Since:* 3.00
*See also:* <<controllergetpadding,controllerGetPadding>>
==== The Trace Header ==== The Trace Header
Whichever of `--program` and `--trace` opened it, `trace.txt` begins with a Whichever of `--program` and `--trace` opened it, `trace.txt` begins with a
@ -4871,6 +4936,19 @@ end
The *disc* is the main laserdisc video, the one Singe was originally built to emulate. A game has at most one disc, opened at startup from the `VIDEO` named in `games.dat` or from `--disc` / `--framefile` on the command line; a game that names none runs without a disc (see <<withoutadisc,Games Without a Disc>>). All `disc*` functions operate on this single implicit disc and take no handle. Frame numbers are zero based positions in the video file (or in the combined framefile) and are the time reference for every branch decision in a laserdisc game. Without a disc the query functions return `0`, `discGetState` reports `DISC_EJECTED`, and the transport functions trace and do nothing. Extra clips layered on top of the disc are the job of the <<video,Video>> family. The *disc* is the main laserdisc video, the one Singe was originally built to emulate. A game has at most one disc, opened at startup from the `VIDEO` named in `games.dat` or from `--disc` / `--framefile` on the command line; a game that names none runs without a disc (see <<withoutadisc,Games Without a Disc>>). All `disc*` functions operate on this single implicit disc and take no handle. Frame numbers are zero based positions in the video file (or in the combined framefile) and are the time reference for every branch decision in a laserdisc game. Without a disc the query functions return `0`, `discGetState` reports `DISC_EJECTED`, and the transport functions trace and do nothing. Extra clips layered on top of the disc are the job of the <<video,Video>> family.
[#discaudio] [#discaudio]
==== drawTransparent
[source,text]
----
drawTransparent(boolean)
----
Hypseus extension, accepted and ignored. It decides whether Hypseus sets colour key 0 on the sprites loaded after it, which is how that engine carries transparency. Singe carries transparency in the alpha channel, as <<spriteresetcolorkey,`spriteResetColorKey`>> already describes, so there is no key to turn on or off.
*Returns:* nothing.
*Since:* 3.00
==== discAudio ==== discAudio
[source,text] [source,text]
@ -6670,6 +6748,20 @@ end
---- ----
[#guigetheight] [#guigetheight]
==== getUserString
[source,text]
----
id = getUserString()
----
Hypseus extension, always an empty string. Despite the name it is not a string the user set: Hypseus answers the machine install ID it sends with network statistics, taken from the Windows `MachineGuid` or the Linux machine ID. Singe sends nothing anywhere and will not hand a game a fingerprint of the machine it is running on.
*Returns:* a string, always empty.
*Since:* 3.00
*See also:* <<allowsocketcall,allowSocketCall>>
==== guiGetHeight ==== guiGetHeight
[source,text] [source,text]
@ -8796,6 +8888,20 @@ end
---- ----
[#mousegetposition] [#mousegetposition]
==== mouseGetPadding
[source,text]
----
padding = mouseGetPadding()
----
Hypseus extension, always `0`, for the reason <<controllergetpadding,`controllerGetPadding`>> gives. Hypseus adds this offset to the input codes its mice report in relative mode; Singe's codes carry no such offset, so there is nothing to subtract.
*Returns:* an integer, always `0`.
*Since:* 3.00
*See also:* <<controllergetpadding,controllerGetPadding>>
==== mouseGetPosition ==== mouseGetPosition
[source,text] [source,text]
@ -11136,6 +11242,19 @@ CABINET_H = overlayGetHeight() - MARGIN_Y - CABINET_Y
---- ----
[#setoverlaylinearscale] [#setoverlaylinearscale]
==== setOverlayFullAlpha
[source,text]
----
setOverlayFullAlpha()
----
Hypseus extension, accepted and ignored. Hypseus blits its overlay with the alpha channel thresholded at `128`, so a half-transparent pixel is either fully opaque or gone, and this asks it to upload the surface as it stands and blend properly instead. Singe's overlay has always been full RGBA with real per-pixel alpha, so what this asks for is already in force.
*Returns:* nothing.
*Since:* 3.00
==== setOverlayLinearScale ==== setOverlayLinearScale
[source,text] [source,text]
@ -14158,6 +14277,19 @@ Sprites are 2D bitmaps loaded from disk with `spriteLoad`, or rendered from text
*Sprite sheets.* Hypseus Singe extends the family with sprite sheets: `spriteLoadFrames` slices a single row strip of equal frames into an animation that is not playing, and `spriteDrawFrame` draws one chosen frame (1-based) without touching playback. A sheet is otherwise an ordinary animation, so `spriteSetFrame` (0-based), `spritePlay`, `spriteDraw`, `nodeSetSprite` and `emitterSetTexture` all accept it, and `spriteFrameWidth` and `spriteFrameHeight` report the unscaled size of one frame. The entries marked "Hypseus extension" exist so games written for Hypseus Singe run unchanged. *Sprite sheets.* Hypseus Singe extends the family with sprite sheets: `spriteLoadFrames` slices a single row strip of equal frames into an animation that is not playing, and `spriteDrawFrame` draws one chosen frame (1-based) without touching playback. A sheet is otherwise an ordinary animation, so `spriteSetFrame` (0-based), `spritePlay`, `spriteDraw`, `nodeSetSprite` and `emitterSetTexture` all accept it, and `spriteFrameWidth` and `spriteFrameHeight` report the unscaled size of one frame. The entries marked "Hypseus extension" exist so games written for Hypseus Singe run unchanged.
[#spritedraw] [#spritedraw]
==== spriteBlend
[source,text]
----
spriteBlend(boolean, sprite)
----
Hypseus extension, accepted and ignored. It is a workaround for that engine: Hypseus loads sprites with SDL's blend mode off, and this turns it back on for one sprite. Singe draws every sprite with its alpha channel already, so blending is never off to begin with. The sprite handle is still checked, so a bad one is still an error.
*Returns:* nothing.
*Since:* 3.00
==== spriteDraw ==== spriteDraw
[source,text] [source,text]
@ -16042,13 +16174,16 @@ end
[source,text] [source,text]
---- ----
left, right = videoGetVolume(id) left, right = videoGetVolume(id)
volume = videoGetVolume()
---- ----
Returns the stereo volume of a loaded video as two percentages. A freshly loaded video is at the `--volume_nonvldp` level on both channels (default `100`). Note that two values come back, left first. Returns the stereo volume of a loaded video as two percentages. A freshly loaded video is at the `--volume_nonvldp` level on both channels (default `100`). Note that two values come back, left first.
*Returns:* two integers, left and right, each `0` to `100`. Called with no argument it is a Hypseus extension answering the laserdisc's own volume instead, as a single number on Hypseus's `0` to `64` scale rather than as a percentage. Its games double that for <<musicsetvolume,`musicSetVolume`>>, whose range is `0` to `128`. The level follows `--volume_vldp`.
*Since:* 2.00 *Returns:* two integers, left and right, each `0` to `100`; or with no argument one integer, `0` to `64`.
*Since:* 2.00, the no-argument disc form 3.00
*See also:* <<videosetvolume,videoSetVolume>>, <<videoload,videoLoad>> *See also:* <<videosetvolume,videoSetVolume>>, <<videoload,videoLoad>>
.Example .Example
@ -16395,10 +16530,13 @@ videoPlay(attractVideo)
[source,text] [source,text]
---- ----
videoSetVolume(id, left, right) videoSetVolume(id, left, right)
videoSetVolume(volume)
---- ----
Sets the stereo volume of a loaded video as percentages. Values are clamped to `0` through `100` without complaint. The setting is remembered even for a silent clip and is reported back by `videoGetVolume`. Sets the stereo volume of a loaded video as percentages. Values are clamped to `0` through `100` without complaint. The setting is remembered even for a silent clip and is reported back by `videoGetVolume`.
Called with one argument it is a Hypseus extension setting the laserdisc's own volume instead, on Hypseus's `0` to `64` scale rather than as a percentage: the twin of the bare <<videogetvolume,`videoGetVolume()`>>. A level outside `0` to `64` is ignored rather than fatal, which is what Hypseus does with one.
*Parameters:* *Parameters:*
* `id` -- video handle. * `id` -- video handle.
@ -17264,6 +17402,11 @@ end
[#unimplementedandlegacy] [#unimplementedandlegacy]
=== Hypseus Compatibility === Hypseus Compatibility
IMPORTANT: Everything in this section exists so that a game written for Hypseus
Singe runs unchanged. *None of it is recommended for a new game.* Prefer the
Singe call each entry names: it is the one that will keep gaining features, and
it does not carry another engine's scales, argument orders or fixed answers.
Hypseus Singe registers a few names in its engine that Singe answers from Hypseus Singe registers a few names in its engine that Singe answers from
`Singe/Framework.singe` instead, so that a game written for Hypseus runs `Singe/Framework.singe` instead, so that a game written for Hypseus runs
unchanged. Each one is defined only when the engine does not already provide unchanged. Each one is defined only when the engine does not already provide

View file

@ -504,11 +504,17 @@ float4 fragmentMain(VertexOutput input) : SV_Target {
} else if (material.w > 0.5) { } else if (material.w > 0.5) {
albedo *= baseTexture.Sample(baseSampler, uv); albedo *= baseTexture.Sample(baseSampler, uv);
} }
// Alpha masking: a glTF MASK material keeps only the texels at or above its cutoff. Tested // Alpha masking: a glTF MASK material keeps only the texels at or above its cutoff, and what
// it keeps is fully opaque -- that is what MASK means, as against BLEND. Passing the sampled
// alpha on instead would let whatever sits behind the scene show through a leaf in proportion
// to it, which with a transparent background is the disc picture, tinting the foliage. Tested
// before any lighting, so a discarded texel costs nothing beyond the sample above. // before any lighting, so a discarded texel costs nothing beyond the sample above.
if ((maps.z > 0.0) && (albedo.a < maps.z)) { if (maps.z > 0.0) {
if (albedo.a < maps.z) {
discard; discard;
} }
albedo.a = 1.0;
}
if (material.z > 0.5) { if (material.z > 0.5) {
return float4(applyFog(albedo.rgb, input.worldPosition), albedo.a); return float4(applyFog(albedo.rgb, input.worldPosition), albedo.a);
} }

View file

@ -50,6 +50,11 @@ LUASOCKET_API int luaopen_socket_serial(lua_State *L);
int luaopen_luars232(lua_State *L); int luaopen_luars232(lua_State *L);
// Nor for lsqlite3. // Nor for lsqlite3.
int luaopen_lsqlite3(lua_State *L); int luaopen_lsqlite3(lua_State *L);
int luaopen_md5_core(lua_State *L);
int luaopen_bit(lua_State *L);
int luaopen_random(lua_State *L);
int luaopen_cjson(lua_State *L);
int luaopen_lpeg(lua_State *L);
// There is no header for ssl.config binding. Make our own. // There is no header for ssl.config binding. Make our own.
LSEC_API int luaopen_ssl_config(lua_State *L); LSEC_API int luaopen_ssl_config(lua_State *L);
@ -88,6 +93,7 @@ LSEC_API int luaopen_ssl_config(lua_State *L);
#define CONTROLLER_AXIS_COUNT 6 #define CONTROLLER_AXIS_COUNT 6
#define CONTROLLER_BUTTON_COUNT 15 #define CONTROLLER_BUTTON_COUNT 15
#define CONTROLLER_DEAD_ZONE_DEFAULT 15000 #define CONTROLLER_DEAD_ZONE_DEFAULT 15000
#define HYPSEUS_VOLUME_MAX 64 // What Hypseus's videoGetVolume() answers at full volume
#define CONTROLLER_TRIGGER_FIRST 4 // Gamepad axes 4 and 5 are the two analogue triggers #define CONTROLLER_TRIGGER_FIRST 4 // Gamepad axes 4 and 5 are the two analogue triggers
#define AXIS_VALUE_MAX 32767 // What SDL reports at full deflection, and the unit DEAD_ZONE counts in #define AXIS_VALUE_MAX 32767 // What SDL reports at full deflection, and the unit DEAD_ZONE counts in
#define PERCENT_FULL 100.0 // TRIGGER_THRESHOLD is a per cent of that full deflection, as Hypseus writes it #define PERCENT_FULL 100.0 // TRIGGER_THRESHOLD is a per cent of that full deflection, as Hypseus writes it
@ -863,6 +869,7 @@ static void _videoDestroy(VideoT *video);
static bool _watchedChanged(void); static bool _watchedChanged(void);
static void _watchFile(const char *name); static void _watchFile(const char *name);
static int32_t apiAllowSocketCall(lua_State *L);
static int32_t apiAnimationGetTime(lua_State *L); static int32_t apiAnimationGetTime(lua_State *L);
static int32_t apiAnimationIsPlaying(lua_State *L); static int32_t apiAnimationIsPlaying(lua_State *L);
static int32_t apiAnimationPause(lua_State *L); static int32_t apiAnimationPause(lua_State *L);
@ -899,8 +906,10 @@ static int32_t apiControllerDoRumble(lua_State *L);
static int32_t apiControllerGetAxis(lua_State *L); static int32_t apiControllerGetAxis(lua_State *L);
static int32_t apiControllerGetButton(lua_State *L); static int32_t apiControllerGetButton(lua_State *L);
static int32_t apiControllerGetName(lua_State *L); static int32_t apiControllerGetName(lua_State *L);
static int32_t apiControllerGetPadding(lua_State *L);
static int32_t apiControllerHowMany(lua_State *L); static int32_t apiControllerHowMany(lua_State *L);
static int32_t apiControllerIsValid(lua_State *L); static int32_t apiControllerIsValid(lua_State *L);
static int32_t apiControllerSetPadding(lua_State *L);
static int32_t apiDebugPrint(lua_State *L); static int32_t apiDebugPrint(lua_State *L);
static int32_t apiDiscAudio(lua_State *L); static int32_t apiDiscAudio(lua_State *L);
static int32_t apiDiscAudioSuffix(lua_State *L); static int32_t apiDiscAudioSuffix(lua_State *L);
@ -925,6 +934,7 @@ static int32_t apiDiscSkipToFrame(lua_State *L);
static int32_t apiDiscStepBackward(lua_State *L); static int32_t apiDiscStepBackward(lua_State *L);
static int32_t apiDiscStepForward(lua_State *L); static int32_t apiDiscStepForward(lua_State *L);
static int32_t apiDiscStop(lua_State *L); static int32_t apiDiscStop(lua_State *L);
static int32_t apiDrawTransparent(lua_State *L);
static int32_t apiEmitterBurst(lua_State *L); static int32_t apiEmitterBurst(lua_State *L);
static int32_t apiEmitterClear(lua_State *L); static int32_t apiEmitterClear(lua_State *L);
static int32_t apiEmitterDelete(lua_State *L); static int32_t apiEmitterDelete(lua_State *L);
@ -963,6 +973,7 @@ static int32_t apiFontSelect(lua_State *L);
static int32_t apiFontToSprite(lua_State *L); static int32_t apiFontToSprite(lua_State *L);
static int32_t apiFontUnload(lua_State *L); static int32_t apiFontUnload(lua_State *L);
static int32_t apiGetFValue(lua_State *L); static int32_t apiGetFValue(lua_State *L);
static int32_t apiGetUserString(lua_State *L);
static int32_t apiGuiClose(lua_State *L); static int32_t apiGuiClose(lua_State *L);
static int32_t apiGuiDelete(lua_State *L); static int32_t apiGuiDelete(lua_State *L);
static int32_t apiGuiDraw(lua_State *L); static int32_t apiGuiDraw(lua_State *L);
@ -1034,6 +1045,7 @@ static int32_t apiModelDelete(lua_State *L);
static int32_t apiModelGetAnimations(lua_State *L); static int32_t apiModelGetAnimations(lua_State *L);
static int32_t apiModelInstance(lua_State *L); static int32_t apiModelInstance(lua_State *L);
static int32_t apiModelLoad(lua_State *L); static int32_t apiModelLoad(lua_State *L);
static int32_t apiMouseGetPadding(lua_State *L);
static int32_t apiMusicIsPlaying(lua_State *L); static int32_t apiMusicIsPlaying(lua_State *L);
static int32_t apiMusicLoad(lua_State *L); static int32_t apiMusicLoad(lua_State *L);
static int32_t apiMusicPause(lua_State *L); static int32_t apiMusicPause(lua_State *L);
@ -1171,6 +1183,7 @@ static int32_t apiScoreBezelScore(lua_State *L);
static int32_t apiScoreBezelTwinScoreOn(lua_State *L); static int32_t apiScoreBezelTwinScoreOn(lua_State *L);
static int32_t apiScriptExecute(lua_State *L); static int32_t apiScriptExecute(lua_State *L);
static int32_t apiScriptPush(lua_State *L); static int32_t apiScriptPush(lua_State *L);
static int32_t apiSetOverlayFullAlpha(lua_State *L);
static int32_t apiSetOverlayLinearScale(lua_State *L); static int32_t apiSetOverlayLinearScale(lua_State *L);
static int32_t apiSetOverlayOnTop(lua_State *L); static int32_t apiSetOverlayOnTop(lua_State *L);
static int32_t apiSetOverlayOpacity(lua_State *L); static int32_t apiSetOverlayOpacity(lua_State *L);
@ -1219,6 +1232,7 @@ static int32_t apiSoundSetRange(lua_State *L);
static int32_t apiSoundSetVolume(lua_State *L); static int32_t apiSoundSetVolume(lua_State *L);
static int32_t apiSoundStop(lua_State *L); static int32_t apiSoundStop(lua_State *L);
static int32_t apiSoundUnload(lua_State *L); static int32_t apiSoundUnload(lua_State *L);
static int32_t apiSpriteBlend(lua_State *L);
static int32_t apiSpriteDraw(lua_State *L); static int32_t apiSpriteDraw(lua_State *L);
static int32_t apiSpriteDrawFrame(lua_State *L); static int32_t apiSpriteDrawFrame(lua_State *L);
static int32_t apiSpriteDrawGrid(lua_State *L); static int32_t apiSpriteDrawGrid(lua_State *L);
@ -1315,6 +1329,13 @@ static int32_t apiVldpSetVerbose(lua_State *L);
static const LuaModuleT _luaModules[] = { static const LuaModuleT _luaModules[] = {
// LuaFileSystem // LuaFileSystem
MODC("lfs", _luaopenLfs), MODC("lfs", _luaopenLfs),
// md5, the PUC-Rio library Hypseus bundles: sum, hexsum, exor, crypt, decrypt
MODC("md5", luaopen_md5_core),
// The rest of what Hypseus exposes, so a game written against it finds the same modules here
MODC("bit", luaopen_bit),
MODC("random", luaopen_random),
MODC("cjson", luaopen_cjson),
MODC("lpeg", luaopen_lpeg),
// SQLite for script data // SQLite for script data
MODC("sqlite3", luaopen_lsqlite3), MODC("sqlite3", luaopen_lsqlite3),
// LuaSocket // LuaSocket
@ -4853,6 +4874,7 @@ static void _readColor(lua_State *L, const char *method, SDL_Color *color, uint8
// Every Singe call a script may make. Comments give the version each call appeared in. // Every Singe call a script may make. Comments give the version each call appeared in.
static void _registerApi(lua_State *L) { static void _registerApi(lua_State *L) {
lua_register(L, "allowSocketCall", apiAllowSocketCall); // Hypseus
lua_register(L, "animationGetTime", apiAnimationGetTime); // 3.00 lua_register(L, "animationGetTime", apiAnimationGetTime); // 3.00
lua_register(L, "animationIsPlaying", apiAnimationIsPlaying); // 3.00 lua_register(L, "animationIsPlaying", apiAnimationIsPlaying); // 3.00
lua_register(L, "animationPause", apiAnimationPause); // 3.00 lua_register(L, "animationPause", apiAnimationPause); // 3.00
@ -4889,8 +4911,10 @@ static void _registerApi(lua_State *L) {
lua_register(L, "controllerGetAxis", apiControllerGetAxis); // 2.00 lua_register(L, "controllerGetAxis", apiControllerGetAxis); // 2.00
lua_register(L, "controllerGetButton", apiControllerGetButton); // 2.10 lua_register(L, "controllerGetButton", apiControllerGetButton); // 2.10
lua_register(L, "controllerGetName", apiControllerGetName); // 3.00 lua_register(L, "controllerGetName", apiControllerGetName); // 3.00
lua_register(L, "controllerGetPadding", apiControllerGetPadding); // Hypseus
lua_register(L, "controllerHowMany", apiControllerHowMany); // Hypseus lua_register(L, "controllerHowMany", apiControllerHowMany); // Hypseus
lua_register(L, "controllerIsValid", apiControllerIsValid); // Hypseus lua_register(L, "controllerIsValid", apiControllerIsValid); // Hypseus
lua_register(L, "controllerSetPadding", apiControllerSetPadding); // Hypseus
lua_register(L, "debugPrint", apiDebugPrint); // 1.xx lua_register(L, "debugPrint", apiDebugPrint); // 1.xx
@ -4919,6 +4943,7 @@ static void _registerApi(lua_State *L) {
lua_register(L, "discStepForward", apiDiscStepForward); // 1.xx lua_register(L, "discStepForward", apiDiscStepForward); // 1.xx
lua_register(L, "discStop", apiDiscStop); // 1.xx lua_register(L, "discStop", apiDiscStop); // 1.xx
lua_register(L, "drawTransparent", apiDrawTransparent); // Hypseus
lua_register(L, "emitterBurst", apiEmitterBurst); // 3.00 lua_register(L, "emitterBurst", apiEmitterBurst); // 3.00
lua_register(L, "emitterClear", apiEmitterClear); // 3.00 lua_register(L, "emitterClear", apiEmitterClear); // 3.00
lua_register(L, "emitterDelete", apiEmitterDelete); // 3.00 lua_register(L, "emitterDelete", apiEmitterDelete); // 3.00
@ -4957,6 +4982,7 @@ static void _registerApi(lua_State *L) {
lua_register(L, "fontToSprite", apiFontToSprite); // 1.xx lua_register(L, "fontToSprite", apiFontToSprite); // 1.xx
lua_register(L, "fontUnload", apiFontUnload); // 2.00 lua_register(L, "fontUnload", apiFontUnload); // 2.00
lua_register(L, "getFValue", apiGetFValue); // Hypseus lua_register(L, "getFValue", apiGetFValue); // Hypseus
lua_register(L, "getUserString", apiGetUserString); // Hypseus
lua_register(L, "guiClose", apiGuiClose); // 3.00 lua_register(L, "guiClose", apiGuiClose); // 3.00
lua_register(L, "guiDelete", apiGuiDelete); // 3.00 lua_register(L, "guiDelete", apiGuiDelete); // 3.00
lua_register(L, "guiDraw", apiGuiDraw); // 3.00 lua_register(L, "guiDraw", apiGuiDraw); // 3.00
@ -5030,6 +5056,7 @@ static void _registerApi(lua_State *L) {
lua_register(L, "modelInstance", apiModelInstance); // 3.00 lua_register(L, "modelInstance", apiModelInstance); // 3.00
lua_register(L, "modelLoad", apiModelLoad); // 3.00 lua_register(L, "modelLoad", apiModelLoad); // 3.00
lua_register(L, "mouseGetName", apiMouseGetName); // 3.00 lua_register(L, "mouseGetName", apiMouseGetName); // 3.00
lua_register(L, "mouseGetPadding", apiMouseGetPadding); // Hypseus
lua_register(L, "mouseGetPosition", apiMouseGetPosition); // 2.00 lua_register(L, "mouseGetPosition", apiMouseGetPosition); // 2.00
lua_register(L, "mouseHowMany", apiMouseHowMany); // 1.18 RDG lua_register(L, "mouseHowMany", apiMouseHowMany); // 1.18 RDG
lua_register(L, "mouseSetCaptured", apiMouseSetCaptured); // 2.00 lua_register(L, "mouseSetCaptured", apiMouseSetCaptured); // 2.00
@ -5168,6 +5195,7 @@ static void _registerApi(lua_State *L) {
lua_register(L, "scoreBezelTwinScoreOn", apiScoreBezelTwinScoreOn); // Hypseus lua_register(L, "scoreBezelTwinScoreOn", apiScoreBezelTwinScoreOn); // Hypseus
lua_register(L, "scriptExecute", apiScriptExecute); // 2.00 lua_register(L, "scriptExecute", apiScriptExecute); // 2.00
lua_register(L, "scriptPush", apiScriptPush); // 2.00 lua_register(L, "scriptPush", apiScriptPush); // 2.00
lua_register(L, "setOverlayFullAlpha", apiSetOverlayFullAlpha); // Hypseus
lua_register(L, "setOverlayLinearScale", apiSetOverlayLinearScale); // Hypseus lua_register(L, "setOverlayLinearScale", apiSetOverlayLinearScale); // Hypseus
lua_register(L, "setOverlayOnTop", apiSetOverlayOnTop); // Hypseus lua_register(L, "setOverlayOnTop", apiSetOverlayOnTop); // Hypseus
lua_register(L, "setOverlayOpacity", apiSetOverlayOpacity); // Hypseus lua_register(L, "setOverlayOpacity", apiSetOverlayOpacity); // Hypseus
@ -5219,6 +5247,7 @@ static void _registerApi(lua_State *L) {
lua_register(L, "soundStop", apiSoundStop); // 1.xx RDG lua_register(L, "soundStop", apiSoundStop); // 1.xx RDG
lua_register(L, "soundUnload", apiSoundUnload); // 2.00 lua_register(L, "soundUnload", apiSoundUnload); // 2.00
lua_register(L, "spriteBlend", apiSpriteBlend); // Hypseus
lua_register(L, "spriteDraw", apiSpriteDraw); // 1.xx Handle first since 3.00. lua_register(L, "spriteDraw", apiSpriteDraw); // 1.xx Handle first since 3.00.
lua_register(L, "spriteDrawFrame", apiSpriteDrawFrame); // Hypseus lua_register(L, "spriteDrawFrame", apiSpriteDrawFrame); // Hypseus
lua_register(L, "spriteDrawGrid", apiSpriteDrawGrid); // Hypseus lua_register(L, "spriteDrawGrid", apiSpriteDrawGrid); // Hypseus
@ -6943,6 +6972,19 @@ static void _watchFile(const char *name) {
// seconds = animationGetTime(node) // seconds = animationGetTime(node)
// allowSocketCall()
// Hypseus answers whether the user let it send data to a stats server, which -noserversend turns
// off; the sending itself is commented out there. Singe sends nothing anywhere, so the answer is
// false and stays false. It exists so a game that asks does not die on a nil call.
static int32_t apiAllowSocketCall(lua_State *L) {
_argCheck(L, "allowSocketCall", 0, 0);
lua_pushboolean(L, false);
_luaTrace(L, "allowSocketCall", "false");
return 1;
}
static int32_t apiAnimationGetTime(lua_State *L) { static int32_t apiAnimationGetTime(lua_State *L) {
int32_t root; int32_t root;
@ -7474,6 +7516,19 @@ static int32_t apiControllerGetName(lua_State *L) {
// count = controllerHowMany() Hypseus extension. Gamepads open in the four slots. // count = controllerHowMany() Hypseus extension. Gamepads open in the four slots.
// controllerGetPadding()
// Hypseus adds this offset to a switch code that came from a gamepad, so a game can tell which
// device pressed what and still recover the switch by subtracting it. Singe delivers gamepad input
// as ordinary mapped switches with no such mark, so the honest answer is zero: a game then takes
// its "not a gamepad" branch and works, rather than subtracting a number that means nothing here.
static int32_t apiControllerGetPadding(lua_State *L) {
_argCheck(L, "controllerGetPadding", 0, 0);
lua_pushinteger(L, 0);
_luaTrace(L, "controllerGetPadding", "0");
return 1;
}
static int32_t apiControllerHowMany(lua_State *L) { static int32_t apiControllerHowMany(lua_State *L) {
int32_t count = 0; int32_t count = 0;
int32_t x = 0; int32_t x = 0;
@ -7509,6 +7564,17 @@ static int32_t apiControllerIsValid(lua_State *L) {
} }
// controllerSetPadding(boolean)
// Accepted and ignored, as controllerGetPadding explains. Turning the offset on without marking
// the events would be worse than leaving it off: the game would subtract it from switch codes that
// never carried it.
static int32_t apiControllerSetPadding(lua_State *L) {
_argCheck(L, "controllerSetPadding", 1, 1);
_argBoolean(L, "controllerSetPadding", 1);
return 0;
}
// debugPrint(message) // debugPrint(message)
static int32_t apiDebugPrint(lua_State *L) { static int32_t apiDebugPrint(lua_State *L) {
const char *message = NULL; const char *message = NULL;
@ -7523,6 +7589,18 @@ static int32_t apiDebugPrint(lua_State *L) {
// discAudio(channel, enabled) Channel 1 is left, 2 is right. // discAudio(channel, enabled) Channel 1 is left, 2 is right.
// drawTransparent(boolean)
// Accepted and ignored. It decides whether Hypseus sets colour key 0 on the sprites loaded after
// it, which is how that engine carries transparency. Singe carries it in the alpha channel, as
// spriteResetColorKey already documents, so there is no key to turn on or off.
static int32_t apiDrawTransparent(lua_State *L) {
_argCheck(L, "drawTransparent", 1, 1);
_argBoolean(L, "drawTransparent", 1);
return 0;
}
static int32_t apiDiscAudio(lua_State *L) { static int32_t apiDiscAudio(lua_State *L) {
int32_t channel = 0; int32_t channel = 0;
int32_t left = 0; int32_t left = 0;
@ -8336,6 +8414,19 @@ static int32_t apiGuiDrawScreen(lua_State *L) {
} }
// getUserString()
// Always empty. Despite the name it is not a user string: Hypseus answers the machine install ID
// it sends with network statistics, from the Windows MachineGuid or the Linux machine-id. Singe
// sends nothing anywhere and will not hand a game a fingerprint of the machine it runs on.
static int32_t apiGetUserString(lua_State *L) {
_argCheck(L, "getUserString", 0, 0);
lua_pushstring(L, "");
_luaTrace(L, "getUserString", "empty");
return 1;
}
static int32_t apiGuiGetHeight(lua_State *L) { static int32_t apiGuiGetHeight(lua_State *L) {
_argCheck(L, "guiGetHeight", 1, 1); _argCheck(L, "guiGetHeight", 1, 1);
lua_pushinteger(L, guiGetHeight(_argGui(L, "guiGetHeight", 1))); lua_pushinteger(L, guiGetHeight(_argGui(L, "guiGetHeight", 1)));
@ -8650,7 +8741,6 @@ static int32_t apiKeyboardGetLastUp(lua_State *L) {
} }
// mode = keyboardGetMode()
static int32_t apiKeyboardGetMode(lua_State *L) { static int32_t apiKeyboardGetMode(lua_State *L) {
_luaTrace(L, "keyboardGetMode", "%d", _global.keyboardMode); _luaTrace(L, "keyboardGetMode", "%d", _global.keyboardMode);
lua_pushinteger(L, _global.keyboardMode); lua_pushinteger(L, _global.keyboardMode);
@ -9581,6 +9671,18 @@ static int32_t apiMouseGetName(lua_State *L) {
// x, y = mouseGetPosition(mouse) // x, y = mouseGetPosition(mouse)
// mouseGetPadding()
// Always 0, for the reason controllerGetPadding gives: Hypseus adds this offset to the input codes
// its mice report in relative mode, and Singe's codes carry no such offset to subtract.
static int32_t apiMouseGetPadding(lua_State *L) {
_argCheck(L, "mouseGetPadding", 0, 0);
lua_pushinteger(L, 0);
_luaTrace(L, "mouseGetPadding", "0");
return 1;
}
static int32_t apiMouseGetPosition(lua_State *L) { static int32_t apiMouseGetPosition(lua_State *L) {
int32_t m = 0; int32_t m = 0;
int32_t x = 0; int32_t x = 0;
@ -11006,7 +11108,6 @@ static int32_t apiRatioGetY(lua_State *L) {
} }
// sceneEnable(bool): turns the 3D layer on or off
static int32_t apiSceneEnable(lua_State *L) { static int32_t apiSceneEnable(lua_State *L) {
bool enabled; bool enabled;
@ -11363,7 +11464,13 @@ static int32_t apiScriptPush(lua_State *L) {
} }
// setOverlayLinearScale(enabled) Hypseus extension. Smooths the overlay as it is scaled to the window instead of blocking it up. static int32_t apiSetOverlayFullAlpha(lua_State *L) {
_argCheck(L, "setOverlayFullAlpha", 0, 0);
return 0;
}
static int32_t apiSetOverlayLinearScale(lua_State *L) { static int32_t apiSetOverlayLinearScale(lua_State *L) {
bool enabled = false; bool enabled = false;
@ -12010,6 +12117,18 @@ static int32_t apiSoundUnload(lua_State *L) {
// spriteDraw(id, x, y[, centered]) - Draw at natural size // spriteDraw(id, x, y[, centered]) - Draw at natural size
// spriteDraw(id, x, y, x2, y2[, centered]) - Stretch into the rectangle // spriteDraw(id, x, y, x2, y2[, centered]) - Stretch into the rectangle
// spriteBlend(boolean, id)
// Accepted and ignored. It is a Hypseus workaround: that engine loads sprites with SDL's blend
// mode off, and this turns it back on per sprite. Singe draws every sprite with its alpha already.
static int32_t apiSpriteBlend(lua_State *L) {
_argCheck(L, "spriteBlend", 2, 2);
_argBoolean(L, "spriteBlend", 1);
_argSprite(L, "spriteBlend", 2);
return 0;
}
static int32_t apiSpriteDraw(lua_State *L) { static int32_t apiSpriteDraw(lua_State *L) {
int32_t n = lua_gettop(L); int32_t n = lua_gettop(L);
bool center = false; bool center = false;
@ -12294,7 +12413,6 @@ static int32_t apiSpriteIsPlaying(lua_State *L) {
} }
// id = spriteLoad(filename) Animated GIF and WEBP files load as animations.
static int32_t apiSpriteLoad(lua_State *L) { static int32_t apiSpriteLoad(lua_State *L) {
const char *name = NULL; const char *name = NULL;
SpriteT *sprite = NULL; SpriteT *sprite = NULL;
@ -13073,13 +13191,25 @@ static int32_t apiVideoGetLanguageDescription(lua_State *L) {
} }
// left, right = videoGetVolume(id) // left, right = videoGetVolume(id), or volume = videoGetVolume() for the laserdisc
static int32_t apiVideoGetVolume(lua_State *L) { static int32_t apiVideoGetVolume(lua_State *L) {
VideoT *video = NULL; VideoT *video = NULL;
int32_t left = 0; int32_t left = 0;
int32_t right = 0; int32_t right = 0;
_argCheck(L, "videoGetVolume", 1, 1); _argCheck(L, "videoGetVolume", 0, 1);
// Hypseus extension: no argument answers the laserdisc's own volume, on the 0 to 64 scale its
// games expect -- they double it for musicSetVolume, whose range is 0 to 128, and a level
// outside that ends the script. Singe keeps the disc volume as a percentage, so it is scaled
// here rather than kept twice.
if (lua_gettop(L) == 0) {
int32_t level = (_global.conf->volumeVldp * HYPSEUS_VOLUME_MAX) / VOLUME_MAX;
_luaTrace(L, "videoGetVolume", "disc %d", level);
lua_pushinteger(L, level);
return 1;
}
video = _argVideo(L, "videoGetVolume", 1); video = _argVideo(L, "videoGetVolume", 1);
videoGetVolume(video->handle, &left, &right); videoGetVolume(video->handle, &left, &right);
_luaTrace(L, "videoGetVolume", "%d %d %d", video->id, left, right); _luaTrace(L, "videoGetVolume", "%d %d %d", video->id, left, right);
@ -13301,7 +13431,29 @@ static int32_t apiVideoSetVolume(lua_State *L) {
int32_t left = 0; int32_t left = 0;
int32_t right = 0; int32_t right = 0;
_argCheck(L, "videoSetVolume", 3, 3); _argCheck(L, "videoSetVolume", 1, 3);
// Hypseus extension: one argument sets the laserdisc's own volume on its 0 to 64 scale, the
// twin of the bare videoGetVolume(). Hypseus ignores a level outside that range with a warning
// rather than stopping the script, and so does this: a game that oversteps keeps playing.
if (lua_gettop(L) == 1) {
int32_t level = _argInteger(L, "videoSetVolume", 1);
if ((level < 0) || (level > HYPSEUS_VOLUME_MAX)) {
_luaTrace(L, "videoSetVolume", "disc %d out of range, ignored", level);
return 0;
}
_global.conf->volumeVldp = (level * VOLUME_MAX) / HYPSEUS_VOLUME_MAX;
if (_global.videoHandle >= 0) {
videoSetVolume(_global.videoHandle, _global.conf->volumeVldp, _global.conf->volumeVldp);
}
_luaTrace(L, "videoSetVolume", "disc %d (%d percent)", level, _global.conf->volumeVldp);
return 0;
}
if (lua_gettop(L) != 3) {
_luaDie(L, "videoSetVolume", "Expected 1 or 3 arguments, got %d.", lua_gettop(L));
}
video = _argVideo(L, "videoSetVolume", 1); video = _argVideo(L, "videoSetVolume", 1);
left = _argInteger(L, "videoSetVolume", 2); left = _argInteger(L, "videoSetVolume", 2);
right = _argInteger(L, "videoSetVolume", 3); right = _argInteger(L, "videoSetVolume", 3);

BIN
testScripts/Models/Sponza.glb (Stored with Git LFS)

Binary file not shown.

8
thirdparty/lpeg/LICENSE vendored Normal file
View file

@ -0,0 +1,8 @@
License
Copyright © 2007-2023 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

612
thirdparty/lpeg/lpcap.c vendored Normal file
View file

@ -0,0 +1,612 @@
#include "lua.h"
#include "lauxlib.h"
#include "lpcap.h"
#include "lpprint.h"
#include "lptypes.h"
#define getfromktable(cs,v) lua_rawgeti((cs)->L, ktableidx((cs)->ptop), v)
#define pushluaval(cs) getfromktable(cs, (cs)->cap->idx)
#define skipclose(cs,head) \
if (isopencap(head)) { assert(isclosecap(cs->cap)); cs->cap++; }
/*
** Return the size of capture 'cap'. If it is an open capture, 'close'
** must be its corresponding close.
*/
static Index_t capsize (Capture *cap, Capture *close) {
if (isopencap(cap)) {
assert(isclosecap(close));
return close->index - cap->index;
}
else
return cap->siz - 1;
}
static Index_t closesize (CapState *cs, Capture *head) {
return capsize(head, cs->cap);
}
/*
** Put at the cache for Lua values the value indexed by 'v' in ktable
** of the running pattern (if it is not there yet); returns its index.
*/
static int updatecache (CapState *cs, int v) {
int idx = cs->ptop + 1; /* stack index of cache for Lua values */
if (v != cs->valuecached) { /* not there? */
getfromktable(cs, v); /* get value from 'ktable' */
lua_replace(cs->L, idx); /* put it at reserved stack position */
cs->valuecached = v; /* keep track of what is there */
}
return idx;
}
static int pushcapture (CapState *cs);
/*
** Goes back in a list of captures looking for an open capture
** corresponding to a close one.
*/
static Capture *findopen (Capture *cap) {
int n = 0; /* number of closes waiting an open */
for (;;) {
cap--;
if (isclosecap(cap)) n++; /* one more open to skip */
else if (isopencap(cap))
if (n-- == 0) return cap;
}
}
/*
** Go to the next capture at the same level.
*/
static void nextcap (CapState *cs) {
Capture *cap = cs->cap;
if (isopencap(cap)) { /* must look for a close? */
int n = 0; /* number of opens waiting a close */
for (;;) { /* look for corresponding close */
cap++;
if (isopencap(cap)) n++;
else if (isclosecap(cap))
if (n-- == 0) break;
}
cs->cap = cap + 1; /* + 1 to skip last close */
}
else {
Capture *next;
for (next = cap + 1; capinside(cap, next); next++)
; /* skip captures inside current one */
cs->cap = next;
}
}
/*
** Push on the Lua stack all values generated by nested captures inside
** the current capture. Returns number of values pushed. 'addextra'
** makes it push the entire match after all captured values. The
** entire match is pushed also if there are no other nested values,
** so the function never returns zero.
*/
static int pushnestedvalues (CapState *cs, int addextra) {
Capture *head = cs->cap++; /* original capture */
int n = 0; /* number of pushed subvalues */
/* repeat for all nested patterns */
while (capinside(head, cs->cap))
n += pushcapture(cs);
if (addextra || n == 0) { /* need extra? */
lua_pushlstring(cs->L, cs->s + head->index, closesize(cs, head));
n++;
}
skipclose(cs, head);
return n;
}
/*
** Push only the first value generated by nested captures
*/
static void pushonenestedvalue (CapState *cs) {
int n = pushnestedvalues(cs, 0);
if (n > 1)
lua_pop(cs->L, n - 1); /* pop extra values */
}
/*
** Checks whether group 'grp' is visible to 'ref', that is, 'grp' is
** not nested inside a full capture that does not contain 'ref'. (We
** only need to care for full captures because the search at 'findback'
** skips open-end blocks; so, if 'grp' is nested in a non-full capture,
** 'ref' is also inside it.) To check this, we search backward for the
** inner full capture enclosing 'grp'. A full capture cannot contain
** non-full captures, so a close capture means we cannot be inside a
** full capture anymore.
*/
static int capvisible (CapState *cs, Capture *grp, Capture *ref) {
Capture *cap = grp;
int i = MAXLOP; /* maximum distance for an 'open' */
while (i-- > 0 && cap-- > cs->ocap) {
if (isclosecap(cap))
return 1; /* can stop the search */
else if (grp->index - cap->index >= UCHAR_MAX)
return 1; /* can stop the search */
else if (capinside(cap, grp)) /* is 'grp' inside cap? */
return capinside(cap, ref); /* ok iff cap also contains 'ref' */
}
return 1; /* 'grp' is not inside any capture */
}
/*
** Try to find a named group capture with the name given at the top of
** the stack; goes backward from 'ref'.
*/
static Capture *findback (CapState *cs, Capture *ref) {
lua_State *L = cs->L;
Capture *cap = ref;
while (cap-- > cs->ocap) { /* repeat until end of list */
if (isclosecap(cap))
cap = findopen(cap); /* skip nested captures */
else if (capinside(cap, ref))
continue; /* enclosing captures are not visible to 'ref' */
if (captype(cap) == Cgroup && capvisible(cs, cap, ref)) {
getfromktable(cs, cap->idx); /* get group name */
if (lp_equal(L, -2, -1)) { /* right group? */
lua_pop(L, 2); /* remove reference name and group name */
return cap;
}
else lua_pop(L, 1); /* remove group name */
}
}
luaL_error(L, "back reference '%s' not found", lua_tostring(L, -1));
return NULL; /* to avoid warnings */
}
/*
** Back-reference capture. Return number of values pushed.
*/
static int backrefcap (CapState *cs) {
int n;
Capture *curr = cs->cap;
pushluaval(cs); /* reference name */
cs->cap = findback(cs, curr); /* find corresponding group */
n = pushnestedvalues(cs, 0); /* push group's values */
cs->cap = curr + 1;
return n;
}
/*
** Table capture: creates a new table and populates it with nested
** captures.
*/
static int tablecap (CapState *cs) {
lua_State *L = cs->L;
Capture *head = cs->cap++;
int n = 0;
lua_newtable(L);
while (capinside(head, cs->cap)) {
if (captype(cs->cap) == Cgroup && cs->cap->idx != 0) { /* named group? */
pushluaval(cs); /* push group name */
pushonenestedvalue(cs);
lua_settable(L, -3);
}
else { /* not a named group */
int i;
int k = pushcapture(cs);
for (i = k; i > 0; i--) /* store all values into table */
lua_rawseti(L, -(i + 1), n + i);
n += k;
}
}
skipclose(cs, head);
return 1; /* number of values pushed (only the table) */
}
/*
** Table-query capture
*/
static int querycap (CapState *cs) {
int idx = cs->cap->idx;
pushonenestedvalue(cs); /* get nested capture */
lua_gettable(cs->L, updatecache(cs, idx)); /* query cap. value at table */
if (!lua_isnil(cs->L, -1))
return 1;
else { /* no value */
lua_pop(cs->L, 1); /* remove nil */
return 0;
}
}
/*
** Fold capture
*/
static int foldcap (CapState *cs) {
int n;
lua_State *L = cs->L;
Capture *head = cs->cap++;
int idx = head->idx;
if (isclosecap(cs->cap) || /* no nested captures (large subject)? */
(n = pushcapture(cs)) == 0) /* nested captures with no values? */
return luaL_error(L, "no initial value for fold capture");
if (n > 1)
lua_pop(L, n - 1); /* leave only one result for accumulator */
while (capinside(head, cs->cap)) {
lua_pushvalue(L, updatecache(cs, idx)); /* get folding function */
lua_insert(L, -2); /* put it before accumulator */
n = pushcapture(cs); /* get next capture's values */
lua_call(L, n + 1, 1); /* call folding function */
}
skipclose(cs, head);
return 1; /* only accumulator left on the stack */
}
/*
** Function capture
*/
static int functioncap (CapState *cs) {
int n;
int top = lua_gettop(cs->L);
pushluaval(cs); /* push function */
n = pushnestedvalues(cs, 0); /* push nested captures */
lua_call(cs->L, n, LUA_MULTRET); /* call function */
return lua_gettop(cs->L) - top; /* return function's results */
}
/*
** Accumulator capture
*/
static int accumulatorcap (CapState *cs) {
lua_State *L = cs->L;
int n;
if (lua_gettop(L) < cs->firstcap)
luaL_error(L, "no previous value for accumulator capture");
pushluaval(cs); /* push function */
lua_insert(L, -2); /* previous value becomes first argument */
n = pushnestedvalues(cs, 0); /* push nested captures */
lua_call(L, n + 1, 1); /* call function */
return 0; /* did not add any extra value */
}
/*
** Select capture
*/
static int numcap (CapState *cs) {
int idx = cs->cap->idx; /* value to select */
if (idx == 0) { /* no values? */
nextcap(cs); /* skip entire capture */
return 0; /* no value produced */
}
else {
int n = pushnestedvalues(cs, 0);
if (n < idx) /* invalid index? */
return luaL_error(cs->L, "no capture '%d'", idx);
else {
lua_pushvalue(cs->L, -(n - idx + 1)); /* get selected capture */
lua_replace(cs->L, -(n + 1)); /* put it in place of 1st capture */
lua_pop(cs->L, n - 1); /* remove other captures */
return 1;
}
}
}
/*
** Return the stack index of the first runtime capture in the given
** list of captures (or zero if no runtime captures)
*/
int finddyncap (Capture *cap, Capture *last) {
for (; cap < last; cap++) {
if (cap->kind == Cruntime)
return cap->idx; /* stack position of first capture */
}
return 0; /* no dynamic captures in this segment */
}
/*
** Calls a runtime capture. Returns number of captures "removed" by the
** call, that is, those inside the group capture. Captures to be added
** are on the Lua stack.
*/
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
int n, id;
lua_State *L = cs->L;
int otop = lua_gettop(L);
Capture *open = findopen(close); /* get open group capture */
assert(captype(open) == Cgroup);
id = finddyncap(open, close); /* get first dynamic capture argument */
close->kind = Cclose; /* closes the group */
close->index = s - cs->s;
cs->cap = open; cs->valuecached = 0; /* prepare capture state */
luaL_checkstack(L, 4, "too many runtime captures");
pushluaval(cs); /* push function to be called */
lua_pushvalue(L, SUBJIDX); /* push original subject */
lua_pushinteger(L, s - cs->s + 1); /* push current position */
n = pushnestedvalues(cs, 0); /* push nested captures */
lua_call(L, n + 2, LUA_MULTRET); /* call dynamic function */
if (id > 0) { /* are there old dynamic captures to be removed? */
int i;
for (i = id; i <= otop; i++)
lua_remove(L, id); /* remove old dynamic captures */
*rem = otop - id + 1; /* total number of dynamic captures removed */
}
else
*rem = 0; /* no dynamic captures removed */
return close - open - 1; /* number of captures to be removed */
}
/*
** Auxiliary structure for substitution and string captures: keep
** information about nested captures for future use, avoiding to push
** string results into Lua
*/
typedef struct StrAux {
int isstring; /* whether capture is a string */
union {
Capture *cp; /* if not a string, respective capture */
struct { /* if it is a string... */
Index_t idx; /* starts here */
Index_t siz; /* with this size */
} s;
} u;
} StrAux;
#define MAXSTRCAPS 10
/*
** Collect values from current capture into array 'cps'. Current
** capture must be Cstring (first call) or Csimple (recursive calls).
** (In first call, fills %0 with whole match for Cstring.)
** Returns number of elements in the array that were filled.
*/
static int getstrcaps (CapState *cs, StrAux *cps, int n) {
int k = n++;
Capture *head = cs->cap++;
cps[k].isstring = 1; /* get string value */
cps[k].u.s.idx = head->index; /* starts here */
while (capinside(head, cs->cap)) {
if (n >= MAXSTRCAPS) /* too many captures? */
nextcap(cs); /* skip extra captures (will not need them) */
else if (captype(cs->cap) == Csimple) /* string? */
n = getstrcaps(cs, cps, n); /* put info. into array */
else {
cps[n].isstring = 0; /* not a string */
cps[n].u.cp = cs->cap; /* keep original capture */
nextcap(cs);
n++;
}
}
cps[k].u.s.siz = closesize(cs, head);
skipclose(cs, head);
return n;
}
/*
** add next capture value (which should be a string) to buffer 'b'
*/
static int addonestring (luaL_Buffer *b, CapState *cs, const char *what);
/*
** String capture: add result to buffer 'b' (instead of pushing
** it into the stack)
*/
static void stringcap (luaL_Buffer *b, CapState *cs) {
StrAux cps[MAXSTRCAPS];
int n;
size_t len, i;
const char *fmt; /* format string */
fmt = lua_tolstring(cs->L, updatecache(cs, cs->cap->idx), &len);
n = getstrcaps(cs, cps, 0) - 1; /* collect nested captures */
for (i = 0; i < len; i++) { /* traverse format string */
if (fmt[i] != '%') /* not an escape? */
luaL_addchar(b, fmt[i]); /* add it to buffer */
else if (fmt[++i] < '0' || fmt[i] > '9') /* not followed by a digit? */
luaL_addchar(b, fmt[i]); /* add to buffer */
else {
int l = fmt[i] - '0'; /* capture index */
if (l > n)
luaL_error(cs->L, "invalid capture index (%d)", l);
else if (cps[l].isstring)
luaL_addlstring(b, cs->s + cps[l].u.s.idx, cps[l].u.s.siz);
else {
Capture *curr = cs->cap;
cs->cap = cps[l].u.cp; /* go back to evaluate that nested capture */
if (!addonestring(b, cs, "capture"))
luaL_error(cs->L, "no values in capture index %d", l);
cs->cap = curr; /* continue from where it stopped */
}
}
}
}
/*
** Substitution capture: add result to buffer 'b'
*/
static void substcap (luaL_Buffer *b, CapState *cs) {
const char *curr = cs->s + cs->cap->index;
Capture *head = cs->cap++;
while (capinside(head, cs->cap)) {
Capture *cap = cs->cap;
const char *caps = cs->s + cap->index;
luaL_addlstring(b, curr, caps - curr); /* add text up to capture */
if (addonestring(b, cs, "replacement"))
curr = caps + capsize(cap, cs->cap - 1); /* continue after match */
else /* no capture value */
curr = caps; /* keep original text in final result */
}
/* add last piece of text */
luaL_addlstring(b, curr, cs->s + head->index + closesize(cs, head) - curr);
skipclose(cs, head);
}
/*
** Evaluates a capture and adds its first value to buffer 'b'; returns
** whether there was a value
*/
static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) {
switch (captype(cs->cap)) {
case Cstring:
stringcap(b, cs); /* add capture directly to buffer */
return 1;
case Csubst:
substcap(b, cs); /* add capture directly to buffer */
return 1;
case Cacc: /* accumulator capture? */
return luaL_error(cs->L, "invalid context for an accumulator capture");
default: {
lua_State *L = cs->L;
int n = pushcapture(cs);
if (n > 0) {
if (n > 1) lua_pop(L, n - 1); /* only one result */
if (!lua_isstring(L, -1))
return luaL_error(L, "invalid %s value (a %s)",
what, luaL_typename(L, -1));
luaL_addvalue(b);
}
return n;
}
}
}
#if !defined(MAXRECLEVEL)
#define MAXRECLEVEL 200
#endif
/*
** Push all values of the current capture into the stack; returns
** number of values pushed
*/
static int pushcapture (CapState *cs) {
lua_State *L = cs->L;
int res;
luaL_checkstack(L, 4, "too many captures");
if (cs->reclevel++ > MAXRECLEVEL)
return luaL_error(L, "subcapture nesting too deep");
switch (captype(cs->cap)) {
case Cposition: {
lua_pushinteger(L, cs->cap->index + 1);
cs->cap++;
res = 1;
break;
}
case Cconst: {
pushluaval(cs);
cs->cap++;
res = 1;
break;
}
case Carg: {
int arg = (cs->cap++)->idx;
if (arg + FIXEDARGS > cs->ptop)
return luaL_error(L, "reference to absent extra argument #%d", arg);
lua_pushvalue(L, arg + FIXEDARGS);
res = 1;
break;
}
case Csimple: {
int k = pushnestedvalues(cs, 1);
lua_insert(L, -k); /* make whole match be first result */
res = k;
break;
}
case Cruntime: {
lua_pushvalue(L, (cs->cap++)->idx); /* value is in the stack */
res = 1;
break;
}
case Cstring: {
luaL_Buffer b;
luaL_buffinit(L, &b);
stringcap(&b, cs);
luaL_pushresult(&b);
res = 1;
break;
}
case Csubst: {
luaL_Buffer b;
luaL_buffinit(L, &b);
substcap(&b, cs);
luaL_pushresult(&b);
res = 1;
break;
}
case Cgroup: {
if (cs->cap->idx == 0) /* anonymous group? */
res = pushnestedvalues(cs, 0); /* add all nested values */
else { /* named group: add no values */
nextcap(cs); /* skip capture */
res = 0;
}
break;
}
case Cbackref: res = backrefcap(cs); break;
case Ctable: res = tablecap(cs); break;
case Cfunction: res = functioncap(cs); break;
case Cacc: res = accumulatorcap(cs); break;
case Cnum: res = numcap(cs); break;
case Cquery: res = querycap(cs); break;
case Cfold: res = foldcap(cs); break;
default: assert(0); res = 0;
}
cs->reclevel--;
return res;
}
/*
** Prepare a CapState structure and traverse the entire list of
** captures in the stack pushing its results. 's' is the subject
** string, 'r' is the final position of the match, and 'ptop'
** the index in the stack where some useful values were pushed.
** Returns the number of results pushed. (If the list produces no
** results, push the final position of the match.)
*/
int getcaptures (lua_State *L, const char *s, const char *r, int ptop) {
Capture *capture = (Capture *)lua_touserdata(L, caplistidx(ptop));
int n = 0;
/* printcaplist(capture); */
if (!isclosecap(capture)) { /* is there any capture? */
CapState cs;
cs.ocap = cs.cap = capture; cs.L = L; cs.reclevel = 0;
cs.s = s; cs.valuecached = 0; cs.ptop = ptop;
cs.firstcap = lua_gettop(L) + 1; /* where first value (if any) will go */
do { /* collect their values */
n += pushcapture(&cs);
} while (!isclosecap(cs.cap));
assert(lua_gettop(L) - cs.firstcap == n - 1);
}
if (n == 0) { /* no capture values? */
lua_pushinteger(L, r - s + 1); /* return only end position */
n = 1;
}
return n;
}

86
thirdparty/lpeg/lpcap.h vendored Normal file
View file

@ -0,0 +1,86 @@
#if !defined(lpcap_h)
#define lpcap_h
#include "lptypes.h"
/* kinds of captures */
typedef enum CapKind {
Cclose, /* not used in trees */
Cposition,
Cconst, /* ktable[key] is Lua constant */
Cbackref, /* ktable[key] is "name" of group to get capture */
Carg, /* 'key' is arg's number */
Csimple, /* next node is pattern */
Ctable, /* next node is pattern */
Cfunction, /* ktable[key] is function; next node is pattern */
Cacc, /* ktable[key] is function; next node is pattern */
Cquery, /* ktable[key] is table; next node is pattern */
Cstring, /* ktable[key] is string; next node is pattern */
Cnum, /* numbered capture; 'key' is number of value to return */
Csubst, /* substitution capture; next node is pattern */
Cfold, /* ktable[key] is function; next node is pattern */
Cruntime, /* not used in trees (is uses another type for tree) */
Cgroup /* ktable[key] is group's "name" */
} CapKind;
/*
** An unsigned integer large enough to index any subject entirely.
** It can be size_t, but that will double the size of the array
** of captures in a 64-bit machine.
*/
#if !defined(Index_t)
typedef uint Index_t;
#endif
#define MAXINDT (~(Index_t)0)
typedef struct Capture {
Index_t index; /* subject position */
unsigned short idx; /* extra info (group name, arg index, etc.) */
byte kind; /* kind of capture */
byte siz; /* size of full capture + 1 (0 = not a full capture) */
} Capture;
typedef struct CapState {
Capture *cap; /* current capture */
Capture *ocap; /* (original) capture list */
lua_State *L;
int ptop; /* stack index of last argument to 'match' */
int firstcap; /* stack index of first capture pushed in the stack */
const char *s; /* original string */
int valuecached; /* value stored in cache slot */
int reclevel; /* recursion level */
} CapState;
#define captype(cap) ((cap)->kind)
#define isclosecap(cap) (captype(cap) == Cclose)
#define isopencap(cap) ((cap)->siz == 0)
/* true if c2 is (any number of levels) inside c1 */
#define capinside(c1,c2) \
(isopencap(c1) ? !isclosecap(c2) \
: (c2)->index < (c1)->index + (c1)->siz - 1)
/**
** Maximum number of captures to visit when looking for an 'open'.
*/
#define MAXLOP 20
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem);
int getcaptures (lua_State *L, const char *s, const char *r, int ptop);
int finddyncap (Capture *cap, Capture *last);
#endif

1051
thirdparty/lpeg/lpcode.c vendored Normal file

File diff suppressed because it is too large Load diff

36
thirdparty/lpeg/lpcode.h vendored Normal file
View file

@ -0,0 +1,36 @@
#if !defined(lpcode_h)
#define lpcode_h
#include "lua.h"
#include "lptypes.h"
#include "lptree.h"
#include "lpvm.h"
int checkaux (TTree *tree, int pred);
int fixedlen (TTree *tree);
int hascaptures (TTree *tree);
int lp_gc (lua_State *L);
Instruction *compile (lua_State *L, Pattern *p, uint size);
void freecode (lua_State *L, Pattern *p);
int sizei (const Instruction *i);
#define PEnullable 0
#define PEnofail 1
/*
** nofail(t) implies that 't' cannot fail with any input
*/
#define nofail(t) checkaux(t, PEnofail)
/*
** (not nullable(t)) implies 't' cannot match without consuming
** something
*/
#define nullable(t) checkaux(t, PEnullable)
#endif

110
thirdparty/lpeg/lpcset.c vendored Normal file
View file

@ -0,0 +1,110 @@
#include "lptypes.h"
#include "lpcset.h"
/*
** Add to 'c' the index of the (only) bit set in byte 'b'
*/
static int onlybit (int c, int b) {
if ((b & 0xF0) != 0) { c += 4; b >>= 4; }
if ((b & 0x0C) != 0) { c += 2; b >>= 2; }
if ((b & 0x02) != 0) { c += 1; }
return c;
}
/*
** Check whether a charset is empty (returns IFail), singleton (IChar),
** full (IAny), or none of those (ISet). When singleton, 'info.offset'
** returns which character it is. When generic set, 'info' returns
** information about its range.
*/
Opcode charsettype (const byte *cs, charsetinfo *info) {
int low0, low1, high0, high1;
for (low1 = 0; low1 < CHARSETSIZE && cs[low1] == 0; low1++)
/* find lowest byte with a 1-bit */;
if (low1 == CHARSETSIZE)
return IFail; /* no characters in set */
for (high1 = CHARSETSIZE - 1; cs[high1] == 0; high1--)
/* find highest byte with a 1-bit; low1 is a sentinel */;
if (low1 == high1) { /* only one byte with 1-bits? */
int b = cs[low1];
if ((b & (b - 1)) == 0) { /* does byte has only one 1-bit? */
info->offset = onlybit(low1 * BITSPERCHAR, b); /* get that bit */
return IChar; /* single character */
}
}
for (low0 = 0; low0 < CHARSETSIZE && cs[low0] == 0xFF; low0++)
/* find lowest byte with a 0-bit */;
if (low0 == CHARSETSIZE)
return IAny; /* set has all bits set */
for (high0 = CHARSETSIZE - 1; cs[high0] == 0xFF; high0--)
/* find highest byte with a 0-bit; low0 is a sentinel */;
if (high1 - low1 <= high0 - low0) { /* range of 1s smaller than of 0s? */
info->offset = low1;
info->size = high1 - low1 + 1;
info->deflt = 0; /* all discharged bits were 0 */
}
else {
info->offset = low0;
info->size = high0 - low0 + 1;
info->deflt = 0xFF; /* all discharged bits were 1 */
}
info->cs = cs + info->offset;
return ISet;
}
/*
** Get a byte from a compact charset. If index is inside the charset
** range, get the byte from the supporting charset (correcting it
** by the offset). Otherwise, return the default for the set.
*/
byte getbytefromcharset (const charsetinfo *info, int index) {
if (index < info->size)
return info->cs[index];
else return info->deflt;
}
/*
** If 'tree' is a 'char' pattern (TSet, TChar, TAny, TFalse), convert it
** into a charset and return 1; else return 0.
*/
int tocharset (TTree *tree, Charset *cs) {
switch (tree->tag) {
case TChar: { /* only one char */
assert(0 <= tree->u.n && tree->u.n <= UCHAR_MAX);
clearset(cs->cs); /* erase all chars */
setchar(cs->cs, tree->u.n); /* add that one */
return 1;
}
case TAny: {
fillset(cs->cs, 0xFF); /* add all characters to the set */
return 1;
}
case TFalse: {
clearset(cs->cs); /* empty set */
return 1;
}
case TSet: { /* fill set */
int i;
fillset(cs->cs, tree->u.set.deflt);
for (i = 0; i < tree->u.set.size; i++)
cs->cs[tree->u.set.offset + i] = treebuffer(tree)[i];
return 1;
}
default: return 0;
}
}
void tree2cset (TTree *tree, charsetinfo *info) {
assert(tree->tag == TSet);
info->offset = tree->u.set.offset;
info->size = tree->u.set.size;
info->deflt = tree->u.set.deflt;
info->cs = treebuffer(tree);
}

30
thirdparty/lpeg/lpcset.h vendored Normal file
View file

@ -0,0 +1,30 @@
#if !defined(lpset_h)
#define lpset_h
#include "lpcset.h"
#include "lpcode.h"
#include "lptree.h"
/*
** Extra information for the result of 'charsettype'. When result is
** IChar, 'offset' is the character. When result is ISet, 'cs' is the
** supporting bit array (with offset included), 'offset' is the offset
** (in bytes), 'size' is the size (in bytes), and 'delt' is the default
** value for bytes outside the set.
*/
typedef struct {
const byte *cs;
int offset;
int size;
int deflt;
} charsetinfo;
int tocharset (TTree *tree, Charset *cs);
Opcode charsettype (const byte *cs, charsetinfo *info);
byte getbytefromcharset (const charsetinfo *info, int index);
void tree2cset (TTree *tree, charsetinfo *info);
#endif

298
thirdparty/lpeg/lpprint.c vendored Normal file
View file

@ -0,0 +1,298 @@
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include "lptypes.h"
#include "lpprint.h"
#include "lpcode.h"
#if defined(LPEG_DEBUG)
/*
** {======================================================
** Printing patterns (for debugging)
** =======================================================
*/
void printcharset (const byte *st) {
int i;
printf("[");
for (i = 0; i <= UCHAR_MAX; i++) {
int first = i;
while (i <= UCHAR_MAX && testchar(st, i)) i++;
if (i - 1 == first) /* unary range? */
printf("(%02x)", first);
else if (i - 1 > first) /* non-empty range? */
printf("(%02x-%02x)", first, i - 1);
}
printf("]");
}
static void printIcharset (const Instruction *inst, const byte *buff) {
byte cs[CHARSETSIZE];
int i;
printf("(%02x-%d) ", inst->i.aux2.set.offset, inst->i.aux2.set.size);
clearset(cs);
for (i = 0; i < CHARSETSIZE * 8; i++) {
if (charinset(inst, buff, i))
setchar(cs, i);
}
printcharset(cs);
}
static void printTcharset (TTree *tree) {
byte cs[CHARSETSIZE];
int i;
printf("(%02x-%d) ", tree->u.set.offset, tree->u.set.size);
fillset(cs, tree->u.set.deflt);
for (i = 0; i < tree->u.set.size; i++)
cs[tree->u.set.offset + i] = treebuffer(tree)[i];
printcharset(cs);
}
static const char *capkind (int kind) {
const char *const modes[] = {
"close", "position", "constant", "backref",
"argument", "simple", "table", "function", "accumulator",
"query", "string", "num", "substitution", "fold",
"runtime", "group"};
return modes[kind];
}
static void printjmp (const Instruction *op, const Instruction *p) {
printf("-> %d", (int)(p + (p + 1)->offset - op));
}
void printinst (const Instruction *op, const Instruction *p) {
const char *const names[] = {
"any", "char", "set",
"testany", "testchar", "testset",
"span", "utf-range", "behind",
"ret", "end",
"choice", "jmp", "call", "open_call",
"commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup",
"fullcapture", "opencapture", "closecapture", "closeruntime",
"--"
};
printf("%02ld: %s ", (long)(p - op), names[p->i.code]);
switch ((Opcode)p->i.code) {
case IChar: {
printf("'%c' (%02x)", p->i.aux1, p->i.aux1);
break;
}
case ITestChar: {
printf("'%c' (%02x)", p->i.aux1, p->i.aux1); printjmp(op, p);
break;
}
case IUTFR: {
printf("%d - %d", p[1].offset, utf_to(p));
break;
}
case IFullCapture: {
printf("%s (size = %d) (idx = %d)",
capkind(getkind(p)), getoff(p), p->i.aux2.key);
break;
}
case IOpenCapture: {
printf("%s (idx = %d)", capkind(getkind(p)), p->i.aux2.key);
break;
}
case ISet: {
printIcharset(p, (p+1)->buff);
break;
}
case ITestSet: {
printIcharset(p, (p+2)->buff); printjmp(op, p);
break;
}
case ISpan: {
printIcharset(p, (p+1)->buff);
break;
}
case IOpenCall: {
printf("-> %d", (p + 1)->offset);
break;
}
case IBehind: {
printf("%d", p->i.aux1);
break;
}
case IJmp: case ICall: case ICommit: case IChoice:
case IPartialCommit: case IBackCommit: case ITestAny: {
printjmp(op, p);
break;
}
default: break;
}
printf("\n");
}
void printpatt (Instruction *p) {
Instruction *op = p;
uint n = op[-1].codesize - 1;
while (p < op + n) {
printinst(op, p);
p += sizei(p);
}
}
static void printcap (Capture *cap, int ident) {
while (ident--) printf(" ");
printf("%s (idx: %d - size: %d) -> %lu (%p)\n",
capkind(cap->kind), cap->idx, cap->siz, (long)cap->index, (void*)cap);
}
/*
** Print a capture and its nested captures
*/
static Capture *printcap2close (Capture *cap, int ident) {
Capture *head = cap++;
printcap(head, ident); /* print head capture */
while (capinside(head, cap))
cap = printcap2close(cap, ident + 2); /* print nested captures */
if (isopencap(head)) {
assert(isclosecap(cap));
printcap(cap++, ident); /* print and skip close capture */
}
return cap;
}
void printcaplist (Capture *cap) {
{ /* for debugging, print first a raw list of captures */
Capture *c = cap;
while (c->index != MAXINDT) { printcap(c, 0); c++; }
}
printf(">======\n");
while (!isclosecap(cap))
cap = printcap2close(cap, 0);
printf("=======\n");
}
/* }====================================================== */
/*
** {======================================================
** Printing trees (for debugging)
** =======================================================
*/
static const char *tagnames[] = {
"char", "set", "any",
"true", "false", "utf8.range",
"rep",
"seq", "choice",
"not", "and",
"call", "opencall", "rule", "xinfo", "grammar",
"behind",
"capture", "run-time"
};
void printtree (TTree *tree, int ident) {
int i;
int sibs = numsiblings[tree->tag];
for (i = 0; i < ident; i++) printf(" ");
printf("%s", tagnames[tree->tag]);
switch (tree->tag) {
case TChar: {
int c = tree->u.n;
if (isprint(c))
printf(" '%c'\n", c);
else
printf(" (%02X)\n", c);
break;
}
case TSet: {
printTcharset(tree);
printf("\n");
break;
}
case TUTFR: {
assert(sib1(tree)->tag == TXInfo);
printf(" %d (%02x %d) - %d (%02x %d) \n",
tree->u.n, tree->key, tree->cap,
sib1(tree)->u.n, sib1(tree)->key, sib1(tree)->cap);
break;
}
case TOpenCall: case TCall: {
assert(sib1(sib2(tree))->tag == TXInfo);
printf(" key: %d (rule: %d)\n", tree->key, sib1(sib2(tree))->u.n);
break;
}
case TBehind: {
printf(" %d\n", tree->u.n);
break;
}
case TCapture: {
printf(" kind: '%s' key: %d\n", capkind(tree->cap), tree->key);
break;
}
case TRule: {
printf(" key: %d\n", tree->key);
sibs = 1; /* do not print 'sib2' (next rule) as a sibling */
break;
}
case TXInfo: {
printf(" n: %d\n", tree->u.n);
break;
}
case TGrammar: {
TTree *rule = sib1(tree);
printf(" %d\n", tree->u.n); /* number of rules */
for (i = 0; i < tree->u.n; i++) {
printtree(rule, ident + 2);
rule = sib2(rule);
}
assert(rule->tag == TTrue); /* sentinel */
sibs = 0; /* siblings already handled */
break;
}
default:
printf("\n");
break;
}
if (sibs >= 1) {
printtree(sib1(tree), ident + 2);
if (sibs >= 2)
printtree(sib2(tree), ident + 2);
}
}
void printktable (lua_State *L, int idx) {
int n, i;
lua_getuservalue(L, idx);
if (lua_isnil(L, -1)) /* no ktable? */
return;
n = lua_rawlen(L, -1);
printf("[");
for (i = 1; i <= n; i++) {
printf("%d = ", i);
lua_rawgeti(L, -1, i);
if (lua_isstring(L, -1))
printf("%s ", lua_tostring(L, -1));
else
printf("%s ", lua_typename(L, lua_type(L, -1)));
lua_pop(L, 1);
}
printf("]\n");
/* leave ktable at the stack */
}
/* }====================================================== */
#endif

32
thirdparty/lpeg/lpprint.h vendored Normal file
View file

@ -0,0 +1,32 @@
#if !defined(lpprint_h)
#define lpprint_h
#include "lptree.h"
#include "lpvm.h"
#if defined(LPEG_DEBUG)
void printpatt (Instruction *p);
void printtree (TTree *tree, int ident);
void printktable (lua_State *L, int idx);
void printcharset (const byte *st);
void printcaplist (Capture *cap);
void printinst (const Instruction *op, const Instruction *p);
#else
#define printktable(L,idx) \
luaL_error(L, "function only implemented in debug mode")
#define printtree(tree,i) \
luaL_error(L, "function only implemented in debug mode")
#define printpatt(p) \
luaL_error(L, "function only implemented in debug mode")
#endif
#endif

1399
thirdparty/lpeg/lptree.c vendored Normal file

File diff suppressed because it is too large Load diff

92
thirdparty/lpeg/lptree.h vendored Normal file
View file

@ -0,0 +1,92 @@
#if !defined(lptree_h)
#define lptree_h
#include "lptypes.h"
/*
** types of trees
*/
typedef enum TTag {
TChar = 0, /* 'n' = char */
TSet, /* the set is encoded in 'u.set' and the next 'u.set.size' bytes */
TAny,
TTrue,
TFalse,
TUTFR, /* range of UTF-8 codepoints; 'n' has initial codepoint;
'cap' has length; 'key' has first byte;
extra info is similar for end codepoint */
TRep, /* 'sib1'* */
TSeq, /* 'sib1' 'sib2' */
TChoice, /* 'sib1' / 'sib2' */
TNot, /* !'sib1' */
TAnd, /* &'sib1' */
TCall, /* ktable[key] is rule's key; 'sib2' is rule being called */
TOpenCall, /* ktable[key] is rule's key */
TRule, /* ktable[key] is rule's key (but key == 0 for unused rules);
'sib1' is rule's pattern pre-rule; 'sib2' is next rule;
extra info 'n' is rule's sequential number */
TXInfo, /* extra info */
TGrammar, /* 'sib1' is initial (and first) rule */
TBehind, /* 'sib1' is pattern, 'n' is how much to go back */
TCapture, /* captures: 'cap' is kind of capture (enum 'CapKind');
ktable[key] is Lua value associated with capture;
'sib1' is capture body */
TRunTime /* run-time capture: 'key' is Lua function;
'sib1' is capture body */
} TTag;
/*
** Tree trees
** The first child of a tree (if there is one) is immediately after
** the tree. A reference to a second child (ps) is its position
** relative to the position of the tree itself.
*/
typedef struct TTree {
byte tag;
byte cap; /* kind of capture (if it is a capture) */
unsigned short key; /* key in ktable for Lua data (0 if no key) */
union {
int ps; /* occasional second child */
int n; /* occasional counter */
struct {
byte offset; /* compact set offset (in bytes) */
byte size; /* compact set size (in bytes) */
byte deflt; /* default value */
byte bitmap[1]; /* bitmap (open array) */
} set; /* for compact sets */
} u;
} TTree;
/* access to charset */
#define treebuffer(t) ((t)->u.set.bitmap)
/*
** A complete pattern has its tree plus, if already compiled,
** its corresponding code
*/
typedef struct Pattern {
union Instruction *code;
TTree tree[1];
} Pattern;
/* number of children for each tree */
extern const byte numsiblings[];
/* access to children */
#define sib1(t) ((t) + 1)
#define sib2(t) ((t) + (t)->u.ps)
#endif

150
thirdparty/lpeg/lptypes.h vendored Normal file
View file

@ -0,0 +1,150 @@
/*
** LPeg - PEG pattern matching for Lua
** Copyright 2007-2023, Lua.org & PUC-Rio (see 'LICENSE' for license)
** written by Roberto Ierusalimschy
*/
#if !defined(lptypes_h)
#define lptypes_h
#include <assert.h>
#include <limits.h>
#include <string.h>
#include "lua.h"
#define VERSION "1.1.0"
#define PATTERN_T "lpeg-pattern"
#define MAXSTACKIDX "lpeg-maxstack"
/*
** compatibility with Lua 5.1
*/
#if (LUA_VERSION_NUM == 501)
#define lp_equal lua_equal
#define lua_getuservalue lua_getfenv
#define lua_setuservalue lua_setfenv
#define lua_rawlen lua_objlen
#define luaL_setfuncs(L,f,n) luaL_register(L,NULL,f)
#define luaL_newlib(L,f) luaL_register(L,"lpeg",f)
typedef size_t lua_Unsigned;
#endif
#if !defined(lp_equal)
#define lp_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#endif
/* default maximum size for call/backtrack stack */
#if !defined(MAXBACK)
#define MAXBACK 400
#endif
/* maximum number of rules in a grammar (limited by 'unsigned short') */
#if !defined(MAXRULES)
#define MAXRULES 1000
#endif
/* initial size for capture's list */
#define INITCAPSIZE 32
/* index, on Lua stack, for subject */
#define SUBJIDX 2
/* number of fixed arguments to 'match' (before capture arguments) */
#define FIXEDARGS 3
/* index, on Lua stack, for capture list */
#define caplistidx(ptop) ((ptop) + 2)
/* index, on Lua stack, for pattern's ktable */
#define ktableidx(ptop) ((ptop) + 3)
/* index, on Lua stack, for backtracking stack */
#define stackidx(ptop) ((ptop) + 4)
typedef unsigned char byte;
typedef unsigned int uint;
#define BITSPERCHAR 8
#define CHARSETSIZE ((UCHAR_MAX/BITSPERCHAR) + 1)
typedef struct Charset {
byte cs[CHARSETSIZE];
} Charset;
#define loopset(v,b) { int v; for (v = 0; v < CHARSETSIZE; v++) {b;} }
#define fillset(s,c) memset(s,c,CHARSETSIZE)
#define clearset(s) fillset(s,0)
/* number of slots needed for 'n' bytes */
#define bytes2slots(n) (((n) - 1u) / (uint)sizeof(TTree) + 1u)
/* set 'b' bit in charset 'cs' */
#define setchar(cs,b) ((cs)[(b) >> 3] |= (1 << ((b) & 7)))
/*
** in capture instructions, 'kind' of capture and its offset are
** packed in field 'aux', 4 bits for each
*/
#define getkind(op) ((op)->i.aux1 & 0xF)
#define getoff(op) (((op)->i.aux1 >> 4) & 0xF)
#define joinkindoff(k,o) ((k) | ((o) << 4))
#define MAXOFF 0xF
#define MAXAUX 0xFF
/* maximum number of bytes to look behind */
#define MAXBEHIND MAXAUX
/* maximum size (in elements) for a pattern */
#define MAXPATTSIZE (SHRT_MAX - 10)
/* size (in instructions) for l bytes (l > 0) */
#define instsize(l) ((int)(((l) + (uint)sizeof(Instruction) - 1u) \
/ (uint)sizeof(Instruction)))
/* size (in elements) for a ISet instruction */
#define CHARSETINSTSIZE (1 + instsize(CHARSETSIZE))
/* size (in elements) for a IFunc instruction */
#define funcinstsize(p) ((p)->i.aux + 2)
#define testchar(st,c) ((((uint)(st)[((c) >> 3)]) >> ((c) & 7)) & 1)
#endif

455
thirdparty/lpeg/lpvm.c vendored Normal file
View file

@ -0,0 +1,455 @@
#include <limits.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lpcap.h"
#include "lptypes.h"
#include "lpvm.h"
#include "lpprint.h"
/* initial size for call/backtrack stack */
#if !defined(INITBACK)
#define INITBACK MAXBACK
#endif
#define getoffset(p) (((p) + 1)->offset)
static const Instruction giveup = {{IGiveup, 0, {0}}};
int charinset (const Instruction *i, const byte *buff, uint c) {
c -= i->i.aux2.set.offset;
if (c >= ((uint)i->i.aux2.set.size /* size in instructions... */
* (uint)sizeof(Instruction) /* in bytes... */
* 8u)) /* in bits */
return i->i.aux1; /* out of range; return default value */
return testchar(buff, c);
}
/*
** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
*/
static const char *utf8_decode (const char *o, int *val) {
static const uint limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFFu};
const unsigned char *s = (const unsigned char *)o;
uint c = s[0]; /* first byte */
uint res = 0; /* final result */
if (c < 0x80) /* ascii? */
res = c;
else {
int count = 0; /* to count number of continuation bytes */
while (c & 0x40) { /* still have continuation bytes? */
int cc = s[++count]; /* read next byte */
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
c <<= 1; /* to test next bit */
}
res |= (c & 0x7F) << (count * 5); /* add first byte */
if (count > 3 || res > 0x10FFFFu || res <= limits[count])
return NULL; /* invalid byte sequence */
s += count; /* skip continuation bytes read */
}
*val = res;
return (const char *)s + 1; /* +1 to include first byte */
}
/*
** {======================================================
** Virtual Machine
** =======================================================
*/
typedef struct Stack {
const char *s; /* saved position (or NULL for calls) */
const Instruction *p; /* next instruction */
int caplevel;
} Stack;
#define getstackbase(L, ptop) ((Stack *)lua_touserdata(L, stackidx(ptop)))
/*
** Ensures the size of array 'capture' (with size '*capsize' and
** 'captop' elements being used) is enough to accomodate 'n' extra
** elements plus one. (Because several opcodes add stuff to the capture
** array, it is simpler to ensure the array always has at least one free
** slot upfront and check its size later.)
*/
/* new size in number of elements cannot overflow integers, and new
size in bytes cannot overflow size_t. */
#define MAXNEWSIZE \
(((size_t)INT_MAX) <= (~(size_t)0 / sizeof(Capture)) ? \
((size_t)INT_MAX) : (~(size_t)0 / sizeof(Capture)))
static Capture *growcap (lua_State *L, Capture *capture, int *capsize,
int captop, int n, int ptop) {
if (*capsize - captop > n)
return capture; /* no need to grow array */
else { /* must grow */
Capture *newc;
uint newsize = captop + n + 1; /* minimum size needed */
if (newsize < (MAXNEWSIZE / 3) * 2)
newsize += newsize / 2; /* 1.5 that size, if not too big */
else if (newsize < (MAXNEWSIZE / 9) * 8)
newsize += newsize / 8; /* else, try 9/8 that size */
else
luaL_error(L, "too many captures");
newc = (Capture *)lua_newuserdata(L, newsize * sizeof(Capture));
memcpy(newc, capture, captop * sizeof(Capture));
*capsize = newsize;
lua_replace(L, caplistidx(ptop));
return newc;
}
}
/*
** Double the size of the stack
*/
static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) {
Stack *stack = getstackbase(L, ptop);
Stack *newstack;
int n = *stacklimit - stack; /* current stack size */
int max, newn;
lua_getfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
max = lua_tointeger(L, -1); /* maximum allowed size */
lua_pop(L, 1);
if (n >= max) /* already at maximum size? */
luaL_error(L, "backtrack stack overflow (current limit is %d)", max);
newn = 2 * n; /* new size */
if (newn > max) newn = max;
newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack));
memcpy(newstack, stack, n * sizeof(Stack));
lua_replace(L, stackidx(ptop));
*stacklimit = newstack + newn;
return newstack + n; /* return next position */
}
/*
** Interpret the result of a dynamic capture: false -> fail;
** true -> keep current position; number -> next position.
** Return new subject position. 'fr' is stack index where
** is the result; 'curr' is current subject position; 'limit'
** is subject's size.
*/
static int resdyncaptures (lua_State *L, int fr, int curr, int limit) {
lua_Integer res;
if (!lua_toboolean(L, fr)) { /* false value? */
lua_settop(L, fr - 1); /* remove results */
return -1; /* and fail */
}
else if (lua_isboolean(L, fr)) /* true? */
res = curr; /* keep current position */
else {
res = lua_tointeger(L, fr) - 1; /* new position */
if (res < curr || res > limit)
luaL_error(L, "invalid position returned by match-time capture");
}
lua_remove(L, fr); /* remove first result (offset) */
return res;
}
/*
** Add capture values returned by a dynamic capture to the list
** 'capture', nested inside a group. 'fd' indexes the first capture
** value, 'n' is the number of values (at least 1). The open group
** capture is already in 'capture', before the place for the new entries.
*/
static void adddyncaptures (Index_t index, Capture *capture, int n, int fd) {
int i;
assert(capture[-1].kind == Cgroup && capture[-1].siz == 0);
capture[-1].idx = 0; /* make group capture an anonymous group */
for (i = 0; i < n; i++) { /* add runtime captures */
capture[i].kind = Cruntime;
capture[i].siz = 1; /* mark it as closed */
capture[i].idx = fd + i; /* stack index of capture value */
capture[i].index = index;
}
capture[n].kind = Cclose; /* close group */
capture[n].siz = 1;
capture[n].index = index;
}
/*
** Remove dynamic captures from the Lua stack (called in case of failure)
*/
static int removedyncap (lua_State *L, Capture *capture,
int level, int last) {
int id = finddyncap(capture + level, capture + last); /* index of 1st cap. */
int top = lua_gettop(L);
if (id == 0) return 0; /* no dynamic captures? */
lua_settop(L, id - 1); /* remove captures */
return top - id + 1; /* number of values removed */
}
/*
** Find the corresponding 'open' capture before 'cap', when that capture
** can become a full capture. If a full capture c1 is followed by an
** empty capture c2, there is no way to know whether c2 is inside
** c1. So, full captures can enclose only captures that start *before*
** its end.
*/
static Capture *findopen (Capture *cap, Index_t currindex) {
int i;
cap--; /* check last capture */
/* Must it be inside current one, but starts where current one ends? */
if (!isopencap(cap) && cap->index == currindex)
return NULL; /* current one cannot be a full capture */
/* else, look for an 'open' capture */
for (i = 0; i < MAXLOP; i++, cap--) {
if (currindex - cap->index >= UCHAR_MAX)
return NULL; /* capture too long for a full capture */
else if (isopencap(cap)) /* open capture? */
return cap; /* that's the one to be closed */
else if (cap->kind == Cclose)
return NULL; /* a full capture should not nest a non-full one */
}
return NULL; /* not found within allowed search limit */
}
/*
** Opcode interpreter
*/
const char *match (lua_State *L, const char *o, const char *s, const char *e,
Instruction *op, Capture *capture, int ptop) {
Stack stackbase[INITBACK];
Stack *stacklimit = stackbase + INITBACK;
Stack *stack = stackbase; /* point to first empty slot in stack */
int capsize = INITCAPSIZE;
int captop = 0; /* point to first empty slot in captures */
int ndyncap = 0; /* number of dynamic captures (in Lua stack) */
const Instruction *p = op; /* current instruction */
stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack++;
lua_pushlightuserdata(L, stackbase);
for (;;) {
#if defined(DEBUG)
printf("-------------------------------------\n");
printcaplist(capture, capture + captop);
printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ",
s, (int)(stack - getstackbase(L, ptop)), ndyncap, captop);
printinst(op, p);
#endif
assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop);
switch ((Opcode)p->i.code) {
case IEnd: {
assert(stack == getstackbase(L, ptop) + 1);
capture[captop].kind = Cclose;
capture[captop].index = MAXINDT;
return s;
}
case IGiveup: {
assert(stack == getstackbase(L, ptop));
return NULL;
}
case IRet: {
assert(stack > getstackbase(L, ptop) && (stack - 1)->s == NULL);
p = (--stack)->p;
continue;
}
case IAny: {
if (s < e) { p++; s++; }
else goto fail;
continue;
}
case IUTFR: {
int codepoint;
if (s >= e)
goto fail;
s = utf8_decode (s, &codepoint);
if (s && p[1].offset <= codepoint && codepoint <= utf_to(p))
p += 2;
else
goto fail;
continue;
}
case ITestAny: {
if (s < e) p += 2;
else p += getoffset(p);
continue;
}
case IChar: {
if ((byte)*s == p->i.aux1 && s < e) { p++; s++; }
else goto fail;
continue;
}
case ITestChar: {
if ((byte)*s == p->i.aux1 && s < e) p += 2;
else p += getoffset(p);
continue;
}
case ISet: {
uint c = (byte)*s;
if (charinset(p, (p+1)->buff, c) && s < e)
{ p += 1 + p->i.aux2.set.size; s++; }
else goto fail;
continue;
}
case ITestSet: {
uint c = (byte)*s;
if (charinset(p, (p + 2)->buff, c) && s < e)
p += 2 + p->i.aux2.set.size;
else p += getoffset(p);
continue;
}
case IBehind: {
int n = p->i.aux1;
if (n > s - o) goto fail;
s -= n; p++;
continue;
}
case ISpan: {
for (; s < e; s++) {
uint c = (byte)*s;
if (!charinset(p, (p+1)->buff, c)) break;
}
p += 1 + p->i.aux2.set.size;
continue;
}
case IJmp: {
p += getoffset(p);
continue;
}
case IChoice: {
if (stack == stacklimit)
stack = doublestack(L, &stacklimit, ptop);
stack->p = p + getoffset(p);
stack->s = s;
stack->caplevel = captop;
stack++;
p += 2;
continue;
}
case ICall: {
if (stack == stacklimit)
stack = doublestack(L, &stacklimit, ptop);
stack->s = NULL;
stack->p = p + 2; /* save return address */
stack++;
p += getoffset(p);
continue;
}
case ICommit: {
assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
stack--;
p += getoffset(p);
continue;
}
case IPartialCommit: {
assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
(stack - 1)->s = s;
(stack - 1)->caplevel = captop;
p += getoffset(p);
continue;
}
case IBackCommit: {
assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
s = (--stack)->s;
if (ndyncap > 0) /* are there matchtime captures? */
ndyncap -= removedyncap(L, capture, stack->caplevel, captop);
captop = stack->caplevel;
p += getoffset(p);
continue;
}
case IFailTwice:
assert(stack > getstackbase(L, ptop));
stack--;
/* FALLTHROUGH */
case IFail:
fail: { /* pattern failed: try to backtrack */
do { /* remove pending calls */
assert(stack > getstackbase(L, ptop));
s = (--stack)->s;
} while (s == NULL);
if (ndyncap > 0) /* is there matchtime captures? */
ndyncap -= removedyncap(L, capture, stack->caplevel, captop);
captop = stack->caplevel;
p = stack->p;
#if defined(DEBUG)
printf("**FAIL**\n");
#endif
continue;
}
case ICloseRunTime: {
CapState cs;
int rem, res, n;
int fr = lua_gettop(L) + 1; /* stack index of first result */
cs.reclevel = 0; cs.L = L;
cs.s = o; cs.ocap = capture; cs.ptop = ptop;
n = runtimecap(&cs, capture + captop, s, &rem); /* call function */
captop -= n; /* remove nested captures */
ndyncap -= rem; /* update number of dynamic captures */
fr -= rem; /* 'rem' items were popped from Lua stack */
res = resdyncaptures(L, fr, s - o, e - o); /* get result */
if (res == -1) /* fail? */
goto fail;
s = o + res; /* else update current position */
n = lua_gettop(L) - fr + 1; /* number of new captures */
ndyncap += n; /* update number of dynamic captures */
if (n == 0) /* no new captures? */
captop--; /* remove open group */
else { /* new captures; keep original open group */
if (fr + n >= SHRT_MAX)
luaL_error(L, "too many results in match-time capture");
/* add new captures + close group to 'capture' list */
capture = growcap(L, capture, &capsize, captop, n + 1, ptop);
adddyncaptures(s - o, capture + captop, n, fr);
captop += n + 1; /* new captures + close group */
}
p++;
continue;
}
case ICloseCapture: {
Capture *open = findopen(capture + captop, s - o);
assert(captop > 0);
if (open) { /* if possible, turn capture into a full capture */
open->siz = (s - o) - open->index + 1;
p++;
continue;
}
else { /* must create a close capture */
capture[captop].siz = 1; /* mark entry as closed */
capture[captop].index = s - o;
goto pushcapture;
}
}
case IOpenCapture:
capture[captop].siz = 0; /* mark entry as open */
capture[captop].index = s - o;
goto pushcapture;
case IFullCapture:
capture[captop].siz = getoff(p) + 1; /* save capture size */
capture[captop].index = s - o - getoff(p);
/* goto pushcapture; */
pushcapture: {
capture[captop].idx = p->i.aux2.key;
capture[captop].kind = getkind(p);
captop++;
capture = growcap(L, capture, &capsize, captop, 0, ptop);
p++;
continue;
}
default: assert(0); return NULL;
}
}
}
/* }====================================================== */

79
thirdparty/lpeg/lpvm.h vendored Normal file
View file

@ -0,0 +1,79 @@
#if !defined(lpvm_h)
#define lpvm_h
#include "lpcap.h"
/*
** About Character sets in instructions: a set is a bit map with an
** initial offset, in bits, and a size, in number of instructions.
** aux1 has the default value for the bits outsize that range.
*/
/* Virtual Machine's instructions */
typedef enum Opcode {
IAny, /* if no char, fail */
IChar, /* if char != aux1, fail */
ISet, /* if char not in set, fail */
ITestAny, /* in no char, jump to 'offset' */
ITestChar, /* if char != aux1, jump to 'offset' */
ITestSet, /* if char not in set, jump to 'offset' */
ISpan, /* read a span of chars in set */
IUTFR, /* if codepoint not in range [offset, utf_to], fail */
IBehind, /* walk back 'aux1' characters (fail if not possible) */
IRet, /* return from a rule */
IEnd, /* end of pattern */
IChoice, /* stack a choice; next fail will jump to 'offset' */
IJmp, /* jump to 'offset' */
ICall, /* call rule at 'offset' */
IOpenCall, /* call rule number 'key' (must be closed to a ICall) */
ICommit, /* pop choice and jump to 'offset' */
IPartialCommit, /* update top choice to current position and jump */
IBackCommit, /* backtrack like "fail" but jump to its own 'offset' */
IFailTwice, /* pop one choice and then fail */
IFail, /* go back to saved state on choice and jump to saved offset */
IGiveup, /* internal use */
IFullCapture, /* complete capture of last 'off' chars */
IOpenCapture, /* start a capture */
ICloseCapture,
ICloseRunTime,
IEmpty /* to fill empty slots left by optimizations */
} Opcode;
/*
** All array of instructions has a 'codesize' as its first element
** and is referred by a pointer to its second element, which is the
** first actual opcode.
*/
typedef union Instruction {
struct Inst {
byte code;
byte aux1;
union {
short key;
struct {
byte offset;
byte size;
} set;
} aux2;
} i;
int offset;
uint codesize;
byte buff[1];
} Instruction;
/* extract 24-bit value from an instruction */
#define utf_to(inst) (((inst)->i.aux2.key << 8) | (inst)->i.aux1)
int charinset (const Instruction *i, const byte *buff, uint c);
const char *match (lua_State *L, const char *o, const char *s, const char *e,
Instruction *op, Capture *capture, int ptop);
#endif

131
thirdparty/lrandom/lrandom.c vendored Normal file
View file

@ -0,0 +1,131 @@
/*
* lrandom.c
* random-number library for Lua 5.1 based on the Mersenne Twister
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 17 Mar 2010 12:31:47
* This code is hereby placed in the public domain.
*/
#include <math.h>
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#define MYNAME "random"
#define MYVERSION MYNAME " library for " LUA_VERSION " / Mar 2010"
#define MYTYPE MYNAME " handle"
#define SEED 2009UL
#include "random.c"
/* Singe: 5.2 renamed luaL_reg to luaL_Reg. Only the spelling changed. */
#if LUA_VERSION_NUM >= 502
#define luaL_reg luaL_Reg
#endif
static MT *Pget(lua_State *L, int i)
{
return luaL_checkudata(L,i,MYTYPE);
}
static MT *Pnew(lua_State *L)
{
MT *c=lua_newuserdata(L,sizeof(MT));
luaL_getmetatable(L,MYTYPE);
lua_setmetatable(L,-2);
return c;
}
static int Lnew(lua_State *L) /** new([seed]) */
{
lua_Number seed=luaL_optnumber(L,1,SEED);
MT *c=Pnew(L);
init_genrand(c,seed);
return 1;
}
static int Lclone(lua_State *L) /** clone(c) */
{
MT *c=Pget(L,1);
MT *d=Pnew(L);
*d=*c;
return 1;
}
static int Lseed(lua_State *L) /** seed(c,[seed]) */
{
MT *c=Pget(L,1);
init_genrand(c,luaL_optnumber(L,2,SEED));
lua_settop(L,1);
return 1;
}
static int Lvalue(lua_State *L) /** value(c,[a,b]) */
{
MT *c=Pget(L,1);
double a,b,r=genrand_res53(c);
switch (lua_gettop(L))
{
case 1:
lua_pushnumber(L,r);
return 1;
case 2:
a=1;
b=luaL_checknumber(L,2);
break;
default:
a=luaL_checknumber(L,2);
b=luaL_checknumber(L,3);
break;
}
if (a>b) { double t=a; a=b; b=t; }
a=ceil(a);
b=floor(b);
if (a>b) return 0;
r=a+floor(r*(b-a+1));
lua_pushnumber(L,r);
return 1;
}
static int Ltostring(lua_State *L)
{
MT *c=Pget(L,1);
lua_pushfstring(L,"%s %p",MYTYPE,(void*)c);
return 1;
}
static const luaL_reg R[] =
{
{ "__tostring", Ltostring }, /** __tostring(c) */
{ "clone", Lclone },
{ "new", Lnew },
{ "seed", Lseed },
{ "value", Lvalue },
{ NULL, NULL }
};
LUALIB_API int luaopen_random(lua_State *L)
{
luaL_newmetatable(L,MYTYPE);
#if LUA_VERSION_NUM < 502
lua_setglobal(L,MYNAME);
luaL_register(L,MYNAME,R);
#else
/* Singe: 5.2 dropped luaL_register. The metatable is the module table here, so the functions go
straight into it and the module system binds the name; nothing is written to the globals. */
luaL_setfuncs(L,R,0);
#endif
lua_pushliteral(L,"version"); /** version */
lua_pushliteral(L,MYVERSION);
lua_settable(L,-3);
lua_pushliteral(L,"__index");
lua_pushvalue(L,-2);
lua_settable(L,-3);
lua_pushliteral(L,"__call"); /** __call(c) */
lua_pushliteral(L,"value");
lua_gettable(L,-3);
lua_settable(L,-3);
return 1;
}

128
thirdparty/lrandom/random.c vendored Normal file
View file

@ -0,0 +1,128 @@
/*
* random.c
* Mersenne Twister random number generator
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 23 Sep 2008 22:57:32
* slightly modified from mt19937ar.c available at
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
*/
/*
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Before using, initialize the state by using init_genrand(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
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. The names of its contributors may not 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 OWNER 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.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
typedef struct {
unsigned long v[N]; /* the array for the state vector */
int i;
} MT;
#define mt (o->v)
#define mti (o->i)
/* initializes mt[N] with a seed */
static void init_genrand(MT *o, unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
/* generates a random number on [0,0xffffffff]-interval */
static unsigned long genrand_int32(MT *o)
{
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(o,5489UL); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<N-1;kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
/* generates a random number on [0,1) with 53-bit resolution*/
static double genrand_res53(MT *o)
{
unsigned long a=genrand_int32(o)>>5, b=genrand_int32(o)>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
/* These real versions are due to Isaku Wada, 2002/01/09 added */

20
thirdparty/lua-cjson/LICENSE vendored Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2010-2012 Mark Pulford <mark@kyne.au>
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.

205
thirdparty/lua-cjson/fpconv.c vendored Normal file
View file

@ -0,0 +1,205 @@
/* fpconv - Floating point conversion routines
*
* Copyright (c) 2011-2012 Mark Pulford <mark@kyne.au>
*
* 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.
*/
/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
* with locale support will break when the decimal separator is a comma.
*
* fpconv_* will around these issues with a translation buffer if required.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "fpconv.h"
/* Lua CJSON assumes the locale is the same for all threads within a
* process and doesn't change after initialisation.
*
* This avoids the need for per thread storage or expensive checks
* for call. */
static char locale_decimal_point = '.';
/* In theory multibyte decimal_points are possible, but
* Lua CJSON only supports UTF-8 and known locales only have
* single byte decimal points ([.,]).
*
* localconv() may not be thread safe (=>crash), and nl_langinfo() is
* not supported on some platforms. Use sprintf() instead - if the
* locale does change, at least Lua CJSON won't crash. */
static void fpconv_update_locale()
{
char buf[8];
snprintf(buf, sizeof(buf), "%g", 0.5);
/* Failing this test might imply the platform has a buggy dtoa
* implementation or wide characters */
if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
fprintf(stderr, "Error: wide characters found or printf() bug.");
abort();
}
locale_decimal_point = buf[1];
}
/* Check for a valid number character: [-+0-9a-yA-Y.]
* Eg: -0.6e+5, infinity, 0xF0.F0pF0
*
* Used to find the probable end of a number. It doesn't matter if
* invalid characters are counted - strtod() will find the valid
* number if it exists. The risk is that slightly more memory might
* be allocated before a parse error occurs. */
static inline int valid_number_character(char ch)
{
char lower_ch;
if ('0' <= ch && ch <= '9')
return 1;
if (ch == '-' || ch == '+' || ch == '.')
return 1;
/* Hex digits, exponent (e), base (p), "infinity",.. */
lower_ch = ch | 0x20;
if ('a' <= lower_ch && lower_ch <= 'y')
return 1;
return 0;
}
/* Calculate the size of the buffer required for a strtod locale
* conversion. */
static int strtod_buffer_size(const char *s)
{
const char *p = s;
while (valid_number_character(*p))
p++;
return p - s;
}
/* Similar to strtod(), but must be passed the current locale's decimal point
* character. Guaranteed to be called at the start of any valid number in a string */
double fpconv_strtod(const char *nptr, char **endptr)
{
char localbuf[FPCONV_G_FMT_BUFSIZE];
char *buf, *endbuf, *dp;
int buflen;
double value;
/* System strtod() is fine when decimal point is '.' */
if (locale_decimal_point == '.')
return strtod(nptr, endptr);
buflen = strtod_buffer_size(nptr);
if (!buflen) {
/* No valid characters found, standard strtod() return */
*endptr = (char *)nptr;
return 0;
}
/* Duplicate number into buffer */
if (buflen >= FPCONV_G_FMT_BUFSIZE) {
/* Handle unusually large numbers */
buf = (char *)malloc(buflen + 1);
if (!buf) {
fprintf(stderr, "Out of memory");
abort();
}
} else {
/* This is the common case.. */
buf = localbuf;
}
memcpy(buf, nptr, buflen);
buf[buflen] = 0;
/* Update decimal point character if found */
dp = strchr(buf, '.');
if (dp)
*dp = locale_decimal_point;
value = strtod(buf, &endbuf);
*endptr = (char *)&nptr[endbuf - buf];
if (buflen >= FPCONV_G_FMT_BUFSIZE)
free(buf);
return value;
}
/* "fmt" must point to a buffer of at least 6 characters */
static void set_number_format(char *fmt, int precision)
{
int d1, d2, i;
assert(1 <= precision && precision <= 14);
/* Create printf format (%.14g) from precision */
d1 = precision / 10;
d2 = precision % 10;
fmt[0] = '%';
fmt[1] = '.';
i = 2;
if (d1) {
fmt[i++] = '0' + d1;
}
fmt[i++] = '0' + d2;
fmt[i++] = 'g';
fmt[i] = 0;
}
/* Assumes there is always at least 32 characters available in the target buffer */
int fpconv_g_fmt(char *str, double num, int precision)
{
char buf[FPCONV_G_FMT_BUFSIZE];
char fmt[6];
int len;
char *b;
set_number_format(fmt, precision);
/* Pass through when decimal point character is dot. */
if (locale_decimal_point == '.')
return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num);
/* snprintf() to a buffer then translate for other decimal point characters */
len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num);
/* Copy into target location. Translate decimal point if required */
b = buf;
do {
*str++ = (*b == locale_decimal_point ? '.' : *b);
} while(*b++);
return len;
}
void fpconv_init()
{
fpconv_update_locale();
}
/* vi:ai et sw=4 ts=4:
*/

22
thirdparty/lua-cjson/fpconv.h vendored Normal file
View file

@ -0,0 +1,22 @@
/* Lua CJSON floating point conversion routines */
/* Buffer required to store the largest string representation of a double.
*
* Longest double printed with %.14g is 21 characters long:
* -1.7976931348623e+308 */
# define FPCONV_G_FMT_BUFSIZE 32
#ifdef USE_INTERNAL_FPCONV
static inline void fpconv_init()
{
/* Do nothing - not required */
}
#else
extern void fpconv_init();
#endif
extern int fpconv_g_fmt(char*, double, int);
extern double fpconv_strtod(const char*, char**);
/* vi:ai et sw=4 ts=4:
*/

1354
thirdparty/lua-cjson/lua_cjson.c vendored Normal file

File diff suppressed because it is too large Load diff

252
thirdparty/lua-cjson/strbuf.c vendored Normal file
View file

@ -0,0 +1,252 @@
/* strbuf - String buffer routines
*
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.au>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "strbuf.h"
static void die(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vfprintf(stderr, fmt, arg);
va_end(arg);
fprintf(stderr, "\n");
exit(-1);
}
void strbuf_init(strbuf_t *s, int len)
{
int size;
if (len <= 0)
size = STRBUF_DEFAULT_SIZE;
else
size = len + 1; /* \0 terminator */
s->buf = NULL;
s->size = size;
s->length = 0;
s->increment = STRBUF_DEFAULT_INCREMENT;
s->dynamic = 0;
s->reallocs = 0;
s->debug = 0;
s->buf = (char *)malloc(size);
if (!s->buf)
die("Out of memory");
strbuf_ensure_null(s);
}
strbuf_t *strbuf_new(int len)
{
strbuf_t *s;
s = (strbuf_t*)malloc(sizeof(strbuf_t));
if (!s)
die("Out of memory");
strbuf_init(s, len);
/* Dynamic strbuf allocation / deallocation */
s->dynamic = 1;
return s;
}
void strbuf_set_increment(strbuf_t *s, int increment)
{
/* Increment > 0: Linear buffer growth rate
* Increment < -1: Exponential buffer growth rate */
if (increment == 0 || increment == -1)
die("BUG: Invalid string increment");
s->increment = increment;
}
static inline void debug_stats(strbuf_t *s)
{
if (s->debug) {
fprintf(stderr, "strbuf(%p) reallocs: %d, length: %d, size: %d\n",
(void *)s, s->reallocs, s->length, s->size);
}
}
/* If strbuf_t has not been dynamically allocated, strbuf_free() can
* be called any number of times strbuf_init() */
void strbuf_free(strbuf_t *s)
{
debug_stats(s);
if (s->buf) {
free(s->buf);
s->buf = NULL;
}
if (s->dynamic)
free(s);
}
char *strbuf_free_to_string(strbuf_t *s, int *len)
{
char *buf;
debug_stats(s);
strbuf_ensure_null(s);
buf = s->buf;
if (len)
*len = s->length;
if (s->dynamic)
free(s);
return buf;
}
static int calculate_new_size(strbuf_t *s, int len)
{
int reqsize, newsize;
if (len <= 0)
die("BUG: Invalid strbuf length requested");
/* Ensure there is room for optional NULL termination */
reqsize = len + 1;
/* If the user has requested to shrink the buffer, do it exactly */
if (s->size > reqsize)
return reqsize;
newsize = s->size;
if (s->increment < 0) {
/* Exponential sizing */
while (newsize < reqsize)
newsize *= -s->increment;
} else {
/* Linear sizing */
newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
}
return newsize;
}
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
* optional termination). */
void strbuf_resize(strbuf_t *s, int len)
{
int newsize;
newsize = calculate_new_size(s, len);
if (s->debug > 1) {
fprintf(stderr, "strbuf(%p) resize: %d => %d\n",
(void *)s, s->size, newsize);
}
s->size = newsize;
s->buf = (char *)realloc(s->buf, s->size);
if (!s->buf)
die("Out of memory");
s->reallocs++;
}
void strbuf_append_string(strbuf_t *s, const char *str)
{
int space, i;
space = strbuf_empty_length(s);
for (i = 0; str[i]; i++) {
if (space < 1) {
strbuf_resize(s, s->length + 1);
space = strbuf_empty_length(s);
}
s->buf[s->length] = str[i];
s->length++;
space--;
}
}
/* strbuf_append_fmt() should only be used when an upper bound
* is known for the output string. */
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
{
va_list arg;
int fmt_len;
strbuf_ensure_empty_length(s, len);
va_start(arg, fmt);
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
va_end(arg);
if (fmt_len < 0)
die("BUG: Unable to convert number"); /* This should never happen.. */
s->length += fmt_len;
}
/* strbuf_append_fmt_retry() can be used when the there is no known
* upper bound for the output string. */
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
{
va_list arg;
int fmt_len;
int empty_len;
int t;
/* If the first attempt to append fails, resize the buffer appropriately
* and try again */
for (t = 0; ; t++) {
va_start(arg, fmt);
/* Append the new formatted string */
/* fmt_len is the length of the string required, excluding the
* trailing NULL */
empty_len = strbuf_empty_length(s);
/* Add 1 since there is also space to store the terminating NULL. */
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
va_end(arg);
if (fmt_len <= empty_len)
break; /* SUCCESS */
if (t > 0)
die("BUG: length of formatted string changed");
strbuf_resize(s, s->length + fmt_len);
}
s->length += fmt_len;
}
/* vi:ai et sw=4 ts=4:
*/

159
thirdparty/lua-cjson/strbuf.h vendored Normal file
View file

@ -0,0 +1,159 @@
/* strbuf - String buffer routines
*
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.au>
*
* 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.
*/
#ifndef _STRBUF_H_
#define _STRBUF_H_
#include <stdlib.h>
#include <stdarg.h>
/* Size: Total bytes allocated to *buf
* Length: String length, excluding optional NULL terminator.
* Increment: Allocation increments when resizing the string buffer.
* Dynamic: True if created via strbuf_new()
*/
typedef struct {
char *buf;
int size;
int length;
int increment;
int dynamic;
int reallocs;
int debug;
} strbuf_t;
#ifndef STRBUF_DEFAULT_SIZE
#define STRBUF_DEFAULT_SIZE 1023
#endif
#ifndef STRBUF_DEFAULT_INCREMENT
#define STRBUF_DEFAULT_INCREMENT -2
#endif
/* Initialise */
extern strbuf_t *strbuf_new(int len);
extern void strbuf_init(strbuf_t *s, int len);
extern void strbuf_set_increment(strbuf_t *s, int increment);
/* Release */
extern void strbuf_free(strbuf_t *s);
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
/* Management */
extern void strbuf_resize(strbuf_t *s, int len);
static int strbuf_empty_length(strbuf_t *s);
static int strbuf_length(strbuf_t *s);
static char *strbuf_string(strbuf_t *s, int *len);
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
static char *strbuf_empty_ptr(strbuf_t *s);
static void strbuf_extend_length(strbuf_t *s, int len);
/* Update */
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
extern void strbuf_append_string(strbuf_t *s, const char *str);
static void strbuf_append_char(strbuf_t *s, const char c);
static void strbuf_ensure_null(strbuf_t *s);
/* Reset string for before use */
static inline void strbuf_reset(strbuf_t *s)
{
s->length = 0;
}
static inline int strbuf_allocated(strbuf_t *s)
{
return s->buf != NULL;
}
/* Return bytes remaining in the string buffer
* Ensure there is space for a NULL terminator. */
static inline int strbuf_empty_length(strbuf_t *s)
{
return s->size - s->length - 1;
}
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
{
if (len > strbuf_empty_length(s))
strbuf_resize(s, s->length + len);
}
static inline char *strbuf_empty_ptr(strbuf_t *s)
{
return s->buf + s->length;
}
static inline void strbuf_extend_length(strbuf_t *s, int len)
{
s->length += len;
}
static inline int strbuf_length(strbuf_t *s)
{
return s->length;
}
static inline void strbuf_append_char(strbuf_t *s, const char c)
{
strbuf_ensure_empty_length(s, 1);
s->buf[s->length++] = c;
}
static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
{
s->buf[s->length++] = c;
}
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
{
strbuf_ensure_empty_length(s, len);
memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
{
memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_ensure_null(strbuf_t *s)
{
s->buf[s->length] = 0;
}
static inline char *strbuf_string(strbuf_t *s, int *len)
{
if (len)
*len = s->length;
return s->buf;
}
#endif
/* vi:ai et sw=4 ts=4:
*/

196
thirdparty/luabitop/lbit.c vendored Normal file
View file

@ -0,0 +1,196 @@
/*
** Lua BitOp -- a bit operations library for Lua.
** http://bitop.luajit.org/
**
** Copyright (C) 2008-2012 Mike Pall. All rights reserved.
**
** 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.
**
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
*/
#define LUA_BITOP_VERSION "1.0.2"
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
/* Singe: Lua 5.3 replaced the LUA_NUMBER_* names this library tests with LUA_FLOAT_TYPE, and 5.2
renamed luaL_typerror. Neither changes what the library does; they only let it compile. */
#if !defined(LUA_NUMBER_DOUBLE) && defined(LUA_FLOAT_TYPE) && defined(LUA_FLOAT_DOUBLE) && (LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE)
#define LUA_NUMBER_DOUBLE
#endif
#if LUA_VERSION_NUM >= 502
#define luaL_typerror(L, idx, name) luaL_typeerror((L), (idx), (name))
#endif
#include <stdint.h>
typedef int32_t SBits;
typedef uint32_t UBits;
typedef union {
lua_Number n;
#ifdef LUA_NUMBER_DOUBLE
uint64_t b;
#else
UBits b;
#endif
} BitNum;
/* Convert argument to bit type. */
static UBits barg(lua_State *L, int idx)
{
BitNum bn;
UBits b;
bn.n = lua_tonumber(L, idx);
#if defined(LUA_NUMBER_DOUBLE)
bn.n += 6755399441055744.0; /* 2^52+2^51 */
#ifdef SWAPPED_DOUBLE
b = (UBits)(bn.b >> 32);
#else
b = (UBits)bn.b;
#endif
#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
defined(LUA_NUMBER_LLONG)
if (sizeof(UBits) == sizeof(lua_Number))
b = bn.b;
else
b = (UBits)(SBits)bn.n;
#elif defined(LUA_NUMBER_FLOAT)
#error "A 'float' lua_Number type is incompatible with this library"
#else
#error "An unknown number type was supplied"
#endif
if (b == 0 && !lua_isnumber(L, idx)) {
luaL_typerror(L, idx, "number");
}
return b;
}
/* Return bit type. */
#define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
#define BIT_OP(FUNC_NAME, OPERATOR) \
static int FUNC_NAME(lua_State *L) { \
int argIndex; \
UBits result = barg(L, 1); \
int numArgs = lua_gettop(L); \
\
for (argIndex = 2; argIndex <= numArgs; ++argIndex) { \
result OPERATOR barg(L, argIndex); \
} \
\
BRET(result); \
}
BIT_OP(bit_band, &=)
BIT_OP(bit_bor, |=)
BIT_OP(bit_bxor, ^=)
#define bshl(b, n) (b << n)
#define bshr(b, n) (b >> n)
#define bsar(b, n) ((SBits)b >> n)
#define brol(b, n) ((b << n) | (b >> (32-n)))
#define bror(b, n) ((b << (32-n)) | (b >> n))
#define BIT_SH(func, fn) \
static int func(lua_State *L) { \
UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
BIT_SH(bit_lshift, bshl)
BIT_SH(bit_rshift, bshr)
BIT_SH(bit_arshift, bsar)
BIT_SH(bit_rol, brol)
BIT_SH(bit_ror, bror)
static int bit_bswap(lua_State *L)
{
UBits b = barg(L, 1);
b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
BRET(b)
}
static int bit_tohex(lua_State *L)
{
UBits b = barg(L, 1);
SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
const char *hexdigits = "0123456789abcdef";
char buf[8];
int i;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 8) n = 8;
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
return 1;
}
static const struct luaL_Reg bit_funcs[] = {
{ "tobit", bit_tobit },
{ "bnot", bit_bnot },
{ "band", bit_band },
{ "bor", bit_bor },
{ "bxor", bit_bxor },
{ "lshift", bit_lshift },
{ "rshift", bit_rshift },
{ "arshift", bit_arshift },
{ "rol", bit_rol },
{ "ror", bit_ror },
{ "bswap", bit_bswap },
{ "tohex", bit_tohex },
{ NULL, NULL }
};
/* Signed right-shifts are implementation-defined per C89/C99.
** But the de facto standard are arithmetic right-shifts on two's
** complement CPUs. This behaviour is required here, so test for it.
*/
#define BAD_SAR (bsar(-8, 2) != (SBits)-2)
LUALIB_API int luaopen_bit(lua_State *L)
{
UBits b;
lua_pushnumber(L, (lua_Number)1437217655L);
b = barg(L, -1);
if (b != (UBits)1437217655L || BAD_SAR) { /* Perform a simple self-test. */
const char *msg = "compiled with incompatible luaconf.h";
#ifdef LUA_NUMBER_DOUBLE
#ifdef _WIN32
if (b == (UBits)1610612736L)
msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
#endif
if (b == (UBits)1127743488L)
msg = "not compiled with SWAPPED_DOUBLE";
#endif
if (BAD_SAR)
msg = "arithmetic right-shift broken";
luaL_error(L, "bit library self-test failed (%s)", msg);
}
/* Singe: 5.2 dropped luaL_register; luaL_newlib builds the table and leaves no global. */
#if LUA_VERSION_NUM < 502
luaL_register(L, "bit", bit_funcs);
#else
luaL_newlib(L, bit_funcs);
#endif
return 1;
}

269
thirdparty/md5/md5.c vendored Normal file
View file

@ -0,0 +1,269 @@
/**
* $Id: md5.c,v 1.2 2008/03/24 20:59:12 mascarenhas Exp $
* Hash function MD5
* @author Marcela Ozorio Suarez, Roberto I.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "md5.h"
#define WORD 32
#define MASK 0xFFFFFFFF
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
/**
* md5 hash function.
* @param message: aribtary string.
* @param len: message length.
* @param output: buffer to receive the hash value. Its size must be
* (at least) HASHSIZE.
*/
void md5(const unsigned char *message, size_t len, unsigned char output[HASHSIZE]);
/**
* init a new md5 calculate context
* @param m a uninitialized md5_t type context
*/
void md5_init(md5_t *m);
/**
* update message to md5 context
* @param m a initialized md5_t type context
* @param message aribtary string
* @param len message length
* @return true if update completed, means len is not the multiples of 64.
* false if you can continue update.
*/
void md5_update(md5_t *m, const unsigned char *message, size_t len);
/**
* finish md5 calculate.
* @param m a md5_type context which previous md5_update on it return true.
* @param output buffer to receive the hash value. its size must be
* (at least) HASHSIZE.
*/
void md5_finish(md5_t *m, unsigned char output[HASHSIZE]);
/*
** Realiza a rotacao no sentido horario dos bits da variavel 'D' do tipo WORD32.
** Os bits sao deslocados de 'num' posicoes
*/
#define ROTATE_LEFT(D, num) (D<<num) | (D>>(WORD-num))
/*Macros que definem operacoes relizadas pelo algoritmo md5 */
#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~(z))))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~(z))))
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (WORD32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (WORD32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (WORD32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (WORD32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
static const unsigned char PAD[64] = {
0x80, 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, 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
};
static void encode(unsigned char* output, const WORD32* input, unsigned int len) {
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
static void decode(WORD32* output, const unsigned char* input, unsigned int len) {
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((WORD32)input[j]) | (((WORD32)input[j + 1]) << 8) |
(((WORD32)input[j + 2]) << 16) | (((WORD32)input[j + 3]) << 24);
}
static void md5_transform(WORD32* digest, const unsigned char* block) {
WORD32 a = digest[0], b = digest[1], c = digest[2], d = digest[3], x[16];
decode(x, block, 64);
/* Round 1 */
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
digest[0] += a;
digest[1] += b;
digest[2] += c;
digest[3] += d;
}
void md5(const unsigned char *message, size_t len, unsigned char output[HASHSIZE]) {
md5_t m;
md5_init(&m);
md5_update(&m, message, len);
md5_finish(&m, output);
}
void md5_init(md5_t *m) {
m->d[0] = 0x67452301;
m->d[1] = 0xEFCDAB89;
m->d[2] = 0x98BADCFE;
m->d[3] = 0x10325476;
m->c[0] = 0;
m->c[1] = 0;
}
void md5_update(md5_t *m, const unsigned char *message, size_t len) {
if (len <= 0)
return;
unsigned int i, index, bits, partLen;
index = (unsigned int)((m->c[0] >> 3) & 0x3f);
bits = (unsigned int)(len << 3);
if ((m->c[0] += bits) < bits)
m->c[1]++;
m->c[1] += (unsigned int)(len >> 29);
partLen = 64 - index;
if (len >= partLen) {
memcpy(m->in + index, message, partLen);
md5_transform(m->d, m->in);
for (i = partLen; i + 63 < len; i += 64) {
md5_transform(m->d, message + i);
}
index = 0;
}
else {
i = 0;
}
memcpy(m->in + index, message + i, len - i);
}
void md5_finish(md5_t *m, unsigned char output[HASHSIZE]) {
unsigned char bits[8];
unsigned int index, padLen;
encode(bits, m->c, 8);
index = (unsigned int)((m->c[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
md5_update(m, PAD, padLen);
md5_update(m, bits, 8);
encode(output, m->d, 16);
}

41
thirdparty/md5/md5.h vendored Normal file
View file

@ -0,0 +1,41 @@
/**
* $Id: md5.h,v 1.2 2006/03/03 15:04:49 tomas Exp $
* Cryptographic module for Lua.
* @author Roberto Ierusalimschy
*/
#ifndef md5_h
#define md5_h
#include "lua.h"
#include <stddef.h>
#define HASHSIZE 16
#if __STDC_VERSION__ >= 199901L
#include <stdint.h>
typedef uint32_t WORD32;
#else
/* static assert that int equal or greater than 32bit. */
typedef char static_assert_sizeof_int
[sizeof(unsigned int) >= 4 ? 1 : -1];
typedef unsigned int WORD32;
#endif
typedef struct md5_t {
WORD32 d[4];
WORD32 c[2];
unsigned char in[64];
} md5_t;
void md5_init(md5_t *m);
void md5_update(md5_t *m, const unsigned char *message, size_t len);
void md5_finish(md5_t *m, unsigned char output[HASHSIZE]);
void md5(const unsigned char *message, size_t len, unsigned char output[HASHSIZE]);
LUALIB_API int luaopen_md5_core (lua_State *L);
#endif

241
thirdparty/md5/md5lib.c vendored Normal file
View file

@ -0,0 +1,241 @@
/**
* $Id: md5lib.c,v 1.10 2008/05/12 20:51:27 carregal Exp $
* Cryptographic and Hash functions for Lua
* @author Roberto Ierusalimschy
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lua.h"
#include "lauxlib.h"
#include "md5.h"
#define MAXKEY 256
#define BLOCKSIZE 16
/**
* Hash function. Returns a hash for a given string.
* @param message: arbitrary binary string.
* @return A 128-bit hash string.
*/
static int lmd5 (lua_State *L) {
char buff[16];
size_t l;
const char *message = luaL_checklstring(L, 1, &l);
md5((const unsigned char *)message, l, (unsigned char *)buff);
lua_pushlstring(L, buff, 16L);
return 1;
}
static int xmd5 (lua_State *L) {
static char tab[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
int i;
char buff[16];
char hexbuff[32];
size_t l;
const char *message = luaL_checklstring(L, 1, &l);
md5((const unsigned char *)message, l, (unsigned char *)buff);
for (i = 0; i < 16; i++)
{
hexbuff[i*2] = tab[(buff[i] >> 4) & 15];
hexbuff[i*2+1] = tab[buff[i] & 15];
}
lua_pushlstring(L, hexbuff, 32L);
return 1;
}
/**
* X-Or. Does a bit-a-bit exclusive-or of two strings.
* @param s1: arbitrary binary string.
* @param s2: arbitrary binary string with same length as s1.
* @return a binary string with same length as s1 and s2,
* where each bit is the exclusive-or of the corresponding bits in s1-s2.
*/
static int ex_or (lua_State *L) {
size_t l1, l2;
const char *s1 = luaL_checklstring(L, 1, &l1);
const char *s2 = luaL_checklstring(L, 2, &l2);
luaL_Buffer b;
luaL_argcheck( L, l1 == l2, 2, "lengths must be equal" );
luaL_buffinit(L, &b);
while (l1--) luaL_addchar(&b, (*s1++)^(*s2++));
luaL_pushresult(&b);
return 1;
}
static void checkseed (lua_State *L) {
if (lua_isnone(L, 3)) { /* no seed? */
time_t tm = time(NULL); /* for `random' seed */
lua_pushlstring(L, (char *)&tm, sizeof(tm));
}
}
// Singe: Lua 5.2 and later provide luaL_setfuncs, so this stand-in is only for 5.1.
#if LUA_VERSION_NUM < 502
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup+1, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
lua_pushstring(L, l->name);
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -(nup + 1));
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */
}
lua_pop(L, nup); /* remove upvalues */
}
#endif
static int initblock (lua_State *L, const char *seed, int lseed, char *block) {
size_t lkey;
const char *key = luaL_checklstring(L, 2, &lkey);
if (lkey > MAXKEY)
luaL_error(L, "key too long (> %d)", MAXKEY);
memset(block, 0, BLOCKSIZE);
memcpy(block, seed, lseed);
memcpy(block+BLOCKSIZE, key, lkey);
return (int)lkey+BLOCKSIZE;
}
static void codestream (lua_State *L, const char *msg, size_t lmsg,
char *block, int lblock) {
luaL_Buffer b;
luaL_buffinit(L, &b);
while (lmsg > 0) {
char code[BLOCKSIZE];
int i;
md5((const unsigned char *)block, lblock, (unsigned char *)code);
for (i=0; i<BLOCKSIZE && lmsg > 0; i++, lmsg--)
code[i] ^= *msg++;
luaL_addlstring(&b, code, i);
memcpy(block, code, i); /* update seed */
}
luaL_pushresult(&b);
}
static void decodestream (lua_State *L, const char *cypher, size_t lcypher,
char *block, int lblock) {
luaL_Buffer b;
luaL_buffinit(L, &b);
while (lcypher > 0) {
char code[BLOCKSIZE];
int i;
md5((const unsigned char *)block, lblock, (unsigned char *)code); /* update seed */
for (i=0; i<BLOCKSIZE && lcypher > 0; i++, lcypher--)
code[i] ^= *cypher++;
luaL_addlstring(&b, code, i);
memcpy(block, cypher-i, i);
}
luaL_pushresult(&b);
}
/**
* Encrypts a string. Uses the hash function md5 in CFB (Cipher-feedback
* mode).
* @param message: arbitrary binary string to be encrypted.
* @param key: arbitrary binary string to be used as a key.
* @param [seed]: optional arbitrary binary string to be used as a seed.
* if no seed is provided, the function uses the result of
* <code>time()</code> as a seed.
* @return The cyphertext (as a binary string).
*/
static int crypt (lua_State *L) {
size_t lmsg;
const char *msg = luaL_checklstring(L, 1, &lmsg);
size_t lseed;
const char *seed;
int lblock;
char block[BLOCKSIZE+MAXKEY];
checkseed(L);
seed = luaL_checklstring(L, 3, &lseed);
if (lseed > BLOCKSIZE)
luaL_error(L, "seed too long (> %d)", BLOCKSIZE);
/* put seed and seed length at the beginning of result */
block[0] = (char)lseed;
memcpy(block+1, seed, lseed);
lua_pushlstring(L, block, lseed+1); /* to concat with result */
lblock = initblock(L, seed, lseed, block);
codestream(L, msg, lmsg, block, lblock);
lua_concat(L, 2);
return 1;
}
/**
* Decrypts a string. For any message, key, and seed, we have that
* <code>decrypt(crypt(msg, key, seed), key) == msg</code>.
* @param cyphertext: message to be decrypted (this must be the result of
a previous call to <code>crypt</code>.
* @param key: arbitrary binary string to be used as a key.
* @return The plaintext.
*/
static int decrypt (lua_State *L) {
size_t lcyphertext;
const char *cyphertext = luaL_checklstring(L, 1, &lcyphertext);
size_t lseed = cyphertext[0];
const char *seed = cyphertext+1;
int lblock;
char block[BLOCKSIZE+MAXKEY];
if (!(lcyphertext >= lseed + 1 && lseed <= BLOCKSIZE)) {
lua_pushlstring(L, NULL, 0);
lua_pushboolean(L, 0);
return 2;
}
cyphertext += lseed+1;
lcyphertext -= lseed+1;
lblock = initblock(L, seed, lseed, block);
decodestream(L, cyphertext, lcyphertext, block, lblock);
lua_pushboolean(L, 1);
return 2;
}
/*
** Assumes the table is on top of the stack.
*/
static void set_info (lua_State *L) {
lua_pushliteral (L, "_COPYRIGHT");
lua_pushliteral (L, "Copyright (C) 2003-2019 PUC-Rio");
lua_settable (L, -3);
lua_pushliteral (L, "_DESCRIPTION");
lua_pushliteral (L, "Checksum facilities for Lua");
lua_settable (L, -3);
lua_pushliteral (L, "_VERSION");
lua_pushliteral (L, "MD5 1.3");
lua_settable (L, -3);
}
static struct luaL_Reg md5lib[] = {
{"sum", lmd5},
{"hexsum", xmd5},
{"exor", ex_or},
{"crypt", crypt},
{"decrypt", decrypt},
{NULL, NULL}
};
int luaopen_md5_core (lua_State *L) {
#if LUA_VERSION_NUM < 502
lua_newtable(L);
luaL_register(L, "md5", md5lib);
luaL_setfuncs(L, md5lib, 0);
#else
/* Singe: 5.2 dropped luaL_register. luaL_newlib makes the table and fills it, and the module
system binds the name, so nothing is written to the globals here. */
luaL_newlib(L, md5lib);
#endif
set_info (L);
return 1;
}

View file

@ -18,14 +18,19 @@ for b in g.get('buffers', []):
for v in views: for v in views:
v['byteOffset'] = v.get('byteOffset', 0) + offsets[v.get('buffer', 0)] v['byteOffset'] = v.get('byteOffset', 0) + offsets[v.get('buffer', 0)]
v['buffer'] = 0 v['buffer'] = 0
# Images: each becomes a buffer view with a mime type. # Images: each becomes a buffer view with a mime type. The table is exhaustive on purpose: a
# two-way png/jpeg guess quietly labelled every .ktx2 as image/jpeg, which Singe survives because it
# sniffs the magic number, and which no other glTF reader has to.
mimeTypes = {'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'ktx2': 'image/ktx2', 'webp': 'image/webp', 'basis': 'image/basis'}
for img in g.get('images', []): for img in g.get('images', []):
uri = img.pop('uri') uri = img.pop('uri')
data = open(os.path.join(base, uri), 'rb').read() data = open(os.path.join(base, uri), 'rb').read()
ext = uri.lower().rsplit('.', 1)[-1] ext = uri.lower().rsplit('.', 1)[-1]
if ext not in mimeTypes:
sys.exit('No mime type known for ' + uri + '; add it to mimeTypes in util/packGlb.py.')
views.append({'buffer': 0, 'byteOffset': add(data), 'byteLength': len(data)}) views.append({'buffer': 0, 'byteOffset': add(data), 'byteLength': len(data)})
img['bufferView'] = len(views) - 1 img['bufferView'] = len(views) - 1
img['mimeType'] = 'image/png' if ext == 'png' else 'image/jpeg' img['mimeType'] = mimeTypes[ext]
while len(binary) % 4: binary.append(0) while len(binary) % 4: binary.append(0)
g['buffers'] = [{'byteLength': len(binary)}] g['buffers'] = [{'byteLength': len(binary)}]
js = json.dumps(g, separators=(',', ':')).encode() js = json.dumps(g, separators=(',', ':')).encode()