Add Deflate() / Inflate() to redbean and fix bugs

The Compress() and Uncompress() APIs were a mistake. The functions
themselves work fine, but it's a design blemish and does superfluous
work. Since they were only introduced in the last few weeks, they're now
deprecated and references to them have been scrubbed from the website
and other documentation. Please use the new APIs since the old APIs will
be removed at some point in the future.

This change introduces automated Lua unit tests for the Redbean APIs.
There's a few functions that were broken which have now been fixed, e.g.
Underlong() and Decimate().
This commit is contained in:
Justine Tunney 2022-07-08 09:47:04 -07:00
parent a18044c504
commit fe5c475f83
12 changed files with 347 additions and 98 deletions

View file

@ -101,3 +101,6 @@ o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp.com
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac.com
@$(COMPILE) -ALUAC o/$(MODE)/third_party/lua/luac.com -s -o $@ $<
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean.com
@$(COMPILE) -ALUA -tT$@ o/$(MODE)/tool/net/redbean.com $(LUAFLAGS) -i $<

View file

@ -44,7 +44,7 @@ char *Underlong(const char *p, size_t n, size_t *z) {
int8_t v1[16], v2[16], vz[16];
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n + 1))) {
if ((q = r = malloc(n * 2 + 1))) {
for (i = 0; i < n;) {
bzero(vz, 16); /* 50x speedup for ASCII */
while (i + 16 < n) {

View file

@ -22,6 +22,11 @@
#include "libc/testlib/testlib.h"
#include "libc/unicode/unicode.h"
TEST(wcwidth, test) {
ASSERT_EQ(0, wcwidth(0));
ASSERT_EQ(-1, wcwidth(1));
}
TEST(strwidth, testCjkWidesAndCombiningLowLines_withThompsonPikeEncoding) {
/*───────────────────────────────────────────────────┬─*/
EXPECT_EQ(20, strwidth(/**/ "𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷▒▒▒▒▒▒▒▒▒▒▒▒" /*│*/, 0));
@ -63,6 +68,8 @@ TEST(wcwidth, testCjkWidesAndCombiningLowLines_widthIsNotLength) {
TEST(wcwidth, block) {
EXPECT_EQ(1, wcwidth(u''));
EXPECT_EQ(0x3061, L'');
EXPECT_EQ(2, wcwidth(L''));
}
TEST(strwidth, testTextDelimitingControlCodes_dontHaveSubstance) {

View file

@ -23,14 +23,21 @@
#include "libc/testlib/testlib.h"
#include "net/http/escape.h"
TEST(Underlong, test) {
size_t n;
TEST(Underlong, test) {
EXPECT_BINEQ(u"e e", gc(Underlong("e\300\200e", -1, &n)));
EXPECT_EQ(3, n);
EXPECT_BINEQ(u"e ", gc(Underlong("e\300\200", -1, &n)));
EXPECT_EQ(2, n);
}
TEST(Underlong, testWeirdInvalidLatin1) {
EXPECT_BINEQ(u"e├Çe ", gc(Underlong("e\300e", -1, &n)));
EXPECT_EQ(4, n);
}
TEST(Underlong, testNormalText) {
size_t n;
EXPECT_STREQ(kHyperion, gc(Underlong(kHyperion, kHyperionSize, &n)));
EXPECT_EQ(kHyperionSize, n);
}

View file

@ -0,0 +1,97 @@
-- Copyright 2022 Justine Alexandra Roberts Tunney
--
-- Permission to use, copy, modify, and/or distribute this software for
-- any purpose with or without fee is hereby granted, provided that the
-- above copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
-- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
x = Rdtsc()
y = Rdtsc()
assert(y > x)
assert(Bsr(1) == 0)
assert(Bsr(2) == 1)
assert(Bsr(3) == 1)
assert(Bsr(4) == 2)
assert(Bsr(0x80000001) == 31)
assert(Bsf(1) == 0)
assert(Bsf(2) == 1)
assert(Bsf(3) == 0)
assert(Bsf(4) == 2)
assert(Bsf(0x80000001) == 0)
assert(Lemur64() == 0x1940efe9d47ae889)
assert(Lemur64() == 0xd4b3103f567f9974)
assert(hex(0x1940efe9d47ae889) == "0x1940efe9d47ae889")
assert(oct(0x1940efe9d47ae889) == "0145007376472436564211")
assert(bin(0x1940efe9d47ae889) == "0b0001100101000000111011111110100111010100011110101110100010001001")
assert(DecodeBase64("abcdefgABCDE") == "\x69\xb7\x1d\x79\xf8\x00\x04\x20\xc4")
assert(EncodeBase64("\x69\xb7\x1d\x79\xf8\x00\x04\x20\xc4") == "abcdefgABCDE")
assert(Decimate("\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00") == "\xff\x00\xff\x00\xff\x00")
assert(Underlong("hello") == "hello")
assert(Underlong("hello\xc0\x80") == "hello\x00")
assert(ParseIp("x") == -1)
assert(ParseIp("127.0.0.1") == 0x7f000001)
assert(GetMonospaceWidth('c') == 1)
assert(GetMonospaceWidth(string.byte('c')) == 1)
assert(GetMonospaceWidth(0) == 0)
assert(GetMonospaceWidth(1) == -1)
assert(GetMonospaceWidth(32) == 1)
assert(GetMonospaceWidth(0x3061) == 2)
assert(GetMonospaceWidth("ちち") == 4)
assert(IsPublicIp(0x08080808))
assert(not IsPublicIp(0x0a000000))
assert(not IsPublicIp(0x7f000001))
assert(not IsPrivateIp(0x08080808))
assert(IsPrivateIp(0x0a000000))
assert(not IsPrivateIp(0x7f000001))
assert(not IsLoopbackIp(0x08080808))
assert(not IsLoopbackIp(0x0a000000))
assert(IsLoopbackIp(0x7f000001))
assert(IndentLines("hi\nthere") == " hi\n there")
assert(IndentLines("hi\nthere\n") == " hi\n there\n")
assert(IndentLines("hi\nthere\n", 2) == " hi\n there\n")
assert(ParseHttpDateTime("Fri, 08 Jul 2022 16:17:43 GMT") == 1657297063)
assert(VisualizeControlCodes("hello\x00") == "hello␀")
assert(math.floor(10 * MeasureEntropy(" ") + .5) == 0)
assert(math.floor(10 * MeasureEntropy("abcabcabcabc") + .5) == 16)
assert(Crc32(0, "123456789") == 0xcbf43926)
assert(Crc32c(0, "123456789") == 0xe3069283)
assert(Md5("hello") == "\x5d\x41\x40\x2a\xbc\x4b\x2a\x76\xb9\x71\x9d\x91\x10\x17\xc5\x92")
assert(Sha1("hello") == "\xaa\xf4\xc6\x1d\xdc\xc5\xe8\xa2\xda\xbe\xde\x0f\x3b\x48\x2c\xd9\xae\xa9\x43\x4d")
assert(Sha224("hello") == "\xea\x09\xae\x9c\xc6\x76\x8c\x50\xfc\xee\x90\x3e\xd0\x54\x55\x6e\x5b\xfc\x83\x47\x90\x7f\x12\x59\x8a\xa2\x41\x93")
assert(Sha256("hello") == "\x2c\xf2\x4d\xba\x5f\xb0\xa3\x0e\x26\xe8\x3b\x2a\xc5\xb9\xe2\x9e\x1b\x16\x1e\x5c\x1f\xa7\x42\x5e\x73\x04\x33\x62\x93\x8b\x98\x24")
assert(Sha384("hello") == "\x59\xe1\x74\x87\x77\x44\x8c\x69\xde\x6b\x80\x0d\x7a\x33\xbb\xfb\x9f\xf1\xb4\x63\xe4\x43\x54\xc3\x55\x3b\xcd\xb9\xc6\x66\xfa\x90\x12\x5a\x3c\x79\xf9\x03\x97\xbd\xf5\xf6\xa1\x3d\xe8\x28\x68\x4f")
assert(Sha512("hello") == "\x9b\x71\xd2\x24\xbd\x62\xf3\x78\x5d\x96\xd4\x6a\xd3\xea\x3d\x73\x31\x9b\xfb\xc2\x89\x0c\xaa\xda\xe2\xdf\xf7\x25\x19\x67\x3c\xa7\x23\x23\xc3\xd9\x9b\xa5\xc1\x1d\x7c\x7a\xcc\x6e\x14\xb8\xc5\xda\x0c\x46\x63\x47\x5c\x2e\x5c\x3a\xde\xf4\x6f\x73\xbc\xde\xc0\x43")
assert(Deflate("hello") == "\xcbH\xcd\xc9\xc9\x07\x00")
assert(Inflate("\xcbH\xcd\xc9\xc9\x07\x00", 5) == "hello")
-- deprecated compression api we wish to forget as quickly as possible
assert(Uncompress(Compress("hello")) == "hello")
assert(Compress("hello") == "\x05\x86\xa6\x106x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15")
assert(Compress("hello", 0) == "\x05\x86\xa6\x106x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15")
assert(Compress("hello", 0, true) == "x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15")

View file

@ -0,0 +1,52 @@
-- Copyright 2022 Justine Alexandra Roberts Tunney
--
-- Permission to use, copy, modify, and/or distribute this software for
-- any purpose with or without fee is hereby granted, provided that the
-- above copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
-- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-- PERFORMANCE OF THIS SOFTWARE.
-- dup()+close()
fd = assert(unix.dup(2))
assert(unix.close(fd))
-- dup2()+close()
assert(assert(unix.dup(2, 10)) == 10)
assert(unix.close(10))
-- fork()+exit()
if assert(unix.fork()) == 0 then
unix.exit(42)
end
pid, ws = assert(unix.wait())
assert(unix.WIFEXITED(ws))
assert(unix.WEXITSTATUS(ws) == 42)
-- pledge()
if GetHostOs() == "LINUX" then
if assert(unix.fork()) == 0 then
assert(unix.pledge("stdio"))
_, err = unix.socket()
assert(err:errno() == unix.EPERM)
unix.exit(0)
end
pid, ws = assert(unix.wait())
assert(unix.WIFEXITED(ws))
assert(unix.WEXITSTATUS(ws) == 0)
elseif GetHostOs() == "OPENBSD" then
if assert(unix.fork()) == 0 then
assert(unix.pledge("stdio"))
unix.socket()
unix.exit(1)
end
pid, ws = assert(unix.wait())
assert(unix.WIFSIGNALED(ws))
assert(unix.WTERMSIG(ws) == unix.SIGABRT)
end

View file

@ -8,8 +8,8 @@ TEST_TOOL_NET_A = o/$(MODE)/test/tool/net/net.a
TEST_TOOL_NET_FILES := $(wildcard test/tool/net/*)
TEST_TOOL_NET_SRCS = $(filter %.c,$(TEST_TOOL_NET_FILES))
TEST_TOOL_NET_SRCS_TEST = $(filter %_test.c,$(TEST_TOOL_NET_SRCS))
TEST_TOOL_NET_LUAS_TEST = $(filter %_test.lua,$(TEST_TOOL_NET_FILES))
TEST_TOOL_NET_HDRS = $(filter %.h,$(TEST_TOOL_NET_FILES))
TEST_TOOL_NET_COMS = $(TEST_TOOL_NET_OBJS:%.o=%.com)
TEST_TOOL_NET_COMS = $(TEST_TOOL_NET_SRCS:%.c=o/$(MODE)/%.com)
TEST_TOOL_NET_OBJS = \
@ -25,7 +25,8 @@ TEST_TOOL_NET_TESTS = \
TEST_TOOL_NET_CHECKS = \
$(TEST_TOOL_NET_HDRS:%=o/$(MODE)/%.ok) \
$(TEST_TOOL_NET_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
$(TEST_TOOL_NET_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) \
$(TEST_TOOL_NET_LUAS_TEST:%.lua=o/$(MODE)/%.lua.runs)
TEST_TOOL_NET_DIRECTDEPS = \
LIBC_CALLS \

View file

@ -624,7 +624,11 @@
((eq major-mode 'sh-mode)
(compile (format "sh %s" file)))
((eq major-mode 'lua-mode)
(compile (format "lua.com %s" file)))
(let* ((mode (cosmo--make-mode arg))
(redbean (format "%s/o/%s/tool/net/redbean.com" root mode)))
(if (file-executable-p redbean)
(compile (format "%s -i %s" redbean file))
(compile (format "lua.com %s" file)))))
((and (eq major-mode 'python-mode)
(cosmo-startswith "third_party/python/Lib/test/" file))
(let ((mode (cosmo--make-mode arg)))

View file

@ -1359,8 +1359,8 @@ FUNCTIONS
Shrinks byte buffer in half using John Costella's magic kernel.
This downscales data 2x using an eight-tap convolution, e.g.
>: Decimate(b'\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00\\xff\\xff\\x00\\x00')
b'\\xff\\x00\\xff\\x00\\xff\\x00'
>: Decimate('\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00')
"\xff\x00\xff\x00\xff\x00"
This is very fast if SSSE3 is available (Intel 2004+ / AMD 2011+).
@ -1369,56 +1369,40 @@ FUNCTIONS
the density of information. Cryptographic random should be in
the ballpark of 7.9 whereas plaintext will be more like 4.5.
Compress(uncompdata:str[, level:int[, raw:bool]]) → compdata:str
Deflate(uncompressed:str[, level:int])
├─→ compressed:str
└─→ nil, error:str
Compresses data using DEFLATE algorithm. The compression
format here is defined to be quick and handy for things like
database fields. For example:
Compresses data.
>: Compress('hello')
"\x05\x86\xa6\x106x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15"
>: Uncompress(Compress('hello'))
>: Deflate("hello")
"\xcbH\xcd\xc9\xc9\x07\x00"
>: Inflate("\xcbH\xcd\xc9\xc9\x07\x00", 5)
"hello"
The binary wire format is defined as follows:
1. uleb64 uncompressed byte size (1 to 10 bytes)
2. uint32_t crc32 (4 bytes; zlib polynomial)
3. data (created by zlib compress function)
The output format is raw DEFLATE that's suitable for embedding
into formats like a ZIP file. It's recommended that, like ZIP,
you also store separately a Crc32() checksum in addition to
the original uncompressed size.
`level` is the compression level, which defaults to 7. The max
is 9. Lower numbers go faster. Higher numbers go slower, but
have better compression ratios.
is 9. Lower numbers go faster (4 for instance is a sweet spot)
and higher numbers go slower but have better compression.
`raw` may be set to true if you only want `data` (3) to be
returned. In this case, it's assumed the caller will take
responsibility for storing the length (and optionall crc)
separately. See the redbean Crc32() API.
Inflate(compressed:str, maxoutsize:int)
├─→ uncompressed:str
└─→ nil, error:str
>: a = 'hello'
>: b = Compress(a, 9, true)
>: Uncompress(b, #a)
"hello"
Decompresses data.
Uncompress(compdata:str[, uncomplen:int]) → uncompdata:str
This function performs the inverse of Deflate(). It's
recommended that you perform a Crc32() check on the output
string after this function succeeds.
Uncompresses data using DEFLATE algorithm. This applies the
inverse transform of the Compress() function. See its docs for
further details on usage and encoding.
This function throws exceptions in the event that the value
couldn't be decoded. There's a crc32 check to make our check
of validity iron-clad. It's implemented using Intel CLMUL so
it has ludicrous speed performance as well.
If you used the `raw` parameter when calling Compress() i.e.
`compdata` doesn't have the redbean header described above,
then the `uncomplen` parameter may be supplied. In that case
your data is handed over directly to zlib `uncompress()`. In
this case an exception will be raised if the value couldn't be
decoded, or if the resulting length differed from the supplied
length. It's recommended that Crc32() check still be performed
manually after using this method.
`maxoutsize` is the uncompressed size, which should be known.
However, it is permissable (although not advised) to specify
some large number in which case (on success) the byte length
of the output string may be less than `maxoutsize`.
Benchmark(func[, count[, maxattempts]])
└─→ nanos:real, ticks:int, overhead-ticks:int, tries:int

View file

@ -163,6 +163,7 @@ int LuaDecimate(lua_State *L) {
s = luaL_checklstring(L, 1, &n);
m = ROUNDUP(n, 16);
p = luaL_buffinitsize(L, &buf, m);
memcpy(p, s, n);
bzero(p + n, m - n);
cDecimate2xUint8x8(m, (unsigned char *)p,
(signed char[8]){-1, -3, 3, 17, 17, 3, -3, -1});
@ -355,7 +356,7 @@ int LuaIndentLines(lua_State *L) {
int LuaGetMonospaceWidth(lua_State *L) {
int w;
if (lua_isinteger(L, 1)) {
if (lua_isnumber(L, 1)) {
w = wcwidth(lua_tointeger(L, 1));
} else if (lua_isstring(L, 1)) {
w = strwidth(luaL_checkstring(L, 1), luaL_optinteger(L, 2, 0) & 7);
@ -766,9 +767,9 @@ int LuaCompress(lua_State *L) {
}
int LuaUncompress(lua_State *L) {
int rc;
char *q;
uint32_t crc;
int rc, level;
const char *p;
luaL_Buffer buf;
size_t n, m, len;
@ -797,3 +798,89 @@ int LuaUncompress(lua_State *L) {
luaL_pushresultsize(&buf, m);
return 1;
}
// unix.deflate(uncompressed:str[, level:int])
// ├─→ compressed:str
// └─→ nil, error:str
int LuaDeflate(lua_State *L) {
char *out;
z_stream zs;
int rc, level;
const char *in;
luaL_Buffer buf;
size_t insize, outsize, actualoutsize;
in = luaL_checklstring(L, 1, &insize);
level = luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION);
outsize = compressBound(insize);
out = luaL_buffinitsize(L, &buf, outsize);
zs.next_in = (const uint8_t *)in;
zs.avail_in = insize;
zs.next_out = (uint8_t *)out;
zs.avail_out = outsize;
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
if ((rc = deflateInit2(&zs, level, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL,
Z_DEFAULT_STRATEGY)) != Z_OK) {
lua_pushnil(L);
lua_pushfstring(L, "%s() failed: %d", "deflateInit2", rc);
return 2;
}
rc = deflate(&zs, Z_FINISH);
actualoutsize = outsize - zs.avail_out;
deflateEnd(&zs);
if (rc != Z_STREAM_END) {
lua_pushnil(L);
lua_pushfstring(L, "%s() failed: %d", "deflate", rc);
return 2;
}
luaL_pushresultsize(&buf, actualoutsize);
return 1;
}
// unix.inflate(compressed:str, maxoutsize:int)
// ├─→ uncompressed:str
// └─→ nil, error:str
int LuaInflate(lua_State *L) {
int rc;
char *out;
z_stream zs;
const char *in;
luaL_Buffer buf;
size_t insize, outsize, actualoutsize;
in = luaL_checklstring(L, 1, &insize);
outsize = luaL_checkinteger(L, 2);
out = luaL_buffinitsize(L, &buf, outsize);
zs.next_in = (const uint8_t *)in;
zs.avail_in = insize;
zs.total_in = insize;
zs.next_out = (uint8_t *)out;
zs.avail_out = outsize;
zs.total_out = outsize;
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
if ((rc = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) {
lua_pushnil(L);
lua_pushfstring(L, "%s() failed: %d", "inflateInit2", rc);
return 2;
}
rc = inflate(&zs, Z_FINISH);
actualoutsize = outsize - zs.avail_out;
inflateEnd(&zs);
if (rc != Z_STREAM_END) {
lua_pushnil(L);
lua_pushfstring(L, "%s() failed: %d", "inflate", rc);
return 2;
}
luaL_pushresultsize(&buf, actualoutsize);
return 1;
}

View file

@ -21,6 +21,7 @@ int LuaCrc32c(lua_State *);
int LuaDecimate(lua_State *);
int LuaDecodeBase64(lua_State *);
int LuaDecodeLatin1(lua_State *);
int LuaDeflate(lua_State *);
int LuaEncodeBase64(lua_State *);
int LuaEncodeLatin1(lua_State *);
int LuaEscapeFragment(lua_State *);
@ -48,6 +49,7 @@ int LuaGetTime(lua_State *);
int LuaHasControlCodes(lua_State *);
int LuaHex(lua_State *);
int LuaIndentLines(lua_State *);
int LuaInflate(lua_State *);
int LuaIsAcceptableHost(lua_State *);
int LuaIsAcceptablePath(lua_State *);
int LuaIsAcceptablePort(lua_State *);

View file

@ -3896,7 +3896,8 @@ static int LuaFetch(lua_State *L) {
freeaddrinfo(addr), addr = 0;
if (rc == -1) {
close(sock);
return LuaNilError(L, "connect(%s:%s) error: %s", host, port, strerror(errno));
return LuaNilError(L, "connect(%s:%s) error: %s", host, port,
strerror(errno));
}
#ifndef UNSECURE
@ -4978,6 +4979,7 @@ static bool LuaRunAsset(const char *path, bool mandatory) {
// <SORTED>
// list of functions that can't be run from the repl
static const char *const kDontAutoComplete[] = {
"Compress", // deprecated
"GetBody", //
"GetClientAddr", //
"GetClientFd", //
@ -5037,6 +5039,7 @@ static const char *const kDontAutoComplete[] = {
"SetCookie", //
"SetHeader", //
"SslInit", // TODO
"Uncompress", // deprecated
"Write", //
};
// </SORTED>
@ -5052,6 +5055,7 @@ static const luaL_Reg kLuaFuncs[] = {
{"Decimate", LuaDecimate}, //
{"DecodeBase64", LuaDecodeBase64}, //
{"DecodeLatin1", LuaDecodeLatin1}, //
{"Deflate", LuaDeflate}, //
{"EncodeBase64", LuaEncodeBase64}, //
{"EncodeJson", LuaEncodeJson}, //
{"EncodeLatin1", LuaEncodeLatin1}, //
@ -5113,11 +5117,12 @@ static const luaL_Reg kLuaFuncs[] = {
{"HasParam", LuaHasParam}, //
{"HidePath", LuaHidePath}, //
{"IndentLines", LuaIndentLines}, //
{"Inflate", LuaInflate}, //
{"IsAcceptableHost", LuaIsAcceptableHost}, //
{"IsAcceptablePath", LuaIsAcceptablePath}, //
{"IsAcceptablePort", LuaIsAcceptablePort}, //
{"IsClientUsingSsl", LuaIsClientUsingSsl}, //
{"IsAssetCompressed", LuaIsAssetCompressed}, //
{"IsClientUsingSsl", LuaIsClientUsingSsl}, //
{"IsDaemon", LuaIsDaemon}, //
{"IsHeaderRepeatable", LuaIsHeaderRepeatable}, //
{"IsHiddenPath", LuaIsHiddenPath}, //
@ -5333,7 +5338,7 @@ static void DisableRawMode(void) {
++__strace;
}
static void LuaInterpreter(lua_State *L) {
static int LuaInterpreter(lua_State *L) {
int i, n, sig, status;
const char *script;
if (optind < __argc) {
@ -5349,7 +5354,7 @@ static void LuaInterpreter(lua_State *L) {
status = lua_runchunk(L, n, LUA_MULTRET);
TRACE_END;
}
lua_report(L, status);
return lua_report(L, status);
} else {
lua_repl_blocking = true;
lua_repl_completions_callback = HandleCompletions;
@ -5384,6 +5389,7 @@ static void LuaInterpreter(lua_State *L) {
if ((sig = linenoiseGetInterrupt())) {
raise(sig);
}
return status;
}
}
@ -5392,8 +5398,7 @@ static void LuaInit(void) {
lua_State *L = GL;
LuaSetArgv(L);
if (interpretermode) {
LuaInterpreter(L);
exit(0);
exit(LuaInterpreter(L));
}
if (LuaRunAsset("/.init.lua", true)) {
hasonhttprequest = IsHookDefined("OnHttpRequest");