Polish redbean serialization

This commit is contained in:
Justine Tunney 2022-04-29 06:06:23 -07:00
parent 7aafa64ab3
commit 2d1731b995
24 changed files with 828 additions and 158 deletions

63
libc/fmt/formatbinary64.c Normal file
View file

@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 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.
*/
#include "libc/fmt/itoa.h"
#include "libc/nexgen32e/bsr.h"
static inline int PickGoodWidth(unsigned x) {
if (x < 16) {
if (x < 2) return 0;
if (x < 8) return 7;
return 15;
} else {
if (x < 32) return 31;
return 63;
}
}
/**
* Converts unsigned 64-bit integer to binary string.
*
* @param p needs at least 67 bytes
* @param z is 0 for DIGITS, 1 for 0bDIGITS, 2 for 0bDIGITS if 0
* @return pointer to nul byte
*/
char *FormatBinary64(char p[hasatleast 67], uint64_t x, char z) {
int i;
uint64_t b;
if (x) {
if (z) {
*p++ = '0';
*p++ = 'b';
}
i = PickGoodWidth(bsrl(x));
do {
b = 1;
b <<= i;
*p++ = '0' + !!(x & b);
} while (i--);
} else {
if (z == 1) {
*p++ = '0';
*p++ = 'b';
}
*p++ = '0';
}
*p = 0;
return p;
}

63
libc/fmt/formatflex64.c Normal file
View file

@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
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.
*/
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/math.h"
static inline int CountZeroesHex(uint64_t x) {
int n;
for (n = 0; x;) {
if (!(x & 15)) {
++n;
}
x >>= 4;
}
return n;
}
static inline int CountZeroesDec(int64_t s) {
int n, r;
uint64_t x;
x = s >= 0 ? s : -(uint64_t)s;
for (n = 0; x;) {
r = x % 10;
x = x / 10;
if (!r) ++n;
}
return n;
}
/**
* Formats integer using decimal or hexadecimal.
*
* We choose hex vs. decimal based on whichever one has the most zeroes.
* We only bother counting zeroes for numbers outside -256 𝑥 256.
*/
char *FormatFlex64(char p[hasatleast 24], int64_t x, char z) {
int zhex, zdec;
if (-256 <= x && x <= 256) goto UseDecimal;
zhex = CountZeroesHex(x) * 16;
zdec = CountZeroesDec(x) * 10;
if (zdec >= zhex) {
UseDecimal:
return FormatInt64(p, x);
} else {
return FormatHex64(p, x, z);
}
}

64
libc/fmt/formathex64.c Normal file
View file

@ -0,0 +1,64 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 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.
*/
#include "libc/fmt/itoa.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
static inline int PickGoodWidth(unsigned x, char z) {
if (z) {
if (x < 16) {
if (x < 8) return 8;
return 16;
} else {
if (x < 32) return 32;
return 64;
}
} else {
return ROUNDUP(x + 1, 4);
}
}
/**
* Converts unsigned 64-bit integer to hex string.
*
* @param p needs at least 19 bytes
* @param z is 0 for DIGITS, 1 for 0bDIGITS, 2 for 0bDIGITS if 0
* @return pointer to nul byte
*/
char *FormatHex64(char p[hasatleast 19], uint64_t x, char z) {
int i;
if (x) {
if (z) {
*p++ = '0';
*p++ = 'x';
}
i = PickGoodWidth(bsrl(x), z);
do {
*p++ = "0123456789abcdef"[(x >> (i -= 4)) & 15];
} while (i);
} else {
if (z == 1) {
*p++ = '0';
*p++ = 'x';
}
*p++ = '0';
}
*p = 0;
return p;
}

View file

@ -21,7 +21,7 @@
/**
* Converts unsigned 64-bit integer to octal string.
*
* @param p needs at least 12 bytes
* @param p needs at least 24 bytes
* @param z ensures it starts with zero
* @return pointer to nul byte
*/

View file

@ -15,6 +15,9 @@ char *FormatInt64Thousands(char[hasatleast 27], int64_t);
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
char *FormatOctal32(char[hasatleast 13], uint32_t, bool);
char *FormatOctal64(char[hasatleast 24], uint64_t, bool);
char *FormatBinary64(char[hasatleast 67], uint64_t, char);
char *FormatHex64(char[hasatleast 19], uint64_t, char);
char *FormatFlex64(char[hasatleast 24], int64_t, char);
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);

View file

@ -0,0 +1,98 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
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.
*/
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
char buf[67];
void SetUp(void) {
memset(buf, 0x55, sizeof(buf));
}
TEST(FormatBinary64, test1) {
EXPECT_EQ(1, FormatBinary64(buf, 0, 2) - buf);
EXPECT_STREQ("0", buf);
}
TEST(FormatBinary64, test2) {
EXPECT_EQ(1, FormatBinary64(buf, 0, 0) - buf);
EXPECT_STREQ("0", buf);
EXPECT_EQ(3, FormatBinary64(buf, 0, 1) - buf);
EXPECT_STREQ("0b0", buf);
}
TEST(FormatBinary64, test3) {
EXPECT_EQ(3, FormatBinary64(buf, 1, 2) - buf);
EXPECT_STREQ("0b1", buf);
}
TEST(FormatBinary64, test4) {
EXPECT_EQ(1, FormatBinary64(buf, 1, 0) - buf);
EXPECT_STREQ("1", buf);
}
TEST(FormatBinary64, test5) {
EXPECT_EQ(66, FormatBinary64(buf, 01777777777777777777777UL, 2) - buf);
EXPECT_STREQ(
"0b1111111111111111111111111111111111111111111111111111111111111111",
buf);
}
TEST(FormatBinary64, test6) {
EXPECT_EQ(64, FormatBinary64(buf, 01777777777777777777777UL, 0) - buf);
EXPECT_STREQ(
"1111111111111111111111111111111111111111111111111111111111111111", buf);
}
TEST(FormatBinary64, test7) {
EXPECT_EQ(66, FormatBinary64(buf, 0xEBF2AA499B9028EAul, 2) - buf);
EXPECT_STREQ(
"0b1110101111110010101010100100100110011011100100000010100011101010",
buf);
}
TEST(FormatBinary64, test8) {
EXPECT_EQ(66, FormatBinary64(buf, 0x00F2AA499B9028EAul, 2) - buf);
EXPECT_STREQ(
"0b0000000011110010101010100100100110011011100100000010100011101010",
buf);
}
TEST(FormatBinary64, testScalesToWordSizes) {
EXPECT_EQ(8 + 2, FormatBinary64(buf, 13, 2) - buf);
EXPECT_STREQ("0b00001101", buf);
EXPECT_EQ(16 + 2, FormatBinary64(buf, 31337, 2) - buf);
EXPECT_STREQ("0b0111101001101001", buf);
EXPECT_EQ(32 + 2, FormatBinary64(buf, 65536, 2) - buf);
EXPECT_STREQ("0b00000000000000010000000000000000", buf);
}
BENCH(FormatBinary64, bench) {
EZBENCH2("FormatUint64 tiny", donothing, FormatUint64(buf, 1));
EZBENCH2("FormatOctal64 tiny", donothing, FormatOctal64(buf, 1, true));
EZBENCH2("FormatBinary64 tiny", donothing, FormatBinary64(buf, 1, 2));
EZBENCH2("FormatUint64 big", donothing,
FormatUint64(buf, 01777777777777777777777UL));
EZBENCH2("FormatOctal64 big", donothing,
FormatOctal64(buf, 01777777777777777777777UL, true));
EZBENCH2("FormatBinary64 big", donothing,
FormatBinary64(buf, 01777777777777777777777UL, 2));
}

View file

@ -0,0 +1,34 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
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.
*/
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/testlib/testlib.h"
char buf[25];
void SetUp(void) {
memset(buf, 0x55, sizeof(buf));
}
TEST(formatflex64, test) {
EXPECT_EQ(5, FormatFlex64(buf, 31337, 2) - buf);
EXPECT_STREQ("31337", buf);
EXPECT_EQ(10, FormatFlex64(buf, 0x80000000, 2) - buf);
EXPECT_STREQ("0x80000000", buf);
}

View file

@ -0,0 +1,87 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
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.
*/
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
char buf[19];
void SetUp(void) {
memset(buf, 0x55, sizeof(buf));
}
TEST(FormatHex64, test1) {
EXPECT_EQ(1, FormatHex64(buf, 0, 2) - buf);
EXPECT_STREQ("0", buf);
}
TEST(FormatHex64, test2) {
EXPECT_EQ(1, FormatHex64(buf, 0, 0) - buf);
EXPECT_STREQ("0", buf);
EXPECT_EQ(3, FormatHex64(buf, 0, 1) - buf);
EXPECT_STREQ("0x0", buf);
}
TEST(FormatHex64, test3) {
EXPECT_EQ(4, FormatHex64(buf, 1, 2) - buf);
EXPECT_STREQ("0x01", buf);
}
TEST(FormatHex64, test4) {
EXPECT_EQ(1, FormatHex64(buf, 1, 0) - buf);
EXPECT_STREQ("1", buf);
}
TEST(FormatHex64, test5) {
EXPECT_EQ(18, FormatHex64(buf, 01777777777777777777777UL, 2) - buf);
EXPECT_STREQ("0xffffffffffffffff", buf);
}
TEST(FormatHex64, test6) {
EXPECT_EQ(16, FormatHex64(buf, 01777777777777777777777UL, 0) - buf);
EXPECT_STREQ("ffffffffffffffff", buf);
}
TEST(FormatHex64, test7) {
EXPECT_EQ(18, FormatHex64(buf, 0xEBF2AA499B9028EAul, 2) - buf);
EXPECT_STREQ("0xebf2aa499b9028ea", buf);
}
TEST(FormatHex64, test8) {
EXPECT_EQ(18, FormatHex64(buf, 0x00F2AA499B9028EAul, 2) - buf);
EXPECT_STREQ("0x00f2aa499b9028ea", buf);
}
TEST(FormatHex64, testScalesToWordSizes) {
EXPECT_EQ(2 + 2, FormatHex64(buf, 13, 2) - buf);
EXPECT_STREQ("0x0d", buf);
EXPECT_EQ(4 + 2, FormatHex64(buf, 31337, 2) - buf);
EXPECT_STREQ("0x7a69", buf);
EXPECT_EQ(8 + 2, FormatHex64(buf, 65536, 2) - buf);
EXPECT_STREQ("0x00010000", buf);
}
BENCH(FormatHex64, bench) {
EZBENCH2("FormatUint64 tiny", donothing, FormatUint64(buf, 1));
EZBENCH2("FormatOctal64 tiny", donothing, FormatOctal64(buf, 1, true));
EZBENCH2("FormatHex64 tiny", donothing, FormatHex64(buf, 1, 2));
EZBENCH2("FormatHex64 big", donothing,
FormatHex64(buf, 01777777777777777777777UL, 2));
}

View file

@ -21,7 +21,7 @@
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
char buf[25];
char buf[24];
void SetUp(void) {
memset(buf, 0x55, sizeof(buf));

View file

@ -24,6 +24,8 @@ LOCAL MODIFICATIONS
Integer literals such as `033` will now be interpreted as octal.
Integer literals such as `0b10` will now be interpreted as binary.
The `\e` string literal escape sequence has been added, which is
equivalent to `\27` (the Lua version of `\033`) or the ASCII ESC
character. It may be used for teletypewriter control like having

View file

@ -15,9 +15,9 @@ int LuaParseUrl(lua_State *);
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
int LuaPushHeaders(lua_State *, struct HttpMessage *, const char *);
void EscapeLuaString(char *, size_t, char **);
void LuaPrintStack(lua_State *);
void LuaPushLatin1(lua_State *, const char *, size_t);
void LuaPushUrlParams(lua_State *, struct UrlParams *);
void LuaPrintStack(lua_State *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

101
third_party/lua/lapi.c vendored
View file

@ -504,26 +504,51 @@ static void *touserdata (const TValue *o) {
}
/**
* lua_touserdata [-0, +0, ]
*
* If the value at the given index is a full userdata, returns its
* memory-block address. If the value is a light userdata, returns its value
* (a pointer). Otherwise, returns NULL.
*/
LUA_API void *lua_touserdata (lua_State *L, int idx) {
const TValue *o = index2value(L, idx);
return touserdata(o);
}
/**
* lua_tothread [-0, +0, ]
*
* Converts the value at the given index to a Lua thread (represented as
* lua_State*). This value must be a thread; otherwise, the function returns
* NULL.
*/
LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
const TValue *o = index2value(L, idx);
return (!ttisthread(o)) ? NULL : thvalue(o);
}
/*
** Returns a pointer to the internal representation of an object.
** Note that ANSI C does not allow the conversion of a pointer to
** function to a 'void*', so the conversion here goes through
** a 'size_t'. (As the returned pointer is only informative, this
** conversion should not be a problem.)
*/
/**
* lua_topointer [-0, +0, ]
*
* Converts the value at the given index to a generic C pointer (void*). The
* value can be a userdata, a table, a thread, a string, or a function;
* otherwise, lua_topointer returns NULL. Different objects will give
* different pointers. There is no way to convert the pointer back to its
* original value.
*
* Typically this function is used only for hashing and debug information.
*/
LUA_API const void *lua_topointer (lua_State *L, int idx) {
/*
** Returns a pointer to the internal representation of an object.
** Note that ANSI C does not allow the conversion of a pointer to
** function to a 'void*', so the conversion here goes through
** a 'size_t'. (As the returned pointer is only informative, this
** conversion should not be a problem.)
*/
const TValue *o = index2value(L, idx);
switch (ttypetag(o)) {
case LUA_VLCF: return cast_voidp(cast_sizet(fvalue(o)));
@ -881,6 +906,12 @@ static Table *gettable (lua_State *L, int idx) {
}
/**
* lua_rawget [-1, +1, ]
*
* Similar to lua_gettable, but does a raw access (i.e., without
* metamethods).
*/
LUA_API int lua_rawget (lua_State *L, int idx) {
Table *t;
const TValue *val;
@ -901,6 +932,15 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
}
/**
* lua_rawgetp [-0, +1, ]
*
* Pushes onto the stack the value t[k], where t is the table at the given
* index and k is the pointer p represented as a light userdata. The access
* is raw; that is, it does not use the __index metavalue.
*
* Returns the type of the pushed value.
*/
LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
Table *t;
TValue k;
@ -911,6 +951,17 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
}
/**
* lua_createtable [-0, +1, m]
*
* Creates a new empty table and pushes it onto the stack. Parameter narr is
* a hint for how many elements the table will have as a sequence; parameter
* nrec is a hint for how many other elements the table will have. Lua may
* use these hints to preallocate memory for the new table. This
* preallocation may help performance when you know in advance how many
* elements the table will have. Otherwise you can use the function
* lua_newtable.
*/
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
@ -924,6 +975,15 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
}
/**
* lua_getmetatable [-0, +(0|1), ]
*
* int lua_getmetatable (lua_State *L, int index);
*
* If the value at the given index has a metatable, the function pushes that
* metatable onto the stack and returns 1. Otherwise, the function returns 0
* and pushes nothing on the stack.
*/
LUA_API int lua_getmetatable (lua_State *L, int objindex) {
const TValue *obj;
Table *mt;
@ -951,6 +1011,17 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
}
/**
* lua_getiuservalue [-0, +1, ]
*
* int lua_getiuservalue (lua_State *L, int index, int n);
*
* Pushes onto the stack the n-th user value associated with the full
* userdata at the given index and returns the type of the pushed value.
*
* If the userdata does not have that value, pushes nil and returns
* LUA_TNONE.
*/
LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
TValue *o;
int t;
@ -1116,6 +1187,15 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
}
/**
* lua_setmetatable [-1, +0, ]
*
* Pops a table or nil from the stack and sets that value as the new
* metatable for the value at the given index. (nil means no metatable.)
*
* (For historical reasons, this function returns an int, which now is always
* 1.)
*/
LUA_API int lua_setmetatable (lua_State *L, int objindex) {
TValue *obj;
Table *mt;
@ -1156,6 +1236,13 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
}
/**
* lua_setiuservalue [-1, +0, ]
*
* Pops a value from the stack and sets it as the new n-th user value
* associated to the full userdata at the given index. Returns 0 if the
* userdata does not have that value.
*/
LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
TValue *o;
int res;

View file

@ -45,6 +45,12 @@
('a' <= c_ && c_ <= 'f')); \
})
#define lisbdigit(C) \
({ \
unsigned char c_ = (C); \
'0' <= c_&& c_ <= '1'; \
})
#define lisprint(C) \
({ \
unsigned char c_ = (C); \

View file

@ -27,7 +27,6 @@
*/
#define lobject_c
#define LUA_CORE
#include "libc/intrin/kprintf.h"
#include "third_party/lua/lctype.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
@ -285,6 +284,14 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
empty = 0;
}
}
if (s[0] == '0' &&
(s[1] == 'b' || s[1] == 'B')) { /* [jart] binary */
s += 2; /* skip '0b' */
for (; lisbdigit(cast_uchar(*s)); s++) {
a = a * 2 + (*s - '0');
empty = 0;
}
}
else if (s[0] == '0') { /* [jart] octal is the best radix */
for (s += 1; lisdigit(cast_uchar(*s)); s++) {
int d = *s - '0';

View file

@ -30,13 +30,13 @@
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#include "third_party/linenoise/linenoise.h"
@ -330,7 +330,7 @@ void lua_initrepl(lua_State *L, const char *progname) {
prompt = get_prompt(L, 1);
if ((g_historypath = linenoiseGetHistoryPath(progname))) {
if (linenoiseHistoryLoad(g_historypath) == -1) {
kprintf("%r%s: failed to load history: %m%n", g_historypath);
fprintf(stderr, "%r%s: failed to load history: %m%n", g_historypath);
free(g_historypath);
g_historypath = 0;
}

View file

@ -16,23 +16,37 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/fmt/itoa.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/append.internal.h"
#include "net/http/escape.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/visitor.h"
static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
char *numformat, int idx) {
char *numformat, int idx,
struct LuaVisited *visited) {
char *s;
bool isarray;
size_t tbllen, z;
size_t tbllen, i, z;
char ibuf[21], fmt[] = "%.14g";
if (level > 0) {
switch (lua_type(L, idx)) {
case LUA_TNIL:
appendw(buf, READ32LE("null"));
return 0;
case LUA_TBOOLEAN:
appendw(buf, lua_toboolean(L, idx) ? READ32LE("true")
: READ64LE("false\0\0"));
return 0;
case LUA_TSTRING:
s = lua_tolstring(L, idx, &z);
s = EscapeJsStringLiteral(s, z, &z);
@ -41,21 +55,7 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
appendw(buf, '"');
free(s);
return 0;
case LUA_TNIL:
appendw(buf, READ32LE("null"));
return 0;
case LUA_TFUNCTION:
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
return 0;
case LUA_TUSERDATA:
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
return 0;
case LUA_TLIGHTUSERDATA:
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
return 0;
case LUA_TTHREAD:
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
return 0;
case LUA_TNUMBER:
if (lua_isinteger(L, idx)) {
appendd(buf, ibuf,
@ -78,58 +78,64 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
appendf(buf, fmt, lua_tonumber(L, idx));
}
return 0;
case LUA_TBOOLEAN:
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
return 0;
case LUA_TTABLE:
tbllen = lua_rawlen(L, idx);
// encode tables with numeric indices and empty tables as arrays
isarray =
tbllen > 0 || // integer keys present
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
appendw(buf, isarray ? '[' : '{');
if (isarray) {
for (size_t i = 1; i <= tbllen; i++) {
if (i > 1) appendw(buf, ',');
lua_rawgeti(L, -1, i); // table/-2, value/-1
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
lua_pop(L, 1);
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
tbllen = lua_rawlen(L, idx);
// encode tables with numeric indices and empty tables as arrays
isarray =
tbllen > 0 || // integer keys present
(lua_pushnil(L), !lua_next(L, -2)) || // no non-integer keys
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
appendw(buf, isarray ? '[' : '{');
if (isarray) {
for (i = 1; i <= tbllen; i++) {
if (i > 1) appendw(buf, ',');
lua_rawgeti(L, -1, i); // table/-2, value/-1
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
lua_pop(L, 1);
}
} else {
i = 1;
lua_pushnil(L); // push the first key
while (lua_next(L, -2)) {
if (!lua_isstring(L, -2)) {
luaL_error(L, "expected number or string as key value");
unreachable;
}
if (i++ > 1) appendw(buf, ',');
appendw(buf, '"');
if (lua_type(L, -2) == LUA_TSTRING) {
s = lua_tolstring(L, -2, &z);
s = EscapeJsStringLiteral(s, z, &z);
appendd(buf, s, z);
free(s);
} else {
// we'd still prefer to use lua_tostring on a numeric index, but
// can't use it in-place, as it breaks lua_next (changes numeric
// key to a string)
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
s = lua_tolstring(L, idx, &z);
appendd(buf, s, z); // use the copy
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
}
appendw(buf, '"' | ':' << 010);
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
lua_pop(L, 1); // table/-2, key/-1
}
// stack: table/-1, as the key was popped by lua_next
}
appendw(buf, isarray ? ']' : '}');
LuaPopVisit(visited);
return 0;
} else {
int i = 1;
lua_pushnil(L); // push the first key
while (lua_next(L, -2)) {
if (!lua_isstring(L, -2)) {
luaL_error(L, "expected number or string as key value");
unreachable;
}
if (i++ > 1) appendw(buf, ',');
appendw(buf, '"');
if (lua_type(L, -2) == LUA_TSTRING) {
s = lua_tolstring(L, -2, &z);
s = EscapeJsStringLiteral(s, z, &z);
appendd(buf, s, z);
free(s);
} else {
// we'd still prefer to use lua_tostring on a numeric index, but
// can't use it in-place, as it breaks lua_next (changes numeric
// key to a string)
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
s = lua_tolstring(L, idx, &z);
appendd(buf, s, z); // use the copy
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
}
appendw(buf, '"' | ':' << 010);
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
lua_pop(L, 1); // table/-2, key/-1
}
// stack: table/-1, as the key was popped by lua_next
// TODO(jart): don't leak memory with longjmp
luaL_error(L, "can't serialize cyclic data structure to json");
unreachable;
}
appendw(buf, isarray ? ']' : '}');
return 0;
default:
luaL_error(L, "can't serialize value of this type");
luaL_error(L, "won't serialize %s to json", luaL_typename(L, idx));
unreachable;
}
} else {
@ -140,6 +146,9 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
int LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
int rc;
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx);
struct LuaVisited visited = {0};
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx, &visited);
assert(!visited.n);
free(visited.p);
return rc;
}

View file

@ -25,39 +25,44 @@
#include "libc/x/x.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lctype.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/visitor.h"
struct Visited {
int n;
void **p;
};
static bool PushVisit(struct Visited *visited, void *p) {
int i;
for (i = 0; i < visited->n; ++i) {
if (visited->p[i] == p) {
return false;
}
static bool IsLuaIdentifier(lua_State *L, int idx) {
size_t i, n;
const char *p;
p = luaL_checklstring(L, idx, &n);
if (!lislalpha(p[0])) return false;
for (i = 1; i < n; ++i) {
if (!lislalnum(p[i])) return false;
}
visited->p = xrealloc(visited->p, ++visited->n * sizeof(*visited->p));
visited->p[visited->n - 1] = p;
return true;
}
static void PopVisit(struct Visited *visited) {
assert(visited->n > 0);
--visited->n;
// TODO: Can we be smarter with lua_rawlen?
static bool IsLuaArray(lua_State *L) {
int i;
lua_pushnil(L);
for (i = 1; lua_next(L, -2); ++i) {
if (!lua_isinteger(L, -2) || lua_tointeger(L, -2) != i) {
lua_pop(L, 2);
return false;
}
lua_pop(L, 1);
}
return true;
}
static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
char *numformat, int idx,
struct Visited *visited) {
struct LuaVisited *visited) {
char *s;
bool didcomma;
bool isarray;
lua_Integer i;
int ktype, vtype;
size_t tbllen, buflen, slen;
char ibuf[21], fmt[] = "%.14g";
char ibuf[24], fmt[] = "%.14g";
if (level > 0) {
switch (lua_type(L, idx)) {
@ -71,15 +76,15 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
return 0;
case LUA_TFUNCTION:
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
appendf(buf, "\"func@%p\"", lua_topointer(L, idx));
return 0;
case LUA_TLIGHTUSERDATA:
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
appendf(buf, "\"light@%p\"", lua_topointer(L, idx));
return 0;
case LUA_TTHREAD:
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
appendf(buf, "\"thread@%p\"", lua_topointer(L, idx));
return 0;
case LUA_TUSERDATA:
@ -111,7 +116,7 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
case LUA_TNUMBER:
if (lua_isinteger(L, idx)) {
appendd(buf, ibuf,
FormatInt64(ibuf, luaL_checkinteger(L, idx)) - ibuf);
FormatFlex64(ibuf, luaL_checkinteger(L, idx), 2) - ibuf);
} else {
// TODO(jart): replace this api
while (*numformat == '%' || *numformat == '.' ||
@ -133,58 +138,52 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
return 0;
case LUA_TBOOLEAN:
if (lua_toboolean(L, idx)) {
appendw(buf, READ32LE("true"));
} else {
appendw(buf, READ64LE("false\0\0"));
}
appendw(buf, lua_toboolean(L, idx) ? READ32LE("true")
: READ64LE("false\0\0"));
return 0;
case LUA_TTABLE:
i = 0;
didcomma = false;
appendw(buf, '{');
lua_pushvalue(L, idx);
lua_pushnil(L); // push the first key
while (lua_next(L, -2)) {
++i;
ktype = lua_type(L, -2);
vtype = lua_type(L, -1);
if (ktype != LUA_TNUMBER || lua_tointeger(L, -2) != i) {
if (PushVisit(visited, lua_touserdata(L, -2))) {
if (i > 1) appendw(buf, ',' | ' ' << 8);
didcomma = true;
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
appendw(buf, '{');
lua_pushvalue(L, idx); // idx becomes invalid once we change stack
isarray = IsLuaArray(L);
lua_pushnil(L); // push the first key
while (lua_next(L, -2)) {
ktype = lua_type(L, -2);
vtype = lua_type(L, -1);
if (i++ > 0) appendw(buf, ',' | ' ' << 8);
if (isarray) {
// use {v₁,v₂,...} for lua-normal integer keys
} else if (ktype == LUA_TSTRING && IsLuaIdentifier(L, -2)) {
// use {𝑘=𝑣} syntax when 𝑘 is legal as a lua identifier
s = lua_tolstring(L, -2, &slen);
appendd(buf, s, slen);
appendw(buf, '=');
} else {
// use {[𝑘]=𝑣} otherwise
appendw(buf, '[');
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -2, visited);
appendw(buf, ']' | '=' << 010);
PopVisit(visited);
} else {
// TODO: Strange Lua data structure, do nothing.
lua_pop(L, 1);
continue;
}
}
if (PushVisit(visited, lua_touserdata(L, -1))) {
if (!didcomma && i > 1) appendw(buf, ',' | ' ' << 8);
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -1, visited);
PopVisit(visited);
} else {
// TODO: Strange Lua data structure, do nothing.
lua_pop(L, 1);
continue;
lua_pop(L, 1); // table/-2, key/-1
}
lua_pop(L, 1); // table/-2, key/-1
lua_pop(L, 1); // table ref
LuaPopVisit(visited);
appendw(buf, '}');
} else {
appendf(buf, "\"cyclic@%p\"", lua_topointer(L, idx));
}
lua_pop(L, 1); // table
// stack: table/-1, as the key was popped by lua_next
appendw(buf, '}');
return 0;
default:
// TODO(jart): don't leak memory with longjmp
luaL_error(L, "can't serialize value of this type");
unreachable;
}
} else {
// TODO(jart): don't leak memory with longjmp
luaL_error(L, "too many nested tables");
unreachable;
}
@ -192,7 +191,7 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
int LuaEncodeLuaData(lua_State *L, char **buf, char *numformat, int idx) {
int rc;
struct Visited visited = {0};
struct LuaVisited visited = {0};
rc = LuaEncodeLuaDataImpl(L, buf, 64, numformat, idx, &visited);
assert(!visited.n);
free(visited.p);

38
third_party/lua/visitor.c vendored Normal file
View file

@ -0,0 +1,38 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
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.
*/
#include "libc/assert.h"
#include "libc/x/x.h"
#include "third_party/lua/visitor.h"
bool LuaPushVisit(struct LuaVisited *visited, const void *p) {
int i;
for (i = 0; i < visited->n; ++i) {
if (visited->p[i] == p) {
return false;
}
}
visited->p = xrealloc(visited->p, ++visited->n * sizeof(*visited->p));
visited->p[visited->n - 1] = p;
return true;
}
void LuaPopVisit(struct LuaVisited *visited) {
assert(visited->n > 0);
--visited->n;
}

16
third_party/lua/visitor.h vendored Normal file
View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_LUA_VISITOR_H_
#define COSMOPOLITAN_THIRD_PARTY_LUA_VISITOR_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct LuaVisited {
int n;
const void **p;
};
bool LuaPushVisit(struct LuaVisited *, const void *);
void LuaPopVisit(struct LuaVisited *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_LUA_VISITOR_H_ */

View file

@ -464,6 +464,7 @@ int main(int argc, char *argv[]) {
/* __log_level = kLogDebug; */
GetOpts(argc, argv);
for (i = 3; i < 16; ++i) close(i);
errno = 0;
// poll()'ing /dev/null stdin file descriptor on xnu returns POLLNVAL?!
if (IsWindows()) {
CHECK_EQ(3, (g_bogusfd = open("/dev/null", O_RDONLY | O_CLOEXEC)));

View file

@ -357,6 +357,10 @@ LUA ENHANCEMENTS
`0644 == 420` is the case in redbean, whereas in upstream Lua
`0644 == 644` would be the case.
- redbean supports binary (base 2) integer literals. For example
`0b1010 == 10` is the case in redbean, whereas in upstream Lua
`0b1010` would result in an error.
- redbean supports the GNU syntax for the ASCII ESC character in
string literals. For example, `"\e"` is the same as `"\x1b"`.
@ -1284,6 +1288,31 @@ FUNCTIONS
possibly because your system is under load and the benchmark was
preempted by the operating system, or moved to a different core.
oct(int)
└─→ str
Formats string as octal integer literal string. If the provided
value is zero, the result will be `"0"`. Otherwise the resulting
value will be the zero-prefixed octal string. The result is
currently modulo 2^64. Negative numbers are converted to unsigned.
hex(int)
└─→ str
Formats string as hexadecimal integer literal string. If the
provided value is zero, the result will be `"0"`. Otherwise the
resulting value will be the `"0x"`-prefixed hex string. The result
is currently modulo 2^64. Negative numbers are converted to
unsigned.
bin(int)
└─→ str
Formats string as binary integer literal string. If the provided
value is zero, the result will be `"0"`. Otherwise the resulting
value will be the `"0b"`-prefixed binary str. The result is
currently modulo 2^64. Negative numbers are converted to unsigned.
────────────────────────────────────────────────────────────────────────────────
@ -1745,6 +1774,27 @@ UNIX MODULE
end
end
unix.WIFEXITED(wstatus:int)
└─→ bool
Returns true if process exited cleanly.
unix.WEXITSTATUS(wstatus:int)
└─→ exitcode:uint8
Returns code passed to exit() assuming `WIFEXITED(wstatus)` is true.
unix.WIFSIGNALED(wstatus:int)
└─→ bool
Returns true if process terminated due to a signal.
unix.WTERMSIG(wstatus:int)
└─→ sig:uint8
Returns signal that caused process to terminate assuming
`WIFSIGNALED(wstatus)` is true.
unix.getpid()
└─→ pid:int

View file

@ -20,6 +20,7 @@
#include "libc/bits/popcnt.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/rusage.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
@ -60,6 +61,33 @@ static int Rdpid(void) {
return rdpid();
}
int LuaHex(lua_State *L) {
char b[19];
uint64_t x;
x = luaL_checkinteger(L, 1);
FormatHex64(b, x, true);
lua_pushstring(L, b);
return 1;
}
int LuaOct(lua_State *L) {
char b[24];
uint64_t x;
x = luaL_checkinteger(L, 1);
FormatOctal64(b, x, true);
lua_pushstring(L, b);
return 1;
}
int LuaBin(lua_State *L) {
char b[67];
uint64_t x;
x = luaL_checkinteger(L, 1);
FormatBinary64(b, x, 2);
lua_pushstring(L, b);
return 1;
}
int LuaGetTime(lua_State *L) {
lua_pushnumber(L, nowl());
return 1;
@ -258,7 +286,7 @@ int LuaPopcnt(lua_State *L) {
int LuaBsr(lua_State *L) {
long x;
if ((x = luaL_checkinteger(L, 1))) {
lua_pushinteger(L, bsr(x));
lua_pushinteger(L, bsrl(x));
return 1;
} else {
luaL_argerror(L, 1, "zero");
@ -269,7 +297,7 @@ int LuaBsr(lua_State *L) {
int LuaBsf(lua_State *L) {
long x;
if ((x = luaL_checkinteger(L, 1))) {
lua_pushinteger(L, bsf(x));
lua_pushinteger(L, bsfl(x));
return 1;
} else {
luaL_argerror(L, 1, "zero");

View file

@ -12,6 +12,7 @@ int luaopen_argon2(lua_State *);
int luaopen_lsqlite3(lua_State *);
int LuaBenchmark(lua_State *);
int LuaBin(lua_State *);
int LuaBsf(lua_State *);
int LuaBsr(lua_State *);
int LuaCategorizeIp(lua_State *);
@ -45,6 +46,7 @@ int LuaGetMonospaceWidth(lua_State *);
int LuaGetRandomBytes(lua_State *);
int LuaGetTime(lua_State *);
int LuaHasControlCodes(lua_State *);
int LuaHex(lua_State *);
int LuaIndentLines(lua_State *);
int LuaIsAcceptableHost(lua_State *);
int LuaIsAcceptablePath(lua_State *);
@ -58,6 +60,7 @@ int LuaIsValidHttpToken(lua_State *);
int LuaLemur64(lua_State *);
int LuaMd5(lua_State *);
int LuaMeasureEntropy(lua_State *);
int LuaOct(lua_State *);
int LuaParseHost(lua_State *);
int LuaParseHttpDateTime(lua_State *);
int LuaParseIp(lua_State *);

View file

@ -192,6 +192,22 @@ STATIC_YOINK("zip_uri_support");
#define HeaderEqualCase(H, S) \
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
#define TRACE_BEGIN \
do { \
if (!IsTiny()) { \
if (funtrace) ++g_ftrace; \
if (systrace) ++__strace; \
} \
} while (0)
#define TRACE_END \
do { \
if (!IsTiny()) { \
if (funtrace) --g_ftrace; \
if (systrace) --__strace; \
} \
} while (0)
// letters not used: EIJNOQWXYnoqwxy
// digits not used: 0123456789
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
@ -5066,6 +5082,9 @@ static const luaL_Reg kLuaFuncs[] = {
{"Underlong", LuaUnderlong}, //
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
{"Write", LuaWrite}, //
{"bin", LuaBin}, //
{"hex", LuaHex}, //
{"oct", LuaOct}, //
#ifndef UNSECURE
{"Fetch", LuaFetch}, //
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
@ -5196,7 +5215,6 @@ static void LuaPrint(lua_State *L) {
static void LuaInterpreter(lua_State *L) {
int i, n, sig, status;
const char *script;
if (funtrace) ftrace_install();
if (optind < __argc) {
script = __argv[optind];
if (!strcmp(script, "-")) script = 0;
@ -5206,11 +5224,9 @@ static void LuaInterpreter(lua_State *L) {
luaL_checkstack(L, n + 3, "too many script args");
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
lua_remove(L, -i); // remove arg table from stack
if (funtrace) ++g_ftrace;
if (systrace) ++__strace;
TRACE_BEGIN;
status = lua_runchunk(L, n, LUA_MULTRET);
if (systrace) --__strace;
if (funtrace) --g_ftrace;
TRACE_END;
}
lua_report(L, status);
} else {
@ -5233,9 +5249,9 @@ static void LuaInterpreter(lua_State *L) {
exit(1);
}
if (status == LUA_OK) {
if (funtrace) ++g_ftrace;
TRACE_BEGIN;
status = lua_runchunk(GL, 0, LUA_MULTRET);
if (funtrace) --g_ftrace;
TRACE_END;
}
if (status == LUA_OK) {
LuaPrint(GL);
@ -6365,19 +6381,10 @@ static int HandleConnection(size_t i) {
meltdown = false;
__isworker = true;
connectionclose = false;
if (!IsTiny()) {
if (systrace) {
__strace = 1;
__kbirth = rdtsc();
}
if (funtrace) {
if (ftrace_install() != -1) {
g_ftrace = 1;
} else {
WARNF("ftrace failed to install %m");
}
}
if (!IsTiny() && systrace) {
__kbirth = rdtsc();
}
TRACE_BEGIN;
if (sandboxed) {
CHECK_NE(-1, EnableSandbox());
}
@ -6850,7 +6857,6 @@ static void GetOpts(int argc, char *argv[]) {
CASE('S', ++sandboxed);
CASE('v', ++__log_level);
CASE('s', --__log_level);
CASE('f', funtrace = true);
CASE('Z', systrace = true);
CASE('b', logbodies = true);
CASE('z', printport = true);
@ -6889,6 +6895,12 @@ static void GetOpts(int argc, char *argv[]) {
CASE('C', ProgramFile(optarg, ProgramCertificate));
CASE('K', ProgramFile(optarg, ProgramPrivateKey));
#endif
case 'f':
funtrace = true;
if (ftrace_install() == -1) {
WARNF("ftrace failed to install %m");
}
break;
default:
PrintUsage(2, EX_USAGE);
}