mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
3f49889841
- Fix preadv() and pwritev() for old distros - Introduce _npassert() and _unassert() macros - Prove that file locks work properly on Windows - Support fcntl(F_DUPFD_CLOEXEC) on more systems
330 lines
8.9 KiB
C
330 lines
8.9 KiB
C
/*-*- 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/mem/gc.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/str/tab.internal.h"
|
|
#include "libc/x/xasprintf.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];
|
|
bool identity;
|
|
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] = identity ? 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] = identity ? i : dig; */
|
|
xlat[argv[k][i] & 255] = identity ? (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 'I':
|
|
identity = !identity;
|
|
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,", (char)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));
|
|
}
|