Improve redbean plus code size optimizations

This change turns symbol table compression back on using Puff, which
noticeably reduces the size of programs like redbean and Python. The
redbean web server receives some minor API additions for controlling
things like SSL in addition to filling gaps in the documentation.
This commit is contained in:
Justine Tunney 2022-05-29 08:14:55 -07:00
parent 425ff5dff0
commit 13ee75150c
58 changed files with 2077 additions and 589 deletions

View file

@ -99,7 +99,7 @@ o/$(MODE)/tool/build/blinkenlights.com: \
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/build/.blinkenlights/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/build/.blinkenlights/.symtab
o/$(MODE)/tool/build/ar.com.dbg: \

323
tool/build/xlat.c Normal file
View file

@ -0,0 +1,323 @@
/*-*- 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/calls/calls.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
/**
* @fileoverview Tool for generating rldecode'd character sets, e.g.
*
* # generate http token table
* o//tool/build/xlat.com -TiC ' ()<>@,;:\"/[]?={}' -i
*/
int dig;
int xlat[256];
const char *symbol;
static int Bing(int c) {
if (!c) return L'';
if (c == ' ') return L'';
if (c == '$') return L'§';
if (c == '\\') return L'';
return kCp437[c & 255];
}
static void Fill(int f(int)) {
int i;
for (i = 0; i < 256; ++i) {
if (f(i)) {
xlat[i] = 1;
}
}
}
static void Invert(void) {
int i;
for (i = 0; i < 256; ++i) {
xlat[i] = !xlat[i];
}
}
static void Negate(void) {
int i;
for (i = 0; i < 256; ++i) {
xlat[i] = ~xlat[i] & 255;
}
}
static void Negative(void) {
int i;
for (i = 0; i < 256; ++i) {
xlat[i] = -xlat[i] & 255;
}
}
static bool ArgNeedsShellQuotes(const char *s) {
if (*s) {
for (;;) {
switch (*s++ & 255) {
case 0:
return false;
case '-':
case '.':
case '/':
case '_':
case '=':
case ':':
case '0' ... '9':
case 'A' ... 'Z':
case 'a' ... 'z':
break;
default:
return true;
}
}
} else {
return true;
}
}
static char *AddShellQuotes(const char *s) {
char *p, *q;
size_t i, j, n;
n = strlen(s);
p = malloc(1 + n * 5 + 1 + 1);
j = 0;
p[j++] = '\'';
for (i = 0; i < n; ++i) {
if (s[i] != '\'') {
p[j++] = s[i];
} else {
p[j + 0] = '\'';
p[j + 1] = '"';
p[j + 2] = '\'';
p[j + 3] = '"';
p[j + 4] = '\'';
j += 5;
}
}
p[j++] = '\'';
p[j] = 0;
if ((q = realloc(p, j + 1))) p = q;
return p;
}
static const char *GetArg(char *argv[], int i, int *k) {
if (argv[*k][i + 1]) {
return argv[*k] + i + 1;
} else {
return argv[++*k];
}
}
int main(int argc, char *argv[]) {
const char *arg;
int i, j, k, opt;
dig = 1;
symbol = "kXlatTab";
for (k = 1; k < argc; ++k) {
if (argv[k][0] != '-') {
for (i = 0; argv[k][i]; ++i) {
xlat[argv[k][i] & 255] = dig;
}
} else {
i = 0;
moar:
++i;
if ((opt = argv[k][i])) {
switch (opt) {
case 's':
symbol = GetArg(argv, i, &k);
break;
case 'x':
dig = atoi(GetArg(argv, i, &k)) & 255;
break;
case 'i':
Invert();
goto moar;
case 'n':
Negative();
goto moar;
case 'N':
Negate();
goto moar;
case 'T':
Fill(isascii);
goto moar;
case 'C':
Fill(iscntrl);
goto moar;
case 'A':
Fill(isalpha);
goto moar;
case 'B':
Fill(isblank);
goto moar;
case 'G':
Fill(isgraph);
goto moar;
case 'P':
Fill(ispunct);
goto moar;
case 'D':
Fill(isdigit);
goto moar;
case 'U':
Fill(isupper);
goto moar;
case 'L':
Fill(islower);
goto moar;
default:
fprintf(stderr, "error: unrecognized option: %c\n", opt);
return 1;
}
}
}
}
////////////////////////////////////////////////////////////
printf("#include \"libc/macros.internal.h\"\n");
printf("\n");
printf("//\tgenerated by:\n");
printf("//\t");
for (i = 0; i < argc; ++i) {
if (i) printf(" ");
printf("%s", !ArgNeedsShellQuotes(argv[i]) ? argv[i]
: gc(AddShellQuotes(argv[i])));
}
printf("\n");
////////////////////////////////////////////////////////////
printf("//\n");
printf("//\t present absent\n");
printf("//\t ──────────────── ────────────────\n");
for (i = 0; i < 16; ++i) {
char16_t absent[16];
char16_t present[16];
for (j = 0; j < 16; ++j) {
if (xlat[i * 16 + j]) {
absent[j] = L' ';
present[j] = Bing(i * 16 + j);
} else {
absent[j] = Bing(i * 16 + j);
present[j] = L' ';
}
}
printf("//\t %.16hs %.16hs 0x%02x\n", present, absent, i * 16);
}
////////////////////////////////////////////////////////////
printf("//\n");
printf("//\tconst char %s[256] = {\n//\t", symbol);
for (i = 0; i < 16; ++i) {
printf(" ");
for (j = 0; j < 16; ++j) {
printf("%2d,", xlat[i * 16 + j]);
}
printf(" // 0x%02x\n//\t", i * 16);
}
printf("};\n");
printf("\n");
////////////////////////////////////////////////////////////
printf("\t.initbss 300,_init_%s\n", symbol);
printf("%s:\n", symbol);
printf("\t.zero\t256\n");
printf("\t.endobj\t%s,globl\n", symbol);
printf("\t.previous\n");
printf("\n");
////////////////////////////////////////////////////////////
printf("\t.initro 300,_init_%s\n", symbol);
printf("%s.rom:\n", symbol);
int thebloat = 0;
int thetally = 0;
int thecount = 0;
int runstart = 0;
int runchar = -1;
int runcount = 0;
for (i = 0;; ++i) {
if (i < 256 && xlat[i] == runchar) {
++runcount;
} else {
if (runcount) {
printf("\t.byte\t%-24s# %02x-%02x %hc-%hc\n",
gc(xasprintf("%3d,%d", runcount, runchar)), runstart,
runstart + runcount - 1, Bing(runstart),
Bing(runstart + runcount - 1));
thetally += 2;
thecount += runcount;
}
if (i < 256) {
runcount = 1;
runchar = xlat[i];
runstart = i;
}
}
if (i == 256) {
break;
}
}
CHECK_EQ(256, thecount);
printf("\t.byte\t%-24s# terminator\n", "0,0");
thetally += 2;
thebloat = thetally;
for (i = 0; (thetally + i) % 8; i += 2) {
printf("\t.byte\t%-24s# padding\n", "0,0");
thebloat += 2;
}
printf("\t.endobj\t%s.rom,globl\n", symbol);
printf("\n");
////////////////////////////////////////////////////////////
printf("\t.init.start 300,_init_%s\n", symbol);
printf("\tcall\trldecode\n");
thebloat += 5;
int padding = 8 - thetally % 8;
if (padding < 8) {
if (padding >= 4) {
thebloat += 1;
printf("\tlodsl\n");
padding -= 4;
}
if (padding >= 2) {
thebloat += 2;
printf("\tlodsw\n");
}
}
printf("\t.init.end 300,_init_%s\n", symbol);
////////////////////////////////////////////////////////////
printf("\n");
printf("//\t%d bytes total (%d%% original size)\n", thebloat,
(int)round((double)thebloat / 256 * 100));
}

View file

@ -134,6 +134,7 @@
"__builtin_complex"
"__builtin_is_constant_evaluated"
"__builtin_expect"
"__builtin_expect_with_probability"
"__builtin_trap"
"__builtin_unreachable"
"__builtin_assume"

View file

@ -55,6 +55,8 @@ FLAGS
-f log worker function calls
-B only use stronger cryptography
-X disable ssl server and client support
-J disable non-ssl server and client support
-% hasten startup by not generating an rsa key
-s increase silence [repeatable]
-v increase verbosity [repeatable]
-V increase ssl verbosity [repeatable]
@ -1096,27 +1098,51 @@ FUNCTIONS
Defaults to 86400 (24 hours). This may be set to ≤0 to disable
SSL tickets. It's a good idea to use these since it increases
handshake performance 10x and eliminates a network round trip.
This function is not available in unsecure mode.
EvadeDragnetSurveillance(bool)
If this option is programmed then redbean will not transmit a
Server Name Indicator (SNI) when performing Fetch() requests.
This function is not available in unsecure mode.
ProgramSslPresharedKey(key:str,identity:str)
This function can be used to enable the PSK ciphersuites
which simplify SSL and enhance its performance in controlled
This function can be used to enable the PSK ciphersuites which
simplify SSL and enhance its performance in controlled
environments. `key` may contain 1..32 bytes of random binary
data and identity is usually a short plaintext string. The
first time this function is called, the preshared key will
be added to both the client and the server SSL configs. If
it's called multiple times, then the remaining keys will be
added to the server, which is useful if you want to assign
separate keys to each client, each of which needs a separate
identity too. If this function is called multiple times with
the same identity string, then the latter call will overwrite
the prior. If a preshared key is supplied and no certificates
or key-signing-keys are programmed, then redbean won't bother
first time this function is called, the preshared key will be
added to both the client and the server SSL configs. If it's
called multiple times, then the remaining keys will be added
to the server, which is useful if you want to assign separate
keys to each client, each of which needs a separate identity
too. If this function is called multiple times with the same
identity string, then the latter call will overwrite the
prior. If a preshared key is supplied and no certificates or
key-signing-keys are programmed, then redbean won't bother
auto-generating any serving certificates and will instead use
only PSK ciphersuites.
only PSK ciphersuites. This function is not available in
unsecure mode.
ProgramSslFetchVerify(enabled:str)
May be used to disable the the verification of certificates
for remote hosts when using the Fetch() API. This function is
not available in unsecure mode.
ProgramSslClientVerify(enabled:str)
Enables the verification of certificates supplied by the HTTP
clients that connect to your redbean. This has the same effect
as the `-j` flag. Tuning this option alone does not preclude
the possibility of unsecured HTTP clients, which can be
disabled using ProgramSslRequired(). This function can only be
called from `.init.lua`. This function is not available in
unsecure mode.
ProgramSslRequired(mandatory:str)
Enables the blocking of HTTP so that all inbound clients and
must use the TLS transport layer. This has the same effect as
the `-J` flag. Fetch() is still allowed to make outbound HTTP
requests. This function can only be called from `.init.lua`.
This function is not available in unsecure mode.
ProgramSslCiphersuite(name:str)
See https://redbean.dev/ for further details.

View file

@ -158,7 +158,7 @@ int LuaDecimate(lua_State *L) {
unsigned char *p;
s = luaL_checklstring(L, 1, &n);
m = ROUNDUP(n, 16);
CHECK_NOTNULL((p = LuaAlloc(L, m)));
p = LuaAllocOrDie(L, m);
bzero(p + n, m - n);
cDecimate2xUint8x8(m, p, (signed char[8]){-1, -3, 3, 17, 17, 3, -3, -1});
lua_pushlstring(L, (char *)p, (n + 1) >> 1);
@ -408,7 +408,7 @@ int LuaGetRandomBytes(lua_State *L) {
luaL_argerror(L, 1, "not in range 1..256");
unreachable;
}
CHECK_NOTNULL((p = LuaAlloc(L, n)));
p = LuaAllocOrDie(L, n);
CHECK_EQ(n, getrandom(p, n, 0));
lua_pushlstring(L, p, n);
free(p);
@ -648,7 +648,8 @@ int LuaBenchmark(lua_State *L) {
if (TSC_AUX_CORE(Rdpid()) == core && GetInterrupts() == interrupts) {
break;
} else if (attempts >= maxattempts) {
return luaL_error(L, "system is under too much load to run benchmark");
luaL_error(L, "system is under too much load to run benchmark");
unreachable;
}
}
overhead = avgticks;
@ -669,7 +670,8 @@ int LuaBenchmark(lua_State *L) {
if (TSC_AUX_CORE(Rdpid()) == core && GetInterrupts() == interrupts) {
break;
} else if (attempts >= maxattempts) {
return luaL_error(L, "system is under too much load to run benchmark");
luaL_error(L, "system is under too much load to run benchmark");
unreachable;
}
}
avgticks = MAX(avgticks - overhead, 0);
@ -682,7 +684,24 @@ int LuaBenchmark(lua_State *L) {
return 4;
}
static void LuaCompress2(lua_State *L, void *dest, size_t *destLen,
const void *source, size_t sourceLen, int level) {
switch (compress2(dest, destLen, source, sourceLen, level)) {
case Z_OK:
break;
case Z_BUF_ERROR:
luaL_error(L, "out of memory");
unreachable;
case Z_STREAM_ERROR:
luaL_error(L, "invalid level");
unreachable;
default:
unreachable;
}
}
int LuaCompress(lua_State *L) {
int rc;
bool raw;
size_t n, m;
char *q, *e;
@ -694,19 +713,17 @@ int LuaCompress(lua_State *L) {
m = compressBound(n);
if (lua_toboolean(L, 3)) {
// raw mode
CHECK_NOTNULL((q = LuaAlloc(L, m)));
CHECK_EQ(Z_OK,
compress2((unsigned char *)q, &m, (unsigned char *)p, n, level));
q = LuaAllocOrDie(L, m);
LuaCompress2(L, q, &m, p, n, level);
lua_pushlstring(L, q, m);
} else {
// easy mode
CHECK_NOTNULL((q = LuaAlloc(L, 10 + 4 + m)));
q = LuaAllocOrDie(L, 10 + 4 + m);
crc = crc32_z(0, p, n);
e = uleb64(q, n);
e = WRITE32LE(e, crc);
hdrlen = e - q;
CHECK_EQ(Z_OK, compress2((unsigned char *)(q + hdrlen), &m,
(unsigned char *)p, n, level));
LuaCompress2(L, q + hdrlen, &m, p, n, level);
lua_pushlstring(L, q, hdrlen + m);
}
free(q);
@ -727,7 +744,7 @@ int LuaUncompress(lua_State *L) {
}
len = m;
crc = READ32LE(p + rc);
CHECK_NOTNULL((q = LuaAlloc(L, m)));
q = LuaAllocOrDie(L, m);
if (uncompress((void *)q, &m, (unsigned char *)p + rc + 4, n) != Z_OK ||
m != len || crc32_z(0, q, m) != crc) {
free(q);
@ -736,7 +753,7 @@ int LuaUncompress(lua_State *L) {
}
} else {
len = m = luaL_checkinteger(L, 2);
CHECK_NOTNULL((q = LuaAlloc(L, m)));
q = LuaAllocOrDie(L, m);
if (uncompress((void *)q, &m, (void *)p, n) != Z_OK || m != len) {
free(q);
luaL_error(L, "compressed value is corrupted");

View file

@ -13,6 +13,7 @@ int luaopen_lsqlite3(lua_State *);
void *LuaRealloc(lua_State *, void *, size_t);
void *LuaAlloc(lua_State *, size_t);
void *LuaAllocOrDie(lua_State *, size_t);
int LuaBenchmark(lua_State *);
int LuaBin(lua_State *);

View file

@ -120,6 +120,16 @@ void *LuaAlloc(lua_State *L, size_t n) {
return LuaRealloc(L, 0, n);
}
void *LuaAllocOrDie(lua_State *L, size_t n) {
void *p;
if ((p = LuaAlloc(L, n))) {
return p;
} else {
luaL_error(L, "out of memory");
unreachable;
}
}
static lua_Integer FixLimit(long x) {
if (0 <= x && x < RLIM_INFINITY) {
return x;
@ -434,19 +444,18 @@ static int LuaUnixReadlink(lua_State *L) {
size_t got, bufsiz = 8192;
path = luaL_checkstring(L, 1);
dirfd = luaL_optinteger(L, 2, AT_FDCWD);
if ((buf = LuaAlloc(L, bufsiz))) {
if ((rc = readlinkat(dirfd, path, buf, bufsiz)) != -1) {
got = rc;
if (got < bufsiz) {
lua_pushlstring(L, buf, got);
free(buf);
return 1;
} else {
enametoolong();
}
buf = LuaAllocOrDie(L, bufsiz);
if ((rc = readlinkat(dirfd, path, buf, bufsiz)) != -1) {
got = rc;
if (got < bufsiz) {
lua_pushlstring(L, buf, got);
free(buf);
return 1;
} else {
enametoolong();
}
free(buf);
}
free(buf);
return SysretErrno(L, "readlink", olderr);
}
@ -535,16 +544,13 @@ static int LuaUnixCommandv(lua_State *L) {
char *pathbuf, *resolved;
olderr = errno;
prog = luaL_checkstring(L, 1);
if ((pathbuf = LuaAlloc(L, PATH_MAX))) {
if ((resolved = commandv(prog, pathbuf, PATH_MAX))) {
lua_pushstring(L, resolved);
free(pathbuf);
return 1;
} else {
free(pathbuf);
return SysretErrno(L, "commandv", olderr);
}
pathbuf = LuaAllocOrDie(L, PATH_MAX);
if ((resolved = commandv(prog, pathbuf, PATH_MAX))) {
lua_pushstring(L, resolved);
free(pathbuf);
return 1;
} else {
free(pathbuf);
return SysretErrno(L, "commandv", olderr);
}
}
@ -905,22 +911,19 @@ static int LuaUnixRead(lua_State *L) {
bufsiz = luaL_optinteger(L, 2, BUFSIZ);
offset = luaL_optinteger(L, 3, -1);
bufsiz = MIN(bufsiz, 0x7ffff000);
if ((buf = LuaAlloc(L, bufsiz))) {
if (offset == -1) {
rc = read(fd, buf, bufsiz);
} else {
rc = pread(fd, buf, bufsiz, offset);
}
if (rc != -1) {
got = rc;
lua_pushlstring(L, buf, got);
free(buf);
return 1;
} else {
free(buf);
return SysretErrno(L, "read", olderr);
}
buf = LuaAllocOrDie(L, bufsiz);
if (offset == -1) {
rc = read(fd, buf, bufsiz);
} else {
rc = pread(fd, buf, bufsiz, offset);
}
if (rc != -1) {
got = rc;
lua_pushlstring(L, buf, got);
free(buf);
return 1;
} else {
free(buf);
return SysretErrno(L, "read", olderr);
}
}
@ -1238,9 +1241,7 @@ static int LuaUnixSiocgifconf(lua_State *L) {
struct ifreq *ifr;
struct ifconf conf;
olderr = errno;
if (!(data = LuaAlloc(L, (n = 4096)))) {
return SysretErrno(L, "siocgifconf", olderr);
}
data = LuaAllocOrDie(L, (n = 4096));
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
free(data);
return SysretErrno(L, "siocgifconf", olderr);
@ -1384,20 +1385,17 @@ static int LuaUnixRecvfrom(lua_State *L) {
bufsiz = luaL_optinteger(L, 2, 1500);
bufsiz = MIN(bufsiz, 0x7ffff000);
flags = luaL_optinteger(L, 3, 0);
if ((buf = LuaAlloc(L, bufsiz))) {
rc = recvfrom(fd, buf, bufsiz, flags, &sa, &addrsize);
if (rc != -1) {
got = rc;
lua_pushlstring(L, buf, got);
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
lua_pushinteger(L, ntohs(sa.sin_port));
free(buf);
return 3;
} else {
free(buf);
return SysretErrno(L, "recvfrom", olderr);
}
buf = LuaAllocOrDie(L, bufsiz);
rc = recvfrom(fd, buf, bufsiz, flags, &sa, &addrsize);
if (rc != -1) {
got = rc;
lua_pushlstring(L, buf, got);
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
lua_pushinteger(L, ntohs(sa.sin_port));
free(buf);
return 3;
} else {
free(buf);
return SysretErrno(L, "recvfrom", olderr);
}
}
@ -1415,18 +1413,15 @@ static int LuaUnixRecv(lua_State *L) {
bufsiz = luaL_optinteger(L, 2, 1500);
bufsiz = MIN(bufsiz, 0x7ffff000);
flags = luaL_optinteger(L, 3, 0);
if ((buf = LuaAlloc(L, bufsiz))) {
rc = recv(fd, buf, bufsiz, flags);
if (rc != -1) {
got = rc;
lua_pushlstring(L, buf, got);
free(buf);
return 1;
} else {
free(buf);
return SysretErrno(L, "recv", olderr);
}
buf = LuaAllocOrDie(L, bufsiz);
rc = recv(fd, buf, bufsiz, flags);
if (rc != -1) {
got = rc;
lua_pushlstring(L, buf, got);
free(buf);
return 1;
} else {
free(buf);
return SysretErrno(L, "recv", olderr);
}
}

View file

@ -115,10 +115,10 @@ o/$(MODE)/tool/net/redbean.com: \
tool/net/redbean.png
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/net/.redbean/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/tool/net/.redbean/.symtab
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/net/.redbean/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/net/.redbean/.symtab \
tool/net/help.txt \
tool/net/.init.lua \
tool/net/favicon.ico \
@ -260,9 +260,8 @@ o/$(MODE)/tool/net/redbean-demo.com: \
@$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-demo
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/net/.redbean-demo/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/tool/net/.redbean-demo/.symtab
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/net/.redbean-demo/.symtab \
tool/net/help.txt
# REDBEAN-STATIC.COM
@ -281,9 +280,8 @@ o/$(MODE)/tool/net/redbean-static.com: \
@$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-static
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/net/.redbean-static/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/tool/net/.redbean-static/.symtab
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/net/.redbean-static/.symtab \
tool/net/help.txt \
tool/net/favicon.ico \
tool/net/redbean.png
@ -316,9 +314,8 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \
@$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-unsecure
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/net/.redbean-unsecure/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/tool/net/.redbean-unsecure/.symtab
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/net/.redbean-unsecure/.symtab \
tool/net/help.txt \
tool/net/favicon.ico \
tool/net/redbean.png
@ -331,6 +328,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \
o/$(MODE)/tool/net/lunix.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/largon2.o \
o/$(MODE)/tool/net/net.pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@ -358,9 +356,8 @@ o/$(MODE)/tool/net/redbean-original.com: \
@$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-original
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/net/.redbean-original/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/tool/net/.redbean-original/.symtab
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/net/.redbean-original/.symtab \
tool/net/help.txt \
tool/net/favicon.ico \
tool/net/redbean.png

View file

@ -34,9 +34,11 @@
#include "libc/dos.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/mem/alloca.h"
#include "libc/nexgen32e/bsr.h"
@ -51,13 +53,13 @@
#include "libc/runtime/clktck.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/stack.h"
#include "libc/sock/goodsocket.internal.h"
#include "libc/sock/sock.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/hex.internal.h"
#include "libc/str/slice.h"
#include "libc/str/undeflate.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/dt.h"
@ -66,6 +68,7 @@
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/inaddr.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
@ -164,12 +167,10 @@ STATIC_YOINK("zip_uri_support");
} \
} while (0)
// letters not used: EIJNOQYnoqwxy
// letters not used: EINOQYnoqwxy
// digits not used: 0123456789
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
#define GETOPTS "BSVXZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:"
extern unsigned long long __kbirth;
// puncts not used: !"#$&'()*+,-./;<=>@[\]^_`{|}~
#define GETOPTS "%BJSVXZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:"
static const uint8_t kGzipHeader[] = {
0x1F, // MAGNUM
@ -329,21 +330,23 @@ static const char kCounterNames[] =
typedef ssize_t (*reader_f)(int, void *, size_t);
typedef ssize_t (*writer_f)(int, struct iovec *, int);
static bool usessl;
static bool suiteb;
static bool killed;
static bool istext;
static bool zombied;
static bool gzipped;
static bool branded;
static bool usingssl;
static bool funtrace;
static bool systrace;
static bool meltdown;
static bool unsecure;
static bool norsagen;
static bool printport;
static bool daemonize;
static bool logrusage;
static bool logbodies;
static bool requiressl;
static bool isterminal;
static bool sslcliused;
static bool loglatency;
@ -1459,7 +1462,7 @@ static ssize_t SslWrite(int fd, struct iovec *iov, int iovlen) {
static void NotifyClose(void) {
#ifndef UNSECURE
if (usessl) {
if (usingssl) {
DEBUGF("(ssl) SSL notifying close");
mbedtls_ssl_close_notify(&ssl);
}
@ -1615,7 +1618,7 @@ static bool TlsSetup(void) {
if (!(r = mbedtls_ssl_handshake(&ssl)) && TlsFlush(&g_bio, 0, 0) != -1) {
LockInc(&shared->c.sslhandshakes);
g_bio.c = -1;
usessl = true;
usingssl = true;
reader = SslRead;
writer = SslWrite;
WipeServingKeys();
@ -1855,14 +1858,20 @@ static void LoadCertificates(void) {
#ifdef MBEDTLS_ECP_C
ecp = GenerateEcpCertificate(ksk.key ? &ksk : 0);
if (!havecert) UseCertificate(&conf, &ecp, "server");
if (!haveclientcert && ksk.key) UseCertificate(&confcli, &ecp, "client");
if (!haveclientcert && ksk.key) {
UseCertificate(&confcli, &ecp, "client");
}
AppendCert(ecp.cert, ecp.key);
#endif
#ifdef MBEDTLS_RSA_C
rsa = GenerateRsaCertificate(ksk.key ? &ksk : 0);
if (!havecert) UseCertificate(&conf, &rsa, "server");
if (!haveclientcert && ksk.key) UseCertificate(&confcli, &rsa, "client");
AppendCert(rsa.cert, rsa.key);
if (!norsagen) {
rsa = GenerateRsaCertificate(ksk.key ? &ksk : 0);
if (!havecert) UseCertificate(&conf, &rsa, "server");
if (!haveclientcert && ksk.key) {
UseCertificate(&confcli, &rsa, "client");
}
AppendCert(rsa.cert, rsa.key);
}
#endif
}
WipeSigningKeys();
@ -2138,43 +2147,8 @@ static char *AppendContentRange(char *p, long a, long b, long c) {
}
static bool Inflate(void *dp, size_t dn, const void *sp, size_t sn) {
int rc;
z_stream zs;
struct DeflateState ds;
LockInc(&shared->c.inflates);
if (IsTiny()) {
return undeflate(dp, dn, sp, sn, &ds) != -1;
} else {
zs.zfree = 0;
zs.zalloc = 0;
zs.next_in = sp;
zs.avail_in = sn;
zs.total_in = sn;
zs.next_out = dp;
zs.avail_out = dn;
zs.total_out = dn;
CHECK_EQ(Z_OK, inflateInit2(&zs, -MAX_WBITS));
switch ((rc = inflate(&zs, Z_NO_FLUSH))) {
case Z_STREAM_END:
CHECK_EQ(Z_OK, inflateEnd(&zs));
return true;
case Z_DATA_ERROR:
inflateEnd(&zs);
WARNF("(zip) Z_DATA_ERROR: %s", zs.msg);
return false;
case Z_NEED_DICT:
inflateEnd(&zs);
WARNF("(zip) Z_NEED_DICT");
return false;
case Z_MEM_ERROR:
DIEF("(zip) Z_MEM_ERROR");
default:
DIEF("(zip) inflate()→%d dn=%ld sn=%ld "
"next_in=%ld avail_in=%ld next_out=%ld avail_out=%ld",
rc, dn, sn, (char *)zs.next_in - (char *)sp, zs.avail_in,
(char *)zs.next_out - (char *)dp, zs.avail_out);
}
}
return !__inflate(dp, dn, sp, sn);
}
static bool Verify(void *data, size_t size, uint32_t crc) {
@ -2288,7 +2262,7 @@ static ssize_t Send(struct iovec *iov, int iovlen) {
}
static bool IsSslCompressed(void) {
return usessl && ssl.session->compression;
return usingssl && ssl.session->compression;
}
static char *CommitOutput(char *p) {
@ -2525,7 +2499,7 @@ static char *ServeAssetCompressed(struct Asset *a) {
dg.t = 0;
dg.i = 0;
dg.c = 0;
if (usessl) {
if (usingssl) {
dg.z = 512 + (rand64() & 1023);
} else {
dg.z = 65536;
@ -3333,7 +3307,7 @@ static int LuaGetStatus(lua_State *L) {
static int LuaGetSslIdentity(lua_State *L) {
const mbedtls_x509_crt *cert;
OnlyCallDuringRequest(L, "GetSslIdentity");
if (!usessl) {
if (!usingssl) {
lua_pushnil(L);
} else {
if (sslpskindex) {
@ -3684,7 +3658,7 @@ static int LuaFetch(lua_State *L) {
#define ssl nope // TODO(jart): make this file less huge
char *p;
ssize_t rc;
bool usessl;
bool usingssl;
uint32_t ip;
struct Url url;
int t, ret, sock, methodidx, hdridx;
@ -3785,12 +3759,12 @@ static int LuaFetch(lua_State *L) {
*/
gc(ParseUrl(urlarg, urlarglen, &url));
gc(url.params.p);
usessl = false;
usingssl = false;
if (url.scheme.n) {
#ifndef UNSECURE
if (!unsecure && url.scheme.n == 5 &&
!memcasecmp(url.scheme.p, "https", 5)) {
usessl = true;
usingssl = true;
} else
#endif
if (!(url.scheme.n == 4 && !memcasecmp(url.scheme.p, "http", 4))) {
@ -3800,7 +3774,7 @@ static int LuaFetch(lua_State *L) {
}
#ifndef UNSECURE
if (usessl && !sslinitialized) TlsInit();
if (usingssl && !sslinitialized) TlsInit();
#endif
if (url.host.n) {
@ -3808,7 +3782,7 @@ static int LuaFetch(lua_State *L) {
if (url.port.n) {
port = gc(strndup(url.port.p, url.port.n));
#ifndef UNSECURE
} else if (usessl) {
} else if (usingssl) {
port = "443";
#endif
} else {
@ -3880,7 +3854,7 @@ static int LuaFetch(lua_State *L) {
}
#ifndef UNSECURE
if (usessl) {
if (usingssl) {
if (sslcliused) {
mbedtls_ssl_session_reset(&sslcli);
} else {
@ -3921,7 +3895,7 @@ static int LuaFetch(lua_State *L) {
*/
DEBUGF("(ftch) client sending %s request", method);
#ifndef UNSECURE
if (usessl) {
if (usingssl) {
ret = mbedtls_ssl_write(&sslcli, request, requestlen);
if (ret != requestlen) {
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) goto VerifyFailed;
@ -3953,7 +3927,7 @@ static int LuaFetch(lua_State *L) {
}
NOISEF("(ftch) client reading");
#ifndef UNSECURE
if (usessl) {
if (usingssl) {
if ((rc = mbedtls_ssl_read(&sslcli, inbuf.p + inbuf.n,
inbuf.c - inbuf.n)) < 0) {
if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
@ -4457,7 +4431,7 @@ static int LuaSetCookie(lua_State *L) {
issecurepref =
keylen > strlen(securepref) &&
SlicesEqual(key, strlen(securepref), securepref, strlen(securepref));
if ((ishostpref || issecurepref) && !usessl) {
if ((ishostpref || issecurepref) && !usingssl) {
luaL_argerror(
L, 1,
gc(xasprintf("%s and %s prefixes require SSL", hostpref, securepref)));
@ -4625,7 +4599,7 @@ static int LuaGetClientFd(lua_State *L) {
static int LuaIsClientUsingSsl(lua_State *L) {
OnlyCallDuringConnection(L, "IsClientUsingSsl");
lua_pushboolean(L, usessl);
lua_pushboolean(L, usingssl);
return 1;
}
@ -4760,6 +4734,11 @@ static int LuaProgramSslClientVerify(lua_State *L) {
return LuaProgramBool(L, &sslclientverify);
}
static int LuaProgramSslRequired(lua_State *L) {
OnlyCallFromInitLua(L, "ProgramSslRequired");
return LuaProgramBool(L, &requiressl);
}
static int LuaProgramSslFetchVerify(lua_State *L) {
OnlyCallFromMainProcess(L, "ProgramSslFetchVerify");
return LuaProgramBool(L, &sslfetchverify);
@ -4984,6 +4963,7 @@ static const char *const kDontAutoComplete[] = {
"ProgramPrivateKey", // TODO
"ProgramSslCiphersuite", // TODO
"ProgramSslClientVerify", // TODO
"LuaProgramSslRequired", // TODO
"ProgramSslCompression", //
"ProgramSslTicketLifetime", //
"ProgramTimeout", // TODO
@ -5108,7 +5088,6 @@ static const luaL_Reg kLuaFuncs[] = {
{"ProgramAddr", LuaProgramAddr}, //
{"ProgramBrand", LuaProgramBrand}, //
{"ProgramCache", LuaProgramCache}, //
{"ProgramCertificate", LuaProgramCertificate}, //
{"ProgramDirectory", LuaProgramDirectory}, //
{"ProgramGid", LuaProgramGid}, //
{"ProgramHeader", LuaProgramHeader}, //
@ -5117,7 +5096,6 @@ static const luaL_Reg kLuaFuncs[] = {
{"ProgramLogPath", LuaProgramLogPath}, //
{"ProgramPidPath", LuaProgramPidPath}, //
{"ProgramPort", LuaProgramPort}, //
{"ProgramPrivateKey", LuaProgramPrivateKey}, //
{"ProgramRedirect", LuaProgramRedirect}, //
{"ProgramTimeout", LuaProgramTimeout}, //
{"ProgramUid", LuaProgramUid}, //
@ -5157,12 +5135,15 @@ static const luaL_Reg kLuaFuncs[] = {
#ifndef UNSECURE
{"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, //
{"GetSslIdentity", LuaGetSslIdentity}, //
{"ProgramCertificate", LuaProgramCertificate}, //
{"ProgramPrivateKey", LuaProgramPrivateKey}, //
{"ProgramSslCiphersuite", LuaProgramSslCiphersuite}, //
{"ProgramSslClientVerify", LuaProgramSslClientVerify}, //
{"ProgramSslCompression", LuaProgramSslCompression}, //
{"ProgramSslFetchVerify", LuaProgramSslFetchVerify}, //
{"ProgramSslInit", LuaProgramSslInit}, //
{"ProgramSslPresharedKey", LuaProgramSslPresharedKey}, //
{"ProgramSslRequired", LuaProgramSslRequired}, //
{"ProgramSslTicketLifetime", LuaProgramSslTicketLifetime}, //
#endif
};
@ -5172,9 +5153,7 @@ static const luaL_Reg kLuaLibs[] = {
{"unix", LuaUnix}, //
{"maxmind", LuaMaxmind}, //
{"lsqlite3", luaopen_lsqlite3}, //
#ifndef UNSECURE
{"argon2", luaopen_argon2}, //
#endif
{"argon2", luaopen_argon2}, //
};
static void LuaSetArgv(lua_State *L) {
@ -5742,7 +5721,7 @@ static void ParseRequestParameters(void) {
url.path.n = 1;
}
if (!url.scheme.n) {
if (usessl) {
if (usingssl) {
url.scheme.p = "https";
url.scheme.n = 5;
} else {
@ -6212,6 +6191,7 @@ static bool IsSsl(unsigned char c) {
}
static void HandleMessages(void) {
char *p;
bool once;
ssize_t rc;
size_t got;
@ -6238,6 +6218,9 @@ static void HandleMessages(void) {
} else {
return;
}
} else if (requiressl) {
INFOF("(clnt) %s didn't send an ssl hello", DescribeClient());
return;
} else {
WipeServingKeys();
}
@ -6629,7 +6612,7 @@ static int HandleConnection(size_t i) {
} else {
switch ((pid = fork())) {
case 0:
if (monitortty) {
if (!IsTiny() && monitortty) {
MonitorMemory();
}
meltdown = false;
@ -6680,8 +6663,8 @@ static int HandleConnection(size_t i) {
inbuf.c = 0;
}
#ifndef UNSECURE
if (usessl) {
usessl = false;
if (usingssl) {
usingssl = false;
reader = read;
writer = WritevAll;
mbedtls_ssl_session_reset(&ssl);
@ -7023,7 +7006,7 @@ static void TlsInit(void) {
if (unsecure) return;
if (suiteb && !X86_HAVE(AES)) {
WARNF("you're using suite b crypto but don't have aes-ni");
WARNF("you're using suite b crypto but you don't have aes-ni");
}
if (!sslinitialized) {
@ -7130,15 +7113,16 @@ static void GetOpts(int argc, char *argv[]) {
CASE('v', ++__log_level);
CASE('s', --__log_level);
CASE('X', unsecure = true);
CASE('%', norsagen = true);
CASE('Z', systrace = true);
CASE('b', logbodies = true);
CASE('z', printport = true);
CASE('d', daemonize = true);
CASE('a', logrusage = true);
CASE('J', requiressl = true);
CASE('u', uniprocess = true);
CASE('g', loglatency = true);
CASE('m', logmessages = true);
CASE('W', monitortty = optarg);
CASE('l', ProgramAddr(optarg));
CASE('H', ProgramHeader(optarg));
CASE('L', ProgramLogPath(optarg));
@ -7153,6 +7137,9 @@ static void GetOpts(int argc, char *argv[]) {
CASE('t', ProgramTimeout(ParseInt(optarg)));
CASE('h', PrintUsage(1, EXIT_SUCCESS));
CASE('M', ProgramMaxPayloadSize(ParseInt(optarg)));
#if !IsTiny()
CASE('W', monitortty = optarg);
#endif
#ifndef STATIC
CASE('e', LuaEvalCode(optarg));
CASE('F', LuaEvalFile(optarg));
@ -7235,11 +7222,13 @@ void RedBean(int argc, char *argv[]) {
inbuf = inbuf_actual;
isinitialized = true;
CallSimpleHookIfDefined("OnServerStart");
if (monitortty && (daemonize || uniprocess)) {
monitortty = 0;
}
if (monitortty) {
MonitorMemory();
if (!IsTiny()) {
if (monitortty && (daemonize || uniprocess)) {
monitortty = 0;
}
if (monitortty) {
MonitorMemory();
}
}
#ifdef STATIC
EventLoop(HEARTBEAT);
@ -7265,11 +7254,13 @@ void RedBean(int argc, char *argv[]) {
TlsDestroy();
MemDestroy();
}
if (monitortty) {
terminatemonitor = true;
_spinlock(monitortid);
munmap(monitorstack, GetStackSize());
free(monitortls);
if (!IsTiny()) {
if (monitortty) {
terminatemonitor = true;
_spinlock(monitortid);
munmap(monitorstack, GetStackSize());
free(monitortls);
}
}
INFOF("(srvr) shutdown complete");
}

View file

@ -54,8 +54,9 @@ o/$(MODE)/tool/plinko/plinko.com: \
tool/plinko/plinko.mk
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/plinko/.redbean
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/plinko/.plinko/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/plinko/.plinko/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/plinko/.plinko/.symtab
$(TOOL_PLINKO_OBJS): \

View file

@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
}
// usage report
fprintf(stderr, "options used: ");
fprintf(stderr, "// options used: ");
for (j = i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i]) {
@ -56,7 +56,7 @@ int main(int argc, char *argv[]) {
}
if (!j) fprintf(stderr, "none");
fprintf(stderr, "\n");
fprintf(stderr, "letters not used: ");
fprintf(stderr, "// letters not used: ");
for (j = i = 0; i < 128; ++i) {
if (!isalpha(i)) continue;
if (!letters_used[i]) {
@ -66,7 +66,7 @@ int main(int argc, char *argv[]) {
}
if (!j) fprintf(stderr, "none");
fprintf(stderr, "\n");
fprintf(stderr, "digits not used: ");
fprintf(stderr, "// digits not used: ");
for (j = i = 0; i < 128; ++i) {
if (!isdigit(i)) continue;
if (!letters_used[i]) {
@ -76,7 +76,7 @@ int main(int argc, char *argv[]) {
}
if (!j) fprintf(stderr, "none");
fprintf(stderr, "\n");
fprintf(stderr, "puncts not used: ");
fprintf(stderr, "// puncts not used: ");
for (j = i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (isalnum(i)) continue;
@ -87,7 +87,7 @@ int main(int argc, char *argv[]) {
}
if (!j) fprintf(stderr, "none");
fprintf(stderr, "\n");
fprintf(stderr, "letters duplicated: ");
fprintf(stderr, "// letters duplicated: ");
for (j = i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i] > 1) {
@ -100,7 +100,7 @@ int main(int argc, char *argv[]) {
// generated code
hasargless = false;
printf("\n#define GETOPTS \"");
printf("#define GETOPTS \"");
for (j = i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i] && !letters_with_args[i]) {
@ -131,13 +131,13 @@ int main(int argc, char *argv[]) {
printf(" ARGS...\\n\\\n");
for (j = i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i]) {
if (letters_used[i] && !letters_with_args[i]) {
printf(" -%c the %c option\\n\\\n", i, i);
}
}
for (j = i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i]) {
if (letters_with_args[i]) {
printf(" -%c VAL the %c option\\n\\\n", i, i);
}
}
@ -146,24 +146,30 @@ int main(int argc, char *argv[]) {
for (i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i]) {
if (isalpha(i) || i == '_') {
printf("int %cflag;\n", i);
if (letters_with_args[i]) {
printf("const char *");
} else {
printf("int ");
}
if (isalnum(i) || i == '_') {
printf("g_%cflag;\n", i);
}
}
}
printf("\n\
static void GetOpts(int argc, char *argv[]) {\n\
int opt;\n\
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {\n\
switch (opt) {\n");
for (i = 0; i < 128; ++i) {
if (!IsLegal(i)) continue;
if (letters_used[i]) {
printf(" case '%c':\n", i);
if (isalpha(i) || i == '_') {
printf(" %cflag", i);
if (isalnum(i) || i == '_') {
printf(" g_%cflag", i);
} else {
printf(" XXXflag", i);
printf(" g_XXXflag", i);
}
if (letters_with_args[i]) {
printf(" = optarg;\n");
@ -175,14 +181,19 @@ static void GetOpts(int argc, char *argv[]) {\n\
}
printf(" case '?':\n");
printf(" write(1, USAGE, strlen(USAGE));\n");
printf(" write(1, USAGE, sizeof(USAGE) - 1);\n");
printf(" exit(0);\n");
printf(" default:\n");
printf(" write(2, USAGE, strlen(USAGE));\n");
printf(" write(2, USAGE, sizeof(USAGE) - 1);\n");
printf(" exit(64);\n");
printf(" }\n");
printf(" }\n");
printf("}\n");
printf("\n");
printf("int main(int argc, char *argv[]) {\n");
printf(" GetOpts(argc, argv);\n");
printf("}\n");
return 0;
}

View file

@ -88,7 +88,7 @@ o/$(MODE)/tool/viz/printimage.com: \
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/viz/.printimage/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/viz/.printimage/.symtab
o/$(MODE)/tool/viz/printvideo.com: \
@ -98,7 +98,7 @@ o/$(MODE)/tool/viz/printvideo.com: \
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
-o o/$(MODE)/tool/viz/.printvideo/.symtab $<
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
o/$(MODE)/tool/viz/.printvideo/.symtab
o/$(MODE)/tool/viz/derasterize.o: \