mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Polish redbean serialization
This commit is contained in:
parent
7aafa64ab3
commit
2d1731b995
24 changed files with 828 additions and 158 deletions
63
libc/fmt/formatbinary64.c
Normal file
63
libc/fmt/formatbinary64.c
Normal 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
63
libc/fmt/formatflex64.c
Normal 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
64
libc/fmt/formathex64.c
Normal 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;
|
||||||
|
}
|
|
@ -21,7 +21,7 @@
|
||||||
/**
|
/**
|
||||||
* Converts unsigned 64-bit integer to octal string.
|
* 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
|
* @param z ensures it starts with zero
|
||||||
* @return pointer to nul byte
|
* @return pointer to nul byte
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,6 +15,9 @@ char *FormatInt64Thousands(char[hasatleast 27], int64_t);
|
||||||
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
|
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
|
||||||
char *FormatOctal32(char[hasatleast 13], uint32_t, bool);
|
char *FormatOctal32(char[hasatleast 13], uint32_t, bool);
|
||||||
char *FormatOctal64(char[hasatleast 24], uint64_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_radix16(uint64_t, char[hasatleast 17]);
|
||||||
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
||||||
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);
|
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);
|
||||||
|
|
98
test/libc/fmt/formatbinary64_test.c
Normal file
98
test/libc/fmt/formatbinary64_test.c
Normal 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));
|
||||||
|
}
|
34
test/libc/fmt/formatflex64_test.c
Normal file
34
test/libc/fmt/formatflex64_test.c
Normal 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);
|
||||||
|
}
|
87
test/libc/fmt/formathex64_test.c
Normal file
87
test/libc/fmt/formathex64_test.c
Normal 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));
|
||||||
|
}
|
|
@ -21,7 +21,7 @@
|
||||||
#include "libc/testlib/ezbench.h"
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
char buf[25];
|
char buf[24];
|
||||||
|
|
||||||
void SetUp(void) {
|
void SetUp(void) {
|
||||||
memset(buf, 0x55, sizeof(buf));
|
memset(buf, 0x55, sizeof(buf));
|
||||||
|
|
2
third_party/lua/README.cosmo
vendored
2
third_party/lua/README.cosmo
vendored
|
@ -24,6 +24,8 @@ LOCAL MODIFICATIONS
|
||||||
|
|
||||||
Integer literals such as `033` will now be interpreted as octal.
|
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
|
The `\e` string literal escape sequence has been added, which is
|
||||||
equivalent to `\27` (the Lua version of `\033`) or the ASCII ESC
|
equivalent to `\27` (the Lua version of `\033`) or the ASCII ESC
|
||||||
character. It may be used for teletypewriter control like having
|
character. It may be used for teletypewriter control like having
|
||||||
|
|
2
third_party/lua/cosmo.h
vendored
2
third_party/lua/cosmo.h
vendored
|
@ -15,9 +15,9 @@ 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 **);
|
void EscapeLuaString(char *, size_t, char **);
|
||||||
|
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 *);
|
||||||
void LuaPrintStack(lua_State *);
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
101
third_party/lua/lapi.c
vendored
101
third_party/lua/lapi.c
vendored
|
@ -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) {
|
LUA_API void *lua_touserdata (lua_State *L, int idx) {
|
||||||
const TValue *o = index2value(L, idx);
|
const TValue *o = index2value(L, idx);
|
||||||
return touserdata(o);
|
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) {
|
LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
|
||||||
const TValue *o = index2value(L, idx);
|
const TValue *o = index2value(L, idx);
|
||||||
return (!ttisthread(o)) ? NULL : thvalue(o);
|
return (!ttisthread(o)) ? NULL : thvalue(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
** Returns a pointer to the internal representation of an object.
|
* lua_topointer [-0, +0, –]
|
||||||
** Note that ANSI C does not allow the conversion of a pointer to
|
*
|
||||||
** function to a 'void*', so the conversion here goes through
|
* Converts the value at the given index to a generic C pointer (void*). The
|
||||||
** a 'size_t'. (As the returned pointer is only informative, this
|
* value can be a userdata, a table, a thread, a string, or a function;
|
||||||
** conversion should not be a problem.)
|
* 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) {
|
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);
|
const TValue *o = index2value(L, idx);
|
||||||
switch (ttypetag(o)) {
|
switch (ttypetag(o)) {
|
||||||
case LUA_VLCF: return cast_voidp(cast_sizet(fvalue(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) {
|
LUA_API int lua_rawget (lua_State *L, int idx) {
|
||||||
Table *t;
|
Table *t;
|
||||||
const TValue *val;
|
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) {
|
LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
|
||||||
Table *t;
|
Table *t;
|
||||||
TValue k;
|
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) {
|
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
|
||||||
Table *t;
|
Table *t;
|
||||||
lua_lock(L);
|
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) {
|
LUA_API int lua_getmetatable (lua_State *L, int objindex) {
|
||||||
const TValue *obj;
|
const TValue *obj;
|
||||||
Table *mt;
|
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) {
|
LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
|
||||||
TValue *o;
|
TValue *o;
|
||||||
int t;
|
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) {
|
LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
||||||
TValue *obj;
|
TValue *obj;
|
||||||
Table *mt;
|
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) {
|
LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
|
||||||
TValue *o;
|
TValue *o;
|
||||||
int res;
|
int res;
|
||||||
|
|
6
third_party/lua/lctype.h
vendored
6
third_party/lua/lctype.h
vendored
|
@ -45,6 +45,12 @@
|
||||||
('a' <= c_ && c_ <= 'f')); \
|
('a' <= c_ && c_ <= 'f')); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define lisbdigit(C) \
|
||||||
|
({ \
|
||||||
|
unsigned char c_ = (C); \
|
||||||
|
'0' <= c_&& c_ <= '1'; \
|
||||||
|
})
|
||||||
|
|
||||||
#define lisprint(C) \
|
#define lisprint(C) \
|
||||||
({ \
|
({ \
|
||||||
unsigned char c_ = (C); \
|
unsigned char c_ = (C); \
|
||||||
|
|
9
third_party/lua/lobject.c
vendored
9
third_party/lua/lobject.c
vendored
|
@ -27,7 +27,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#define lobject_c
|
#define lobject_c
|
||||||
#define LUA_CORE
|
#define LUA_CORE
|
||||||
#include "libc/intrin/kprintf.h"
|
|
||||||
#include "third_party/lua/lctype.h"
|
#include "third_party/lua/lctype.h"
|
||||||
#include "third_party/lua/ldebug.h"
|
#include "third_party/lua/ldebug.h"
|
||||||
#include "third_party/lua/ldo.h"
|
#include "third_party/lua/ldo.h"
|
||||||
|
@ -285,6 +284,14 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
|
||||||
empty = 0;
|
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 */
|
else if (s[0] == '0') { /* [jart] octal is the best radix */
|
||||||
for (s += 1; lisdigit(cast_uchar(*s)); s++) {
|
for (s += 1; lisdigit(cast_uchar(*s)); s++) {
|
||||||
int d = *s - '0';
|
int d = *s - '0';
|
||||||
|
|
4
third_party/lua/lrepl.c
vendored
4
third_party/lua/lrepl.c
vendored
|
@ -30,13 +30,13 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/gc.h"
|
#include "libc/runtime/gc.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "third_party/linenoise/linenoise.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);
|
prompt = get_prompt(L, 1);
|
||||||
if ((g_historypath = linenoiseGetHistoryPath(progname))) {
|
if ((g_historypath = linenoiseGetHistoryPath(progname))) {
|
||||||
if (linenoiseHistoryLoad(g_historypath) == -1) {
|
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);
|
free(g_historypath);
|
||||||
g_historypath = 0;
|
g_historypath = 0;
|
||||||
}
|
}
|
||||||
|
|
63
third_party/lua/luaencodejsondata.c
vendored
63
third_party/lua/luaencodejsondata.c
vendored
|
@ -16,23 +16,37 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#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/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 "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"
|
||||||
#include "third_party/lua/lua.h"
|
#include "third_party/lua/lua.h"
|
||||||
|
#include "third_party/lua/visitor.h"
|
||||||
|
|
||||||
static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
char *numformat, int idx) {
|
char *numformat, int idx,
|
||||||
|
struct LuaVisited *visited) {
|
||||||
char *s;
|
char *s;
|
||||||
bool isarray;
|
bool isarray;
|
||||||
size_t tbllen, z;
|
size_t tbllen, i, z;
|
||||||
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:
|
||||||
|
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:
|
case LUA_TSTRING:
|
||||||
s = lua_tolstring(L, idx, &z);
|
s = lua_tolstring(L, idx, &z);
|
||||||
s = EscapeJsStringLiteral(s, z, &z);
|
s = EscapeJsStringLiteral(s, z, &z);
|
||||||
|
@ -41,21 +55,7 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
appendw(buf, '"');
|
appendw(buf, '"');
|
||||||
free(s);
|
free(s);
|
||||||
return 0;
|
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:
|
case LUA_TNUMBER:
|
||||||
if (lua_isinteger(L, idx)) {
|
if (lua_isinteger(L, idx)) {
|
||||||
appendd(buf, ibuf,
|
appendd(buf, ibuf,
|
||||||
|
@ -78,26 +78,25 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
appendf(buf, fmt, lua_tonumber(L, idx));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case LUA_TBOOLEAN:
|
|
||||||
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
|
|
||||||
return 0;
|
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
|
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
|
||||||
tbllen = lua_rawlen(L, idx);
|
tbllen = lua_rawlen(L, idx);
|
||||||
// encode tables with numeric indices and empty tables as arrays
|
// encode tables with numeric indices and empty tables as arrays
|
||||||
isarray =
|
isarray =
|
||||||
tbllen > 0 || // integer keys present
|
tbllen > 0 || // integer keys present
|
||||||
(lua_pushnil(L), lua_next(L, -2) == 0) || // 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 ? '[' : '{');
|
appendw(buf, isarray ? '[' : '{');
|
||||||
if (isarray) {
|
if (isarray) {
|
||||||
for (size_t i = 1; i <= tbllen; i++) {
|
for (i = 1; i <= tbllen; i++) {
|
||||||
if (i > 1) appendw(buf, ',');
|
if (i > 1) appendw(buf, ',');
|
||||||
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);
|
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1, visited);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int i = 1;
|
i = 1;
|
||||||
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_isstring(L, -2)) {
|
if (!lua_isstring(L, -2)) {
|
||||||
|
@ -121,15 +120,22 @@ static int LuaEncodeJsonDataImpl(lua_State *L, char **buf, int level,
|
||||||
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
||||||
}
|
}
|
||||||
appendw(buf, '"' | ':' << 010);
|
appendw(buf, '"' | ':' << 010);
|
||||||
LuaEncodeJsonDataImpl(L, buf, level - 1, numformat, -1);
|
LuaEncodeJsonDataImpl(L, buf, 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 ? ']' : '}');
|
appendw(buf, isarray ? ']' : '}');
|
||||||
|
LuaPopVisit(visited);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else {
|
||||||
|
// TODO(jart): don't leak memory with longjmp
|
||||||
|
luaL_error(L, "can't serialize cyclic data structure to json");
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
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;
|
unreachable;
|
||||||
}
|
}
|
||||||
} else {
|
} 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 LuaEncodeJsonData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||||
int rc;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
103
third_party/lua/luaencodeluadata.c
vendored
103
third_party/lua/luaencodeluadata.c
vendored
|
@ -25,39 +25,44 @@
|
||||||
#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"
|
||||||
|
#include "third_party/lua/lctype.h"
|
||||||
#include "third_party/lua/lua.h"
|
#include "third_party/lua/lua.h"
|
||||||
|
#include "third_party/lua/visitor.h"
|
||||||
|
|
||||||
struct Visited {
|
static bool IsLuaIdentifier(lua_State *L, int idx) {
|
||||||
int n;
|
size_t i, n;
|
||||||
void **p;
|
const char *p;
|
||||||
};
|
p = luaL_checklstring(L, idx, &n);
|
||||||
|
if (!lislalpha(p[0])) return false;
|
||||||
static bool PushVisit(struct Visited *visited, void *p) {
|
for (i = 1; i < n; ++i) {
|
||||||
int i;
|
if (!lislalnum(p[i])) return false;
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PopVisit(struct Visited *visited) {
|
// TODO: Can we be smarter with lua_rawlen?
|
||||||
assert(visited->n > 0);
|
static bool IsLuaArray(lua_State *L) {
|
||||||
--visited->n;
|
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,
|
static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
char *numformat, int idx,
|
char *numformat, int idx,
|
||||||
struct Visited *visited) {
|
struct LuaVisited *visited) {
|
||||||
char *s;
|
char *s;
|
||||||
bool didcomma;
|
bool isarray;
|
||||||
lua_Integer i;
|
lua_Integer i;
|
||||||
int ktype, vtype;
|
int ktype, vtype;
|
||||||
size_t tbllen, buflen, slen;
|
size_t tbllen, buflen, slen;
|
||||||
char ibuf[21], fmt[] = "%.14g";
|
char ibuf[24], fmt[] = "%.14g";
|
||||||
if (level > 0) {
|
if (level > 0) {
|
||||||
switch (lua_type(L, idx)) {
|
switch (lua_type(L, idx)) {
|
||||||
|
|
||||||
|
@ -71,15 +76,15 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TFUNCTION:
|
case LUA_TFUNCTION:
|
||||||
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
|
appendf(buf, "\"func@%p\"", lua_topointer(L, idx));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TLIGHTUSERDATA:
|
case LUA_TLIGHTUSERDATA:
|
||||||
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
|
appendf(buf, "\"light@%p\"", lua_topointer(L, idx));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TTHREAD:
|
case LUA_TTHREAD:
|
||||||
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
|
appendf(buf, "\"thread@%p\"", lua_topointer(L, idx));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TUSERDATA:
|
case LUA_TUSERDATA:
|
||||||
|
@ -111,7 +116,7 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
if (lua_isinteger(L, idx)) {
|
if (lua_isinteger(L, idx)) {
|
||||||
appendd(buf, ibuf,
|
appendd(buf, ibuf,
|
||||||
FormatInt64(ibuf, luaL_checkinteger(L, idx)) - 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 == '.' ||
|
||||||
|
@ -133,58 +138,52 @@ static int LuaEncodeLuaDataImpl(lua_State *L, char **buf, int level,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TBOOLEAN:
|
case LUA_TBOOLEAN:
|
||||||
if (lua_toboolean(L, idx)) {
|
appendw(buf, lua_toboolean(L, idx) ? READ32LE("true")
|
||||||
appendw(buf, READ32LE("true"));
|
: READ64LE("false\0\0"));
|
||||||
} else {
|
|
||||||
appendw(buf, READ64LE("false\0\0"));
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
i = 0;
|
i = 0;
|
||||||
didcomma = false;
|
if (LuaPushVisit(visited, lua_topointer(L, idx))) {
|
||||||
appendw(buf, '{');
|
appendw(buf, '{');
|
||||||
lua_pushvalue(L, idx);
|
lua_pushvalue(L, idx); // idx becomes invalid once we change stack
|
||||||
|
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)) {
|
||||||
++i;
|
|
||||||
ktype = lua_type(L, -2);
|
ktype = lua_type(L, -2);
|
||||||
vtype = lua_type(L, -1);
|
vtype = lua_type(L, -1);
|
||||||
if (ktype != LUA_TNUMBER || lua_tointeger(L, -2) != i) {
|
if (i++ > 0) appendw(buf, ',' | ' ' << 8);
|
||||||
if (PushVisit(visited, lua_touserdata(L, -2))) {
|
if (isarray) {
|
||||||
if (i > 1) appendw(buf, ',' | ' ' << 8);
|
// use {v₁′,v₂′,...} for lua-normal integer keys
|
||||||
didcomma = true;
|
} 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, '[');
|
appendw(buf, '[');
|
||||||
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -2, visited);
|
LuaEncodeLuaDataImpl(L, buf, level - 1, numformat, -2, visited);
|
||||||
appendw(buf, ']' | '=' << 010);
|
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);
|
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
|
lua_pop(L, 1); // table ref
|
||||||
// stack: table/-1, as the key was popped by lua_next
|
LuaPopVisit(visited);
|
||||||
appendw(buf, '}');
|
appendw(buf, '}');
|
||||||
|
} else {
|
||||||
|
appendf(buf, "\"cyclic@%p\"", lua_topointer(L, idx));
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
// TODO(jart): don't leak memory with longjmp
|
||||||
luaL_error(L, "can't serialize value of this type");
|
luaL_error(L, "can't serialize value of this type");
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// TODO(jart): don't leak memory with longjmp
|
||||||
luaL_error(L, "too many nested tables");
|
luaL_error(L, "too many nested tables");
|
||||||
unreachable;
|
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 LuaEncodeLuaData(lua_State *L, char **buf, char *numformat, int idx) {
|
||||||
int rc;
|
int rc;
|
||||||
struct Visited 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);
|
assert(!visited.n);
|
||||||
free(visited.p);
|
free(visited.p);
|
||||||
|
|
38
third_party/lua/visitor.c
vendored
Normal file
38
third_party/lua/visitor.c
vendored
Normal 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
16
third_party/lua/visitor.h
vendored
Normal 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_ */
|
|
@ -464,6 +464,7 @@ int main(int argc, char *argv[]) {
|
||||||
/* __log_level = kLogDebug; */
|
/* __log_level = kLogDebug; */
|
||||||
GetOpts(argc, argv);
|
GetOpts(argc, argv);
|
||||||
for (i = 3; i < 16; ++i) close(i);
|
for (i = 3; i < 16; ++i) close(i);
|
||||||
|
errno = 0;
|
||||||
// poll()'ing /dev/null stdin file descriptor on xnu returns POLLNVAL?!
|
// poll()'ing /dev/null stdin file descriptor on xnu returns POLLNVAL?!
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
CHECK_EQ(3, (g_bogusfd = open("/dev/null", O_RDONLY | O_CLOEXEC)));
|
CHECK_EQ(3, (g_bogusfd = open("/dev/null", O_RDONLY | O_CLOEXEC)));
|
||||||
|
|
|
@ -357,6 +357,10 @@ LUA ENHANCEMENTS
|
||||||
`0644 == 420` is the case in redbean, whereas in upstream Lua
|
`0644 == 420` is the case in redbean, whereas in upstream Lua
|
||||||
`0644 == 644` would be the case.
|
`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
|
- redbean supports the GNU syntax for the ASCII ESC character in
|
||||||
string literals. For example, `"\e"` is the same as `"\x1b"`.
|
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
|
possibly because your system is under load and the benchmark was
|
||||||
preempted by the operating system, or moved to a different core.
|
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
|
||||||
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()
|
unix.getpid()
|
||||||
└─→ pid:int
|
└─→ pid:int
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/bits/popcnt.h"
|
#include "libc/bits/popcnt.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
@ -60,6 +61,33 @@ static int Rdpid(void) {
|
||||||
return rdpid();
|
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) {
|
int LuaGetTime(lua_State *L) {
|
||||||
lua_pushnumber(L, nowl());
|
lua_pushnumber(L, nowl());
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -258,7 +286,7 @@ int LuaPopcnt(lua_State *L) {
|
||||||
int LuaBsr(lua_State *L) {
|
int LuaBsr(lua_State *L) {
|
||||||
long x;
|
long x;
|
||||||
if ((x = luaL_checkinteger(L, 1))) {
|
if ((x = luaL_checkinteger(L, 1))) {
|
||||||
lua_pushinteger(L, bsr(x));
|
lua_pushinteger(L, bsrl(x));
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
luaL_argerror(L, 1, "zero");
|
luaL_argerror(L, 1, "zero");
|
||||||
|
@ -269,7 +297,7 @@ int LuaBsr(lua_State *L) {
|
||||||
int LuaBsf(lua_State *L) {
|
int LuaBsf(lua_State *L) {
|
||||||
long x;
|
long x;
|
||||||
if ((x = luaL_checkinteger(L, 1))) {
|
if ((x = luaL_checkinteger(L, 1))) {
|
||||||
lua_pushinteger(L, bsf(x));
|
lua_pushinteger(L, bsfl(x));
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
luaL_argerror(L, 1, "zero");
|
luaL_argerror(L, 1, "zero");
|
||||||
|
|
|
@ -12,6 +12,7 @@ int luaopen_argon2(lua_State *);
|
||||||
int luaopen_lsqlite3(lua_State *);
|
int luaopen_lsqlite3(lua_State *);
|
||||||
|
|
||||||
int LuaBenchmark(lua_State *);
|
int LuaBenchmark(lua_State *);
|
||||||
|
int LuaBin(lua_State *);
|
||||||
int LuaBsf(lua_State *);
|
int LuaBsf(lua_State *);
|
||||||
int LuaBsr(lua_State *);
|
int LuaBsr(lua_State *);
|
||||||
int LuaCategorizeIp(lua_State *);
|
int LuaCategorizeIp(lua_State *);
|
||||||
|
@ -45,6 +46,7 @@ int LuaGetMonospaceWidth(lua_State *);
|
||||||
int LuaGetRandomBytes(lua_State *);
|
int LuaGetRandomBytes(lua_State *);
|
||||||
int LuaGetTime(lua_State *);
|
int LuaGetTime(lua_State *);
|
||||||
int LuaHasControlCodes(lua_State *);
|
int LuaHasControlCodes(lua_State *);
|
||||||
|
int LuaHex(lua_State *);
|
||||||
int LuaIndentLines(lua_State *);
|
int LuaIndentLines(lua_State *);
|
||||||
int LuaIsAcceptableHost(lua_State *);
|
int LuaIsAcceptableHost(lua_State *);
|
||||||
int LuaIsAcceptablePath(lua_State *);
|
int LuaIsAcceptablePath(lua_State *);
|
||||||
|
@ -58,6 +60,7 @@ int LuaIsValidHttpToken(lua_State *);
|
||||||
int LuaLemur64(lua_State *);
|
int LuaLemur64(lua_State *);
|
||||||
int LuaMd5(lua_State *);
|
int LuaMd5(lua_State *);
|
||||||
int LuaMeasureEntropy(lua_State *);
|
int LuaMeasureEntropy(lua_State *);
|
||||||
|
int LuaOct(lua_State *);
|
||||||
int LuaParseHost(lua_State *);
|
int LuaParseHost(lua_State *);
|
||||||
int LuaParseHttpDateTime(lua_State *);
|
int LuaParseHttpDateTime(lua_State *);
|
||||||
int LuaParseIp(lua_State *);
|
int LuaParseIp(lua_State *);
|
||||||
|
|
|
@ -192,6 +192,22 @@ STATIC_YOINK("zip_uri_support");
|
||||||
#define HeaderEqualCase(H, S) \
|
#define HeaderEqualCase(H, S) \
|
||||||
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
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
|
// letters not used: EIJNOQWXYnoqwxy
|
||||||
// digits not used: 0123456789
|
// digits not used: 0123456789
|
||||||
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
|
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
|
||||||
|
@ -5066,6 +5082,9 @@ static const luaL_Reg kLuaFuncs[] = {
|
||||||
{"Underlong", LuaUnderlong}, //
|
{"Underlong", LuaUnderlong}, //
|
||||||
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
|
{"VisualizeControlCodes", LuaVisualizeControlCodes}, //
|
||||||
{"Write", LuaWrite}, //
|
{"Write", LuaWrite}, //
|
||||||
|
{"bin", LuaBin}, //
|
||||||
|
{"hex", LuaHex}, //
|
||||||
|
{"oct", LuaOct}, //
|
||||||
#ifndef UNSECURE
|
#ifndef UNSECURE
|
||||||
{"Fetch", LuaFetch}, //
|
{"Fetch", LuaFetch}, //
|
||||||
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
|
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
|
||||||
|
@ -5196,7 +5215,6 @@ static void LuaPrint(lua_State *L) {
|
||||||
static void LuaInterpreter(lua_State *L) {
|
static void LuaInterpreter(lua_State *L) {
|
||||||
int i, n, sig, status;
|
int i, n, sig, status;
|
||||||
const char *script;
|
const char *script;
|
||||||
if (funtrace) ftrace_install();
|
|
||||||
if (optind < __argc) {
|
if (optind < __argc) {
|
||||||
script = __argv[optind];
|
script = __argv[optind];
|
||||||
if (!strcmp(script, "-")) script = 0;
|
if (!strcmp(script, "-")) script = 0;
|
||||||
|
@ -5206,11 +5224,9 @@ static void LuaInterpreter(lua_State *L) {
|
||||||
luaL_checkstack(L, n + 3, "too many script args");
|
luaL_checkstack(L, n + 3, "too many script args");
|
||||||
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
|
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
|
||||||
lua_remove(L, -i); // remove arg table from stack
|
lua_remove(L, -i); // remove arg table from stack
|
||||||
if (funtrace) ++g_ftrace;
|
TRACE_BEGIN;
|
||||||
if (systrace) ++__strace;
|
|
||||||
status = lua_runchunk(L, n, LUA_MULTRET);
|
status = lua_runchunk(L, n, LUA_MULTRET);
|
||||||
if (systrace) --__strace;
|
TRACE_END;
|
||||||
if (funtrace) --g_ftrace;
|
|
||||||
}
|
}
|
||||||
lua_report(L, status);
|
lua_report(L, status);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5233,9 +5249,9 @@ static void LuaInterpreter(lua_State *L) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
if (funtrace) ++g_ftrace;
|
TRACE_BEGIN;
|
||||||
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
||||||
if (funtrace) --g_ftrace;
|
TRACE_END;
|
||||||
}
|
}
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
LuaPrint(GL);
|
LuaPrint(GL);
|
||||||
|
@ -6365,19 +6381,10 @@ static int HandleConnection(size_t i) {
|
||||||
meltdown = false;
|
meltdown = false;
|
||||||
__isworker = true;
|
__isworker = true;
|
||||||
connectionclose = false;
|
connectionclose = false;
|
||||||
if (!IsTiny()) {
|
if (!IsTiny() && systrace) {
|
||||||
if (systrace) {
|
|
||||||
__strace = 1;
|
|
||||||
__kbirth = rdtsc();
|
__kbirth = rdtsc();
|
||||||
}
|
}
|
||||||
if (funtrace) {
|
TRACE_BEGIN;
|
||||||
if (ftrace_install() != -1) {
|
|
||||||
g_ftrace = 1;
|
|
||||||
} else {
|
|
||||||
WARNF("ftrace failed to install %m");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sandboxed) {
|
if (sandboxed) {
|
||||||
CHECK_NE(-1, EnableSandbox());
|
CHECK_NE(-1, EnableSandbox());
|
||||||
}
|
}
|
||||||
|
@ -6850,7 +6857,6 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
CASE('S', ++sandboxed);
|
CASE('S', ++sandboxed);
|
||||||
CASE('v', ++__log_level);
|
CASE('v', ++__log_level);
|
||||||
CASE('s', --__log_level);
|
CASE('s', --__log_level);
|
||||||
CASE('f', funtrace = true);
|
|
||||||
CASE('Z', systrace = true);
|
CASE('Z', systrace = true);
|
||||||
CASE('b', logbodies = true);
|
CASE('b', logbodies = true);
|
||||||
CASE('z', printport = true);
|
CASE('z', printport = true);
|
||||||
|
@ -6889,6 +6895,12 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
CASE('C', ProgramFile(optarg, ProgramCertificate));
|
CASE('C', ProgramFile(optarg, ProgramCertificate));
|
||||||
CASE('K', ProgramFile(optarg, ProgramPrivateKey));
|
CASE('K', ProgramFile(optarg, ProgramPrivateKey));
|
||||||
#endif
|
#endif
|
||||||
|
case 'f':
|
||||||
|
funtrace = true;
|
||||||
|
if (ftrace_install() == -1) {
|
||||||
|
WARNF("ftrace failed to install %m");
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PrintUsage(2, EX_USAGE);
|
PrintUsage(2, EX_USAGE);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue