mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make redbean serialization deterministic
This commit is contained in:
parent
85aecbda67
commit
c9e68b0ebc
15 changed files with 452 additions and 150 deletions
11
libc/log/rop.h
Normal file
11
libc/log/rop.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_LOG_ROP_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_LOG_ROP_H_
|
||||||
|
|
||||||
|
#define RETURN_ON_ERROR(expr) \
|
||||||
|
do { \
|
||||||
|
if ((expr) == -1) { \
|
||||||
|
goto OnError; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_LOG_ROP_H_ */
|
80
libc/stdio/strlist.c
Normal file
80
libc/stdio/strlist.c
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*-*- 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/alg/alg.h"
|
||||||
|
#include "libc/stdio/append.internal.h"
|
||||||
|
#include "libc/stdio/strlist.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
static int CompareStrings(const void *p1, const void *p2) {
|
||||||
|
const char **a = p1;
|
||||||
|
const char **b = p2;
|
||||||
|
return strcmp(*a, *b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeStrList(struct StrList *sl) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sl->i; ++i) {
|
||||||
|
free(sl->p[i]);
|
||||||
|
}
|
||||||
|
free(sl->p);
|
||||||
|
sl->p = 0;
|
||||||
|
sl->i = 0;
|
||||||
|
sl->n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppendStrList(struct StrList *sl) {
|
||||||
|
int n2;
|
||||||
|
char **p2;
|
||||||
|
if (sl->i == sl->n) {
|
||||||
|
n2 = sl->n;
|
||||||
|
if (!n2) n2 = 2;
|
||||||
|
n2 += n2 >> 1;
|
||||||
|
if ((p2 = realloc(sl->p, n2 * sizeof(*p2)))) {
|
||||||
|
sl->p = p2;
|
||||||
|
sl->n = n2;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sl->p[sl->i] = 0;
|
||||||
|
appendr(&sl->p[sl->i], 0);
|
||||||
|
return sl->i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortStrList(struct StrList *sl) {
|
||||||
|
qsort(sl->p, sl->i, sizeof(*sl->p), CompareStrings);
|
||||||
|
}
|
||||||
|
|
||||||
|
int JoinStrList(struct StrList *sl, char **buf, uint64_t sep) {
|
||||||
|
int i;
|
||||||
|
if (!*buf && !sl->i) {
|
||||||
|
return appendr(buf, 0);
|
||||||
|
}
|
||||||
|
for (i = 0; i < sl->i; ++i) {
|
||||||
|
if (i) {
|
||||||
|
if (appendw(buf, sep) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (appends(buf, sl->p[i]) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
18
libc/stdio/strlist.internal.h
Normal file
18
libc/stdio/strlist.internal.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_STDIO_STRLIST_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_STDIO_STRLIST_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
struct StrList {
|
||||||
|
int i, n;
|
||||||
|
char **p;
|
||||||
|
};
|
||||||
|
|
||||||
|
void FreeStrList(struct StrList *) hidden;
|
||||||
|
int AppendStrList(struct StrList *) hidden;
|
||||||
|
void SortStrList(struct StrList *) hidden;
|
||||||
|
int JoinStrList(struct StrList *, char **, uint64_t) hidden;
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_STDIO_STRLIST_H_ */
|
58
test/libc/stdio/strlist_test.c
Normal file
58
test/libc/stdio/strlist_test.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*-*- 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/bits/bits.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/gc.internal.h"
|
||||||
|
#include "libc/stdio/append.internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/stdio/strlist.internal.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
struct StrList sl;
|
||||||
|
|
||||||
|
void TearDown(void) {
|
||||||
|
FreeStrList(&sl);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(strlist, test) {
|
||||||
|
int i;
|
||||||
|
char *b = 0;
|
||||||
|
ASSERT_NE(-1, (i = AppendStrList(&sl)));
|
||||||
|
ASSERT_NE(-1, appends(&sl.p[i], "world"));
|
||||||
|
ASSERT_NE(-1, (i = AppendStrList(&sl)));
|
||||||
|
ASSERT_NE(-1, appends(&sl.p[i], "hello"));
|
||||||
|
SortStrList(&sl);
|
||||||
|
ASSERT_NE(-1, JoinStrList(&sl, &b, READ16LE(", ")));
|
||||||
|
EXPECT_STREQ("hello, world", b);
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(strlist, testNumbers) {
|
||||||
|
int i;
|
||||||
|
char *b = 0;
|
||||||
|
ASSERT_NE(-1, (i = AppendStrList(&sl)));
|
||||||
|
ASSERT_NE(-1, appends(&sl.p[i], "2"));
|
||||||
|
ASSERT_NE(-1, (i = AppendStrList(&sl)));
|
||||||
|
ASSERT_NE(-1, appends(&sl.p[i], "1"));
|
||||||
|
SortStrList(&sl);
|
||||||
|
ASSERT_NE(-1, JoinStrList(&sl, &b, ':'));
|
||||||
|
EXPECT_STREQ("1:2", b);
|
||||||
|
free(b);
|
||||||
|
}
|
|
@ -54,22 +54,39 @@ assert(EncodeLatin1("helloÿÀ") == "hello\xff\xc0")
|
||||||
assert(EncodeLua(nil) == "nil")
|
assert(EncodeLua(nil) == "nil")
|
||||||
assert(EncodeLua(0) == "0")
|
assert(EncodeLua(0) == "0")
|
||||||
assert(EncodeLua(3.14) == "3.14")
|
assert(EncodeLua(3.14) == "3.14")
|
||||||
assert(EncodeLua({1, 2}) == "{1, 2}")
|
assert(EncodeLua({2, 1}) == "{1, 2}")
|
||||||
x = {1, 2}
|
|
||||||
x[3] = x
|
|
||||||
assert(string.match(EncodeLua(x), "{1, 2, \"cyclic@0x%x+\"}"))
|
|
||||||
|
|
||||||
-- TODO(jart): EncodeLua() should sort tables
|
|
||||||
-- x = {}
|
|
||||||
-- x.c = 'c'
|
|
||||||
-- x.a = 'a'
|
|
||||||
-- x.b = 'b'
|
|
||||||
-- assert(EncodeLua(x) == '{a="a", b="b", c="c"}')
|
|
||||||
|
|
||||||
assert(EncodeJson(nil) == "null")
|
assert(EncodeJson(nil) == "null")
|
||||||
assert(EncodeJson(0) == "0")
|
assert(EncodeJson(0) == "0")
|
||||||
assert(EncodeJson(3.14) == "3.14")
|
assert(EncodeJson(3.14) == "3.14")
|
||||||
assert(EncodeJson({1, 2}) == "[1,2]")
|
assert(EncodeJson({2, 1}) == "[1,2]")
|
||||||
|
|
||||||
|
-- EncodeLua() permits serialization of cyclic data structures
|
||||||
|
x = {2, 1}
|
||||||
|
x[3] = x
|
||||||
|
assert(string.match(EncodeLua(x), "{\"cyclic@0x%x+\", 1, 2}"))
|
||||||
|
|
||||||
|
-- EncodeLua() sorts table entries
|
||||||
|
x = {}
|
||||||
|
x.c = 'c'
|
||||||
|
x.a = 'a'
|
||||||
|
x.b = 'b'
|
||||||
|
assert(EncodeLua(x) == '{a="a", b="b", c="c"}')
|
||||||
|
|
||||||
|
-- EncodeJson() doesn't permit serialization of cyclic data structures
|
||||||
|
x = {2, 1}
|
||||||
|
x[3] = x
|
||||||
|
json, err = EncodeJson(x)
|
||||||
|
assert(not json)
|
||||||
|
assert(err == "serialization failed")
|
||||||
|
|
||||||
|
-- EncodeJson() sorts table entries
|
||||||
|
-- JSON always requires quotes around key names
|
||||||
|
x = {}
|
||||||
|
x.c = 'c'
|
||||||
|
x.a = 'a'
|
||||||
|
x.b = 'b'
|
||||||
|
assert(EncodeJson(x) == '{"a":"a","b":"b","c":"c"}')
|
||||||
|
|
||||||
url = ParseUrl("https://jart:pass@redbean.dev/2.0.html?x&y=z#frag")
|
url = ParseUrl("https://jart:pass@redbean.dev/2.0.html?x&y=z#frag")
|
||||||
assert(url.scheme == "https")
|
assert(url.scheme == "https")
|
||||||
|
@ -141,3 +158,17 @@ 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") == "\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) == "\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")
|
assert(Compress("hello", 0, true) == "x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15")
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
-- benchmarks
|
||||||
|
|
||||||
|
function LuaSerialization()
|
||||||
|
EncodeLua({2, 1, 10, 3, "hello"})
|
||||||
|
end
|
||||||
|
|
||||||
|
function JsonSerialization()
|
||||||
|
EncodeJson({2, 1, 10, 3, "hello"})
|
||||||
|
end
|
||||||
|
|
||||||
|
print(Benchmark(LuaSerialization), "LuaSerialization")
|
||||||
|
print(Benchmark(JsonSerialization), "JsonSerialization")
|
||||||
|
|
|
@ -140,8 +140,11 @@ function UnixTest()
|
||||||
assert(unix.close(fd))
|
assert(unix.close(fd))
|
||||||
|
|
||||||
-- getdents
|
-- getdents
|
||||||
|
t = {}
|
||||||
for name, kind, ino, off in assert(unix.opendir(tmpdir)) do
|
for name, kind, ino, off in assert(unix.opendir(tmpdir)) do
|
||||||
|
table.insert(t, name)
|
||||||
end
|
end
|
||||||
|
assert(EncodeLua(t) == '{".", "..", "foo"}');
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
2
third_party/lua/cosmo.h
vendored
2
third_party/lua/cosmo.h
vendored
|
@ -14,7 +14,7 @@ int LuaEncodeUrl(lua_State *);
|
||||||
int LuaParseUrl(lua_State *);
|
int LuaParseUrl(lua_State *);
|
||||||
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
|
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
|
||||||
int LuaPushHeaders(lua_State *, struct HttpMessage *, const char *);
|
int LuaPushHeaders(lua_State *, struct HttpMessage *, const char *);
|
||||||
void EscapeLuaString(char *, size_t, char **);
|
int EscapeLuaString(char *, size_t, char **);
|
||||||
void LuaPrintStack(lua_State *);
|
void LuaPrintStack(lua_State *);
|
||||||
void LuaPushLatin1(lua_State *, const char *, size_t);
|
void LuaPushLatin1(lua_State *, const char *, size_t);
|
||||||
void LuaPushUrlParams(lua_State *, struct UrlParams *);
|
void LuaPushUrlParams(lua_State *, struct UrlParams *);
|
||||||
|
|
27
third_party/lua/escapeluastring.c
vendored
27
third_party/lua/escapeluastring.c
vendored
|
@ -17,25 +17,32 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/log/rop.h"
|
||||||
#include "libc/stdio/append.internal.h"
|
#include "libc/stdio/append.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "third_party/lua/cosmo.h"
|
#include "third_party/lua/cosmo.h"
|
||||||
#include "third_party/lua/lua.h"
|
#include "third_party/lua/lua.h"
|
||||||
|
|
||||||
void EscapeLuaString(char *s, size_t len, char **buf) {
|
int EscapeLuaString(char *s, size_t len, char **buf) {
|
||||||
appendw(buf, '"');
|
int rc;
|
||||||
for (size_t i = 0; i < len; i++) {
|
size_t i;
|
||||||
|
RETURN_ON_ERROR(appendw(buf, '"'));
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
if (' ' <= s[i] && s[i] <= 0x7e) {
|
if (' ' <= s[i] && s[i] <= 0x7e) {
|
||||||
appendw(buf, s[i]);
|
RETURN_ON_ERROR(appendw(buf, s[i]));
|
||||||
} else if (s[i] == '\n') {
|
} else if (s[i] == '\n') {
|
||||||
appendw(buf, '\\' | 'n' << 8);
|
RETURN_ON_ERROR(appendw(buf, '\\' | 'n' << 8));
|
||||||
} else if (s[i] == '\\' || s[i] == '\'' || s[i] == '\"') {
|
} else if (s[i] == '\\' || s[i] == '\'' || s[i] == '\"') {
|
||||||
appendw(buf, '\\' | s[i] << 8);
|
RETURN_ON_ERROR(appendw(buf, '\\' | s[i] << 8));
|
||||||
} else {
|
} else {
|
||||||
appendw(buf, '\\' | 'x' << 010 |
|
RETURN_ON_ERROR(
|
||||||
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
|
appendw(buf, '\\' | 'x' << 010 |
|
||||||
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030);
|
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
|
||||||
|
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendw(buf, '"');
|
RETURN_ON_ERROR(appendw(buf, '"'));
|
||||||
|
return 0;
|
||||||
|
OnError:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
88
third_party/lua/luaencodejsondata.c
vendored
88
third_party/lua/luaencodejsondata.c
vendored
|
@ -19,9 +19,11 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/log/rop.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/stdio/append.internal.h"
|
#include "libc/stdio/append.internal.h"
|
||||||
|
#include "libc/stdio/strlist.internal.h"
|
||||||
#include "net/http/escape.h"
|
#include "net/http/escape.h"
|
||||||
#include "third_party/lua/cosmo.h"
|
#include "third_party/lua/cosmo.h"
|
||||||
#include "third_party/lua/lauxlib.h"
|
#include "third_party/lua/lauxlib.h"
|
||||||
|
@ -32,34 +34,37 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
char *numformat, int idx,
|
char *numformat, int idx,
|
||||||
struct LuaVisited *visited) {
|
struct LuaVisited *visited) {
|
||||||
char *s;
|
char *s;
|
||||||
|
int sli, rc;
|
||||||
bool isarray;
|
bool isarray;
|
||||||
size_t tbllen, i, z;
|
size_t tbllen, i, z;
|
||||||
|
struct StrList sl = {0};
|
||||||
char ibuf[21], fmt[] = "%.14g";
|
char ibuf[21], fmt[] = "%.14g";
|
||||||
if (level > 0) {
|
if (level > 0) {
|
||||||
switch (lua_type(L, idx)) {
|
switch (lua_type(L, idx)) {
|
||||||
|
|
||||||
case LUA_TNIL:
|
case LUA_TNIL:
|
||||||
appendw(buf, READ32LE("null"));
|
RETURN_ON_ERROR(appendw(buf, READ32LE("null")));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TBOOLEAN:
|
case LUA_TBOOLEAN:
|
||||||
appendw(buf, lua_toboolean(L, idx) ? READ32LE("true")
|
RETURN_ON_ERROR(appendw(buf, lua_toboolean(L, idx)
|
||||||
: READ64LE("false\0\0"));
|
? READ32LE("true")
|
||||||
|
: READ64LE("false\0\0")));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
s = lua_tolstring(L, idx, &z);
|
s = lua_tolstring(L, idx, &z);
|
||||||
s = EscapeJsStringLiteral(s, z, &z);
|
if (!(s = EscapeJsStringLiteral(s, z, &z))) goto OnError;
|
||||||
appendw(buf, '"');
|
RETURN_ON_ERROR(appendw(buf, '"'));
|
||||||
appendd(buf, s, z);
|
RETURN_ON_ERROR(appendd(buf, s, z));
|
||||||
appendw(buf, '"');
|
RETURN_ON_ERROR(appendw(buf, '"'));
|
||||||
free(s);
|
free(s);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
if (lua_isinteger(L, idx)) {
|
if (lua_isinteger(L, idx)) {
|
||||||
appendd(buf, ibuf,
|
RETURN_ON_ERROR(appendd(
|
||||||
FormatInt64(ibuf, luaL_checkinteger(L, idx)) - ibuf);
|
buf, ibuf, FormatInt64(ibuf, luaL_checkinteger(L, idx)) - ibuf));
|
||||||
} else {
|
} else {
|
||||||
// TODO(jart): replace this api
|
// TODO(jart): replace this api
|
||||||
while (*numformat == '%' || *numformat == '.' ||
|
while (*numformat == '%' || *numformat == '.' ||
|
||||||
|
@ -73,16 +78,16 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
fmt[4] = *numformat;
|
fmt[4] = *numformat;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
free(visited->p);
|
// prevent format string hacking
|
||||||
luaL_error(L, "numformat string not allowed");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
RETURN_ON_ERROR(appendf(buf, fmt, lua_tonumber(L, idx)));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
|
RETURN_ON_ERROR(rc = LuaPushVisit(visited, lua_topointer(L, idx)));
|
||||||
|
if (!rc) {
|
||||||
lua_pushvalue(L, idx); // table ref
|
lua_pushvalue(L, idx); // table ref
|
||||||
tbllen = lua_rawlen(L, -1);
|
tbllen = lua_rawlen(L, -1);
|
||||||
// encode tables with numeric indices and empty tables as arrays
|
// encode tables with numeric indices and empty tables as arrays
|
||||||
|
@ -90,12 +95,12 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
tbllen > 0 || // integer keys present
|
tbllen > 0 || // integer keys present
|
||||||
(lua_pushnil(L), !lua_next(L, -2)) || // no non-integer keys
|
(lua_pushnil(L), !lua_next(L, -2)) || // no non-integer keys
|
||||||
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
||||||
appendw(buf, isarray ? '[' : '{');
|
|
||||||
if (isarray) {
|
if (isarray) {
|
||||||
for (i = 1; i <= tbllen; i++) {
|
for (i = 1; i <= tbllen; i++) {
|
||||||
if (i > 1) appendw(buf, ',');
|
RETURN_ON_ERROR(sli = AppendStrList(&sl));
|
||||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
|
RETURN_ON_ERROR(LuaEncodeJsonDataImpl(L, &sl.p[sli], level - 1,
|
||||||
|
numformat, -1, visited));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,45 +108,58 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
lua_pushnil(L); // push the first key
|
lua_pushnil(L); // push the first key
|
||||||
while (lua_next(L, -2)) {
|
while (lua_next(L, -2)) {
|
||||||
if (lua_type(L, -2) != LUA_TSTRING) {
|
if (lua_type(L, -2) != LUA_TSTRING) {
|
||||||
free(visited->p);
|
// json tables must be arrays or use string keys
|
||||||
luaL_error(L, "json tables must be arrays or use string keys");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
if (i++ > 1) appendw(buf, ',');
|
RETURN_ON_ERROR(sli = AppendStrList(&sl));
|
||||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -2, visited);
|
RETURN_ON_ERROR(LuaEncodeJsonDataImpl(L, &sl.p[sli], level - 1,
|
||||||
appendw(buf, ':');
|
numformat, -2, visited));
|
||||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
|
RETURN_ON_ERROR(appendw(&sl.p[sli], ':'));
|
||||||
|
RETURN_ON_ERROR(LuaEncodeJsonDataImpl(L, &sl.p[sli], level - 1,
|
||||||
|
numformat, -1, visited));
|
||||||
lua_pop(L, 1); // table/-2, key/-1
|
lua_pop(L, 1); // table/-2, key/-1
|
||||||
}
|
}
|
||||||
// stack: table/-1, as the key was popped by lua_next
|
// stack: table/-1, as the key was popped by lua_next
|
||||||
}
|
}
|
||||||
appendw(buf, isarray ? ']' : '}');
|
RETURN_ON_ERROR(appendw(buf, isarray ? '[' : '{'));
|
||||||
|
SortStrList(&sl);
|
||||||
|
RETURN_ON_ERROR(JoinStrList(&sl, buf, ','));
|
||||||
|
FreeStrList(&sl);
|
||||||
|
RETURN_ON_ERROR(appendw(buf, isarray ? ']' : '}'));
|
||||||
LuaPopVisit(visited);
|
LuaPopVisit(visited);
|
||||||
lua_pop(L, 1); // table ref
|
lua_pop(L, 1); // table ref
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
free(visited->p);
|
// cyclic data structure
|
||||||
luaL_error(L, "can't serialize cyclic data structure to json");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
free(visited->p);
|
// unsupported lua type
|
||||||
luaL_error(L, "won't serialize %s to json", luaL_typename(L, idx));
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
free(visited->p);
|
// too much depth
|
||||||
luaL_error(L, "too many nested tables");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
OnError:
|
||||||
|
FreeStrList(&sl);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes Lua data structure as JSON.
|
||||||
|
*
|
||||||
|
* @param L is Lua interpreter state
|
||||||
|
* @param buf receives encoded output string
|
||||||
|
* @param numformat controls double formatting
|
||||||
|
* @param idx is index of item on Lua stack
|
||||||
|
* @return 0 on success, or -1 on error
|
||||||
|
*/
|
||||||
int LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
|
int LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||||
int rc;
|
int rc;
|
||||||
struct LuaVisited visited = {0};
|
struct LuaVisited visited = {0};
|
||||||
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx, &visited);
|
rc = LuaEncodeJsonDataImpl(L, buf, 64, numformat, idx, &visited);
|
||||||
assert(!visited.n);
|
|
||||||
free(visited.p);
|
free(visited.p);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
102
third_party/lua/luaencodeluadata.c
vendored
102
third_party/lua/luaencodeluadata.c
vendored
|
@ -19,9 +19,11 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/log/rop.h"
|
||||||
#include "libc/math.h"
|
#include "libc/math.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/stdio/append.internal.h"
|
#include "libc/stdio/append.internal.h"
|
||||||
|
#include "libc/stdio/strlist.internal.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "third_party/lua/cosmo.h"
|
#include "third_party/lua/cosmo.h"
|
||||||
#include "third_party/lua/lauxlib.h"
|
#include "third_party/lua/lauxlib.h"
|
||||||
|
@ -60,41 +62,45 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
char *s;
|
char *s;
|
||||||
bool isarray;
|
bool isarray;
|
||||||
lua_Integer i;
|
lua_Integer i;
|
||||||
int ktype, vtype;
|
struct StrList sl = {0};
|
||||||
|
int ktype, vtype, sli, rc;
|
||||||
size_t tbllen, buflen, slen;
|
size_t tbllen, buflen, slen;
|
||||||
char ibuf[24], fmt[] = "%.14g";
|
char ibuf[24], fmt[] = "%.14g";
|
||||||
if (level > 0) {
|
if (level > 0) {
|
||||||
switch (lua_type(L, idx)) {
|
switch (lua_type(L, idx)) {
|
||||||
|
|
||||||
case LUA_TNIL:
|
case LUA_TNIL:
|
||||||
appendw(buf, READ32LE("nil"));
|
RETURN_ON_ERROR(appendw(buf, READ32LE("nil")));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
s = lua_tolstring(L, idx, &slen);
|
s = lua_tolstring(L, idx, &slen);
|
||||||
EscapeLuaString(s, slen, buf);
|
RETURN_ON_ERROR(EscapeLuaString(s, slen, buf));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TFUNCTION:
|
case LUA_TFUNCTION:
|
||||||
appendf(buf, "\"func@%p\"", lua_topointer(L, idx));
|
RETURN_ON_ERROR(
|
||||||
|
appendf(buf, "\"%s@%p\"", "func", lua_topointer(L, idx)));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TLIGHTUSERDATA:
|
case LUA_TLIGHTUSERDATA:
|
||||||
appendf(buf, "\"light@%p\"", lua_topointer(L, idx));
|
RETURN_ON_ERROR(
|
||||||
|
appendf(buf, "\"%s@%p\"", "light", lua_topointer(L, idx)));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TTHREAD:
|
case LUA_TTHREAD:
|
||||||
appendf(buf, "\"thread@%p\"", lua_topointer(L, idx));
|
RETURN_ON_ERROR(
|
||||||
|
appendf(buf, "\"%s@%p\"", "thread", lua_topointer(L, idx)));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA:
|
||||||
if (luaL_callmeta(L, idx, "__repr")) {
|
if (luaL_callmeta(L, idx, "__repr")) {
|
||||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||||
s = lua_tolstring(L, -1, &slen);
|
s = lua_tolstring(L, -1, &slen);
|
||||||
appendd(buf, s, slen);
|
RETURN_ON_ERROR(appendd(buf, s, slen));
|
||||||
} else {
|
} else {
|
||||||
appendf(buf, "[[error %s returned a %s value]]", "__repr",
|
RETURN_ON_ERROR(appendf(buf, "[[error %s returned a %s value]]",
|
||||||
luaL_typename(L, -1));
|
"__repr", luaL_typename(L, -1)));
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -102,21 +108,23 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
if (luaL_callmeta(L, idx, "__tostring")) {
|
if (luaL_callmeta(L, idx, "__tostring")) {
|
||||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||||
s = lua_tolstring(L, -1, &slen);
|
s = lua_tolstring(L, -1, &slen);
|
||||||
EscapeLuaString(s, slen, buf);
|
RETURN_ON_ERROR(EscapeLuaString(s, slen, buf));
|
||||||
} else {
|
} else {
|
||||||
appendf(buf, "[[error %s returned a %s value]]", "__tostring",
|
RETURN_ON_ERROR(appendf(buf, "[[error %s returned a %s value]]",
|
||||||
luaL_typename(L, -1));
|
"__tostring", luaL_typename(L, -1)));
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
RETURN_ON_ERROR(
|
||||||
|
appendf(buf, "\"%s@%p\"", "udata", lua_touserdata(L, idx)));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
if (lua_isinteger(L, idx)) {
|
if (lua_isinteger(L, idx)) {
|
||||||
appendd(buf, ibuf,
|
RETURN_ON_ERROR(
|
||||||
FormatFlex64(ibuf, luaL_checkinteger(L, idx), 2) - ibuf);
|
appendd(buf, ibuf,
|
||||||
|
FormatFlex64(ibuf, luaL_checkinteger(L, idx), 2) - ibuf));
|
||||||
} else {
|
} else {
|
||||||
// TODO(jart): replace this api
|
// TODO(jart): replace this api
|
||||||
while (*numformat == '%' || *numformat == '.' ||
|
while (*numformat == '%' || *numformat == '.' ||
|
||||||
|
@ -130,71 +138,87 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
fmt[4] = *numformat;
|
fmt[4] = *numformat;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
free(visited->p);
|
// prevent format string hacking
|
||||||
luaL_error(L, "numformat string not allowed");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
RETURN_ON_ERROR(appendf(buf, fmt, lua_tonumber(L, idx)));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TBOOLEAN:
|
case LUA_TBOOLEAN:
|
||||||
appendw(buf, lua_toboolean(L, idx) ? READ32LE("true")
|
RETURN_ON_ERROR(appendw(buf, lua_toboolean(L, idx)
|
||||||
: READ64LE("false\0\0"));
|
? READ32LE("true")
|
||||||
|
: READ64LE("false\0\0")));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
i = 0;
|
i = 0;
|
||||||
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
|
RETURN_ON_ERROR(rc = LuaPushVisit(visited, lua_topointer(L, idx)));
|
||||||
appendw(buf, '{');
|
if (!rc) {
|
||||||
lua_pushvalue(L, idx); // idx becomes invalid once we change stack
|
lua_pushvalue(L, idx); // idx becomes invalid once we change stack
|
||||||
isarray = IsLuaArray(L);
|
isarray = IsLuaArray(L);
|
||||||
lua_pushnil(L); // push the first key
|
lua_pushnil(L); // push the first key
|
||||||
while (lua_next(L, -2)) {
|
while (lua_next(L, -2)) {
|
||||||
ktype = lua_type(L, -2);
|
ktype = lua_type(L, -2);
|
||||||
vtype = lua_type(L, -1);
|
vtype = lua_type(L, -1);
|
||||||
if (i++ > 0) appendw(buf, ',' | ' ' << 8);
|
RETURN_ON_ERROR(sli = AppendStrList(&sl));
|
||||||
if (isarray) {
|
if (isarray) {
|
||||||
// use {v₁′,v₂′,...} for lua-normal integer keys
|
// use {v₁′,v₂′,...} for lua-normal integer keys
|
||||||
} else if (ktype == LUA_TSTRING && IsLuaIdentifier(L, -2)) {
|
} else if (ktype == LUA_TSTRING && IsLuaIdentifier(L, -2)) {
|
||||||
// use {𝑘=𝑣′} syntax when 𝑘 is legal as a lua identifier
|
// use {𝑘=𝑣′} syntax when 𝑘 is legal as a lua identifier
|
||||||
s = lua_tolstring(L, -2, &slen);
|
s = lua_tolstring(L, -2, &slen);
|
||||||
appendd(buf, s, slen);
|
RETURN_ON_ERROR(appendd(&sl.p[sli], s, slen));
|
||||||
appendw(buf, '=');
|
RETURN_ON_ERROR(appendw(&sl.p[sli], '='));
|
||||||
} else {
|
} else {
|
||||||
// use {[𝑘′]=𝑣′} otherwise
|
// use {[𝑘′]=𝑣′} otherwise
|
||||||
appendw(buf, '[');
|
RETURN_ON_ERROR(appendw(&sl.p[sli], '['));
|
||||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -2, visited);
|
RETURN_ON_ERROR(LuaEncodeLuaDataImpl(L, &sl.p[sli], level - 1,
|
||||||
appendw(buf, ']' | '=' << 010);
|
numformat, -2, visited));
|
||||||
|
RETURN_ON_ERROR(appendw(&sl.p[sli], ']' | '=' << 010));
|
||||||
}
|
}
|
||||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -1, visited);
|
RETURN_ON_ERROR(LuaEncodeLuaDataImpl(L, &sl.p[sli], level - 1,
|
||||||
|
numformat, -1, visited));
|
||||||
lua_pop(L, 1); // table/-2, key/-1
|
lua_pop(L, 1); // table/-2, key/-1
|
||||||
}
|
}
|
||||||
lua_pop(L, 1); // table ref
|
lua_pop(L, 1); // table ref
|
||||||
|
RETURN_ON_ERROR(appendw(buf, '{'));
|
||||||
|
SortStrList(&sl);
|
||||||
|
RETURN_ON_ERROR(JoinStrList(&sl, buf, READ16LE(", ")));
|
||||||
|
RETURN_ON_ERROR(appendw(buf, '}'));
|
||||||
|
FreeStrList(&sl);
|
||||||
LuaPopVisit(visited);
|
LuaPopVisit(visited);
|
||||||
appendw(buf, '}');
|
|
||||||
} else {
|
} else {
|
||||||
appendf(buf, "\"cyclic@%p\"", lua_topointer(L, idx));
|
RETURN_ON_ERROR(
|
||||||
|
appendf(buf, "\"%s@%p\"", "cyclic", lua_topointer(L, idx)));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
free(visited->p);
|
// unsupported lua type
|
||||||
luaL_error(L, "can't serialize value of this type");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
free(visited->p);
|
// too much depth
|
||||||
luaL_error(L, "too many nested tables");
|
goto OnError;
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
OnError:
|
||||||
|
FreeStrList(&sl);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes Lua data structure as Lua code string.
|
||||||
|
*
|
||||||
|
* @param L is Lua interpreter state
|
||||||
|
* @param buf receives encoded output string
|
||||||
|
* @param numformat controls double formatting
|
||||||
|
* @param idx is index of item on Lua stack
|
||||||
|
* @return 0 on success, or -1 on error
|
||||||
|
*/
|
||||||
int LuaEncodeLuaData(lua_State *L, char **buf, char *numformat, int idx) {
|
int LuaEncodeLuaData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||||
int rc;
|
int rc;
|
||||||
struct LuaVisited visited = {0};
|
struct LuaVisited visited = {0};
|
||||||
rc = LuaEncodeLuaDataImpl(L, buf, 64, numformat, idx, &visited);
|
rc = LuaEncodeLuaDataImpl(L, buf, 64, numformat, idx, &visited);
|
||||||
assert(!visited.n);
|
|
||||||
free(visited.p);
|
free(visited.p);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
17
third_party/lua/visitor.c
vendored
17
third_party/lua/visitor.c
vendored
|
@ -20,16 +20,23 @@
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "third_party/lua/visitor.h"
|
#include "third_party/lua/visitor.h"
|
||||||
|
|
||||||
bool LuaPushVisit(struct LuaVisited *visited, const void *p) {
|
int LuaPushVisit(struct LuaVisited *visited, const void *p) {
|
||||||
int i;
|
int i, n2;
|
||||||
|
const void **p2;
|
||||||
for (i = 0; i < visited->n; ++i) {
|
for (i = 0; i < visited->n; ++i) {
|
||||||
if (visited->p[i] == p) {
|
if (visited->p[i] == p) {
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visited->p = xrealloc(visited->p, ++visited->n * sizeof(*visited->p));
|
n2 = visited->n;
|
||||||
|
if ((p2 = realloc(visited->p, ++n2 * sizeof(*visited->p)))) {
|
||||||
|
visited->p = p2;
|
||||||
|
visited->n = n2;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
visited->p[visited->n - 1] = p;
|
visited->p[visited->n - 1] = p;
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaPopVisit(struct LuaVisited *visited) {
|
void LuaPopVisit(struct LuaVisited *visited) {
|
||||||
|
|
2
third_party/lua/visitor.h
vendored
2
third_party/lua/visitor.h
vendored
|
@ -8,7 +8,7 @@ struct LuaVisited {
|
||||||
const void **p;
|
const void **p;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool LuaPushVisit(struct LuaVisited *, const void *);
|
int LuaPushVisit(struct LuaVisited *, const void *);
|
||||||
void LuaPopVisit(struct LuaVisited *);
|
void LuaPopVisit(struct LuaVisited *);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
|
|
@ -625,10 +625,8 @@
|
||||||
(compile (format "sh %s" file)))
|
(compile (format "sh %s" file)))
|
||||||
((eq major-mode 'lua-mode)
|
((eq major-mode 'lua-mode)
|
||||||
(let* ((mode (cosmo--make-mode arg))
|
(let* ((mode (cosmo--make-mode arg))
|
||||||
(redbean (format "%s/o/%s/tool/net/redbean.com" root mode)))
|
(redbean ))
|
||||||
(if (file-executable-p redbean)
|
(compile (format "make -j16 MODE=%s o/%s/tool/net/redbean.com && o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
|
||||||
(compile (format "%s -i %s" redbean file))
|
|
||||||
(compile (format "lua.com %s" file)))))
|
|
||||||
((and (eq major-mode 'python-mode)
|
((and (eq major-mode 'python-mode)
|
||||||
(cosmo-startswith "third_party/python/Lib/test/" file))
|
(cosmo-startswith "third_party/python/Lib/test/" file))
|
||||||
(let ((mode (cosmo--make-mode arg)))
|
(let ((mode (cosmo--make-mode arg)))
|
||||||
|
|
|
@ -647,26 +647,66 @@ FUNCTIONS
|
||||||
URIs that do things like embed a PNG file in a web page. See
|
URIs that do things like embed a PNG file in a web page. See
|
||||||
encodebase64.c.
|
encodebase64.c.
|
||||||
|
|
||||||
EncodeJson(value[,options:table]) → json:str
|
EncodeJson(value[,options:table])
|
||||||
Turns passed Lua value into a JSON string. Tables with non-zero
|
├─→ json:str
|
||||||
length (as reported by `#`) are encoded as arrays with non-array
|
├─→ true [if useoutput]
|
||||||
elements ignored. Empty tables are encoded as empty arrays. All
|
└─→ nil, error:str
|
||||||
other tables are encoded as objects with numerical keys
|
|
||||||
converted to strings (so `{[3]=1}` is encoded as `{"3":1}`).
|
Turns Lua data structure into a JSON string.
|
||||||
The following options can be used:
|
|
||||||
|
Tables with non-zero length (as reported by `#`) are encoded
|
||||||
|
as arrays with non-array elements ignored. Empty tables are
|
||||||
|
encoded as empty arrays. All other tables are encoded as
|
||||||
|
objects with numerical keys converted to strings (so `{[3]=1}`
|
||||||
|
is encoded as `{"3":1}`).
|
||||||
|
|
||||||
|
The following options may be used:
|
||||||
|
|
||||||
- useoutput: (bool=false) encodes the result directly to the
|
- useoutput: (bool=false) encodes the result directly to the
|
||||||
output buffer and returns `nil` value. This option is
|
output buffer and returns `nil` value. This option is
|
||||||
ignored if used outside of request handling code.
|
ignored if used outside of request handling code.
|
||||||
- numformat: sets numeric format to be used, which can be 'g',
|
- numformat: sets numeric format to be used, which can be 'g',
|
||||||
'f', or 'a' [experimental api]
|
'f', or 'a' [experimental api]
|
||||||
|
|
||||||
EncodeLua(value[,options:table]) → json:str
|
This function will fail if:
|
||||||
Turns passed Lua value into a Lua string. The following options
|
|
||||||
can be used:
|
- `value` is cyclic
|
||||||
|
- `value` has depth greater than 64
|
||||||
|
- `value` contains functions, user data, or threads
|
||||||
|
|
||||||
|
When arrays and objects are serialized, entries will be sorted
|
||||||
|
in a deterministic order.
|
||||||
|
|
||||||
|
EncodeLua(value[,options:table])
|
||||||
|
├─→ luacode:str
|
||||||
|
├─→ true [if useoutput]
|
||||||
|
└─→ nil, error:str
|
||||||
|
|
||||||
|
Turns Lua data structure into Lua code string.
|
||||||
|
|
||||||
|
The following options may be used:
|
||||||
|
|
||||||
- useoutput: (bool=false) encodes the result directly to the
|
- useoutput: (bool=false) encodes the result directly to the
|
||||||
output buffer and returns `nil` value. This option is
|
output buffer and returns `nil` value. This option is
|
||||||
ignored if used outside of request handling code.
|
ignored if used outside of request handling code.
|
||||||
|
|
||||||
|
This function will fail if:
|
||||||
|
|
||||||
|
- `value` has depth greater than 64
|
||||||
|
|
||||||
|
If a user data object has a `__repr` or `__tostring` meta
|
||||||
|
method, then that'll be used to encode the Lua code.
|
||||||
|
|
||||||
|
Non-encodable value types (e.g. threads, functions) will be
|
||||||
|
represented as a string literal with the type name and pointer
|
||||||
|
address. Note this is subject to change in the future.
|
||||||
|
|
||||||
|
This encoder detects cyclic tables, and encodes a string
|
||||||
|
literal saying it's cyclic when cycles are encountered.
|
||||||
|
|
||||||
|
When tables are serialized, entries will be sorted in a
|
||||||
|
deterministic order.
|
||||||
|
|
||||||
EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str
|
EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str
|
||||||
Turns UTF-8 into ISO-8859-1 string.
|
Turns UTF-8 into ISO-8859-1 string.
|
||||||
|
|
||||||
|
|
|
@ -4231,9 +4231,14 @@ static int LuaEncodeSmth(lua_State *L,
|
||||||
numformat = luaL_optstring(L, -1, numformat);
|
numformat = luaL_optstring(L, -1, numformat);
|
||||||
}
|
}
|
||||||
lua_settop(L, 1); // keep the passed argument on top
|
lua_settop(L, 1); // keep the passed argument on top
|
||||||
Encoder(L, useoutput ? &outbuf : &p, numformat, -1);
|
if (Encoder(L, useoutput ? &outbuf : &p, numformat, -1) == -1) {
|
||||||
if (useoutput) {
|
free(p);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "serialization failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (useoutput) {
|
||||||
|
lua_pushboolean(L, true);
|
||||||
} else {
|
} else {
|
||||||
lua_pushstring(L, p);
|
lua_pushstring(L, p);
|
||||||
free(p);
|
free(p);
|
||||||
|
@ -5394,12 +5399,45 @@ static int LuaInterpreter(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LuaDestroy(void) {
|
||||||
|
#ifndef STATIC
|
||||||
|
lua_State *L = GL;
|
||||||
|
lua_close(L);
|
||||||
|
free(g_lua_path_default);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MemDestroy(void) {
|
||||||
|
FreeAssets();
|
||||||
|
CollectGarbage();
|
||||||
|
inbuf.p = 0, inbuf.n = 0, inbuf.c = 0;
|
||||||
|
Free(&inbuf_actual.p), inbuf_actual.n = inbuf_actual.c = 0;
|
||||||
|
Free(&unmaplist.p), unmaplist.n = unmaplist.c = 0;
|
||||||
|
Free(&freelist.p), freelist.n = freelist.c = 0;
|
||||||
|
Free(&hdrbuf.p), hdrbuf.n = hdrbuf.c = 0;
|
||||||
|
Free(&servers.p), servers.n = 0;
|
||||||
|
Free(&ports.p), ports.n = 0;
|
||||||
|
Free(&ips.p), ips.n = 0;
|
||||||
|
Free(&outbuf);
|
||||||
|
FreeStrings(&stagedirs);
|
||||||
|
FreeStrings(&hidepaths);
|
||||||
|
Free(&launchbrowser);
|
||||||
|
Free(&serverheader);
|
||||||
|
Free(&extrahdrs);
|
||||||
|
Free(&pidpath);
|
||||||
|
Free(&logpath);
|
||||||
|
Free(&brand);
|
||||||
|
Free(&polls);
|
||||||
|
}
|
||||||
|
|
||||||
static void LuaInit(void) {
|
static void LuaInit(void) {
|
||||||
#ifndef STATIC
|
#ifndef STATIC
|
||||||
lua_State *L = GL;
|
lua_State *L = GL;
|
||||||
LuaSetArgv(L);
|
LuaSetArgv(L);
|
||||||
if (interpretermode) {
|
if (interpretermode) {
|
||||||
int rc = LuaInterpreter(L);
|
int rc = LuaInterpreter(L);
|
||||||
|
LuaDestroy();
|
||||||
|
MemDestroy();
|
||||||
if (IsModeDbg()) {
|
if (IsModeDbg()) {
|
||||||
CheckForMemoryLeaks();
|
CheckForMemoryLeaks();
|
||||||
}
|
}
|
||||||
|
@ -5426,14 +5464,6 @@ static void LuaReload(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LuaDestroy(void) {
|
|
||||||
#ifndef STATIC
|
|
||||||
lua_State *L = GL;
|
|
||||||
lua_close(L);
|
|
||||||
free(g_lua_path_default);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *DescribeClose(void) {
|
static const char *DescribeClose(void) {
|
||||||
if (killed) return "killed";
|
if (killed) return "killed";
|
||||||
if (meltdown) return "meltdown";
|
if (meltdown) return "meltdown";
|
||||||
|
@ -7183,29 +7213,6 @@ static void TlsDestroy(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MemDestroy(void) {
|
|
||||||
FreeAssets();
|
|
||||||
CollectGarbage();
|
|
||||||
inbuf.p = 0, inbuf.n = 0, inbuf.c = 0;
|
|
||||||
Free(&inbuf_actual.p), inbuf_actual.n = inbuf_actual.c = 0;
|
|
||||||
Free(&unmaplist.p), unmaplist.n = unmaplist.c = 0;
|
|
||||||
Free(&freelist.p), freelist.n = freelist.c = 0;
|
|
||||||
Free(&hdrbuf.p), hdrbuf.n = hdrbuf.c = 0;
|
|
||||||
Free(&servers.p), servers.n = 0;
|
|
||||||
Free(&ports.p), ports.n = 0;
|
|
||||||
Free(&ips.p), ips.n = 0;
|
|
||||||
Free(&outbuf);
|
|
||||||
FreeStrings(&stagedirs);
|
|
||||||
FreeStrings(&hidepaths);
|
|
||||||
Free(&launchbrowser);
|
|
||||||
Free(&serverheader);
|
|
||||||
Free(&extrahdrs);
|
|
||||||
Free(&pidpath);
|
|
||||||
Free(&logpath);
|
|
||||||
Free(&brand);
|
|
||||||
Free(&polls);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetOpts(int argc, char *argv[]) {
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
int opt;
|
int opt;
|
||||||
bool storeasset = false;
|
bool storeasset = false;
|
||||||
|
|
Loading…
Reference in a new issue