Add minor improvements and cleanup

main
Justine Tunney 2020-10-27 03:39:46 -07:00
parent 9e3e985ae5
commit feed0d2b0e
163 changed files with 2286 additions and 2245 deletions

View File

@ -117,7 +117,6 @@ include libc/ohmyplus/ohmyplus.mk # │
include libc/zipos/zipos.mk # │
include third_party/dtoa/dtoa.mk # │
include libc/time/time.mk # │
include libc/escape/escape.mk # │
include libc/alg/alg.mk # │
include libc/calls/hefty/hefty.mk # │
include libc/stdio/stdio.mk # │

View File

@ -128,7 +128,7 @@
/* Long Mode Paging
@see Intel Manual V.3A §4.1 §4.5
IsValid (ignored on CR3) V
Block Instr. Fetches (if NXE) IsWritable (ignored on CR3) RW
XD:No Inst. Fetches (if NXE) IsWritable (ignored on CR3) RW
Permit User-Mode Access - u
Page-level Write-Through - PWT
Page-level Cache Disable - PCD
@ -147,7 +147,6 @@
Phys. Addr. 1GB
0b00000000000011111111111111111111111111111111111111000000000000
6666555555555544444444443333333333222222222211111111110000000000
3210987654321098765432109876543210987654321098765432109876543210*/
#define PAGE_V /* */ 0b000000001

View File

@ -15,22 +15,22 @@
# remove comments
s/[ \t][ \t]*#.*//
#s/leave\(q\|\)/leavew/
#s/call\(q\|\)/callw/
#s/ret\(q\|\)/retw/
#s/popq\t%rbp/pop\t%bp/
#s/pushq\t%rbp/push\t%bp/
#s/pushq\t\(.*\)/sub $6,%sp\n\tpush \1/
#s/popq\t\(.*\)/pop \1\n\tadd $6,%sp/
# preserve hardcoded stack offsets
# bloats code size 13%
s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/
s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/
s/ret\(q\|\)/retw\t$6/
s/leave\(q\|\)/leavew/
s/call\(q\|\)/callw/
s/ret\(q\|\)/retw/
s/popq\t%rbp/pop\t%bp/
s/pushq\t%rbp/push\t%bp/
s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/
s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
# # preserve hardcoded stack offsets
# # bloats code size 13%
# s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/
# s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/
# s/ret\(q\|\)/retw\t$6/
# s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/
# s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
s/, /,/g
# 32-bitify

View File

@ -27,24 +27,21 @@ struct Itoa8 kItoa8;
static textstartup void itoa8_init(void) {
int i;
uint8_t z;
char p[4];
uint32_t w;
for (i = 0; i < 256; ++i) {
memset(p, 0, sizeof(p));
if (i < 10) {
z = 1;
p[0] = '0' + i;
w = '0' + i;
} else if (i < 100) {
z = 2;
p[0] = '0' + i / 10;
p[1] = '0' + i % 10;
w = ('0' + i / 10) | ('0' + i % 10) << 8;
} else {
z = 3;
p[0] = '0' + i / 100;
p[1] = '0' + i % 100 / 10;
p[2] = '0' + i % 100 % 10;
w = ('0' + i / 100) | ('0' + i % 100 / 10) << 8 |
('0' + i % 100 % 10) << 16;
}
kItoa8.size[i] = z;
memcpy(&kItoa8.data[i], p, sizeof(p));
kItoa8.data[i] = w;
}
}

View File

@ -240,8 +240,9 @@ static const struct Pick kPicksMixBlock[32] = {
{TL, TR, 9}, /* ▓ */
};
static unsigned short bdist(struct TtyRgb a, struct TtyRgb b, struct TtyRgb c,
struct TtyRgb d, struct TtyRgb w, struct TtyRgb x,
static unsigned short GetBlockDist(struct TtyRgb a, struct TtyRgb b,
struct TtyRgb c, struct TtyRgb d,
struct TtyRgb w, struct TtyRgb x,
struct TtyRgb y, struct TtyRgb z) {
unsigned short dist;
dist = 0;
@ -260,7 +261,7 @@ static unsigned short bdist(struct TtyRgb a, struct TtyRgb b, struct TtyRgb c,
return dist;
}
static uint16_t *mixblock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr,
static uint16_t *MixBlock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr,
struct TtyRgb tbl, struct TtyRgb tbr,
struct TtyRgb qtl, struct TtyRgb qtr,
struct TtyRgb qbl, struct TtyRgb qbr) {
@ -465,15 +466,15 @@ static uint16_t *mixblock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr,
return p;
}
static struct TtyRgb getquant(struct TtyRgb rgb) {
static struct TtyRgb GetQuant(struct TtyRgb rgb) {
return g_ansi2rgb_[rgb.xt];
}
static uint16_t *pickunicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
static uint16_t *PickUnicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br,
struct TtyRgb tl2, struct TtyRgb tr2,
struct TtyRgb bl2, struct TtyRgb br2) {
#define PICK(A, B, C, D) *p++ = bdist(tl, tr, bl, br, A, B, C, D)
#define PICK(A, B, C, D) *p++ = GetBlockDist(tl, tr, bl, br, A, B, C, D)
PICK(bl2, bl2, bl2, bl2); /* k=0 bg=bl fg=NULL */
PICK(bl2, bl2, bl2, br2); /* ▗ k=4 bg=bl fg=br */
PICK(bl2, bl2, bl2, tl2); /* ▗ k=4 bg=bl fg=tl */
@ -566,11 +567,11 @@ static uint16_t *pickunicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
return p;
}
static uint16_t *pickcp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
static uint16_t *PickCp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br,
struct TtyRgb tl2, struct TtyRgb tr2,
struct TtyRgb bl2, struct TtyRgb br2) {
#define PICK(A, B, C, D) *p++ = bdist(tl, tr, bl, br, A, B, C, D)
#define PICK(A, B, C, D) *p++ = GetBlockDist(tl, tr, bl, br, A, B, C, D)
PICK(bl2, bl2, bl2, bl2); /* k=0 bg=bl fg=NULL */
PICK(bl2, bl2, br2, br2); /* ▄ k=1 bg=bl fg=br */
PICK(bl2, bl2, tl2, tl2); /* ▄ k=1 bg=bl fg=tl */
@ -603,30 +604,30 @@ static uint16_t *pickcp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr,
return p;
}
static struct Pick pickblock_unicode_ansi(struct TtyRgb tl, struct TtyRgb tr,
static struct Pick PickBlockUnicodeAnsi(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
struct TtyRgb tl2 = getquant(tl);
struct TtyRgb tr2 = getquant(tr);
struct TtyRgb bl2 = getquant(bl);
struct TtyRgb br2 = getquant(br);
struct TtyRgb tl2 = GetQuant(tl);
struct TtyRgb tr2 = GetQuant(tr);
struct TtyRgb bl2 = GetQuant(bl);
struct TtyRgb br2 = GetQuant(br);
unsigned i, p1, p2;
uint16_t picks1[96] aligned(32);
uint16_t picks2[32] aligned(32);
memset(picks1, 0x79, sizeof(picks1));
memset(picks2, 0x79, sizeof(picks2));
pickunicode(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2);
mixblock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2);
PickUnicode(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2);
MixBlock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2);
p1 = windex(picks1, 96);
p2 = windex(picks2, 32);
return picks1[p1] <= picks2[p2] ? kPicksUnicode[p1] : kPicksMixBlock[p2];
}
static struct Pick pickblock_unicode_true(struct TtyRgb tl, struct TtyRgb tr,
static struct Pick PickBlockUnicodeTrue(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
unsigned i;
uint16_t picks[96] aligned(32);
memset(picks, 0x79, sizeof(picks));
pickunicode(picks, tl, tr, bl, br, tl, tr, bl, br);
PickUnicode(picks, tl, tr, bl, br, tl, tr, bl, br);
i = windex(picks, 96);
if (i >= 88) {
unsigned j;
@ -640,39 +641,39 @@ static struct Pick pickblock_unicode_true(struct TtyRgb tl, struct TtyRgb tr,
return kPicksUnicode[i];
}
static struct Pick pickblock_cp437_ansi(struct TtyRgb tl, struct TtyRgb tr,
static struct Pick PickBlockCp437Ansi(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
struct TtyRgb tl2 = getquant(tl);
struct TtyRgb tr2 = getquant(tr);
struct TtyRgb bl2 = getquant(bl);
struct TtyRgb br2 = getquant(br);
struct TtyRgb tl2 = GetQuant(tl);
struct TtyRgb tr2 = GetQuant(tr);
struct TtyRgb bl2 = GetQuant(bl);
struct TtyRgb br2 = GetQuant(br);
unsigned i, p1, p2;
uint16_t picks1[32] aligned(32);
uint16_t picks2[32] aligned(32);
memset(picks1, 0x79, sizeof(picks1));
memset(picks2, 0x79, sizeof(picks2));
pickcp437(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2);
mixblock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2);
PickCp437(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2);
MixBlock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2);
p1 = windex(picks1, 32);
p2 = windex(picks2, 32);
return picks1[p1] <= picks2[p2] ? kPicksCp437[p1] : kPicksMixBlock[p2];
}
static struct Pick pickblock_cp437_true(struct TtyRgb tl, struct TtyRgb tr,
static struct Pick PickBlockCp437True(struct TtyRgb tl, struct TtyRgb tr,
struct TtyRgb bl, struct TtyRgb br) {
unsigned i;
uint16_t picks[32] aligned(32);
memset(picks, 0x79, sizeof(picks));
pickcp437(picks, tl, tr, bl, br, tl, tr, bl, br);
PickCp437(picks, tl, tr, bl, br, tl, tr, bl, br);
return kPicksCp437[windex(picks, 32)];
}
static char *copyglyph(char *v, struct Glyph glyph) {
static char *CopyGlyph(char *v, struct Glyph glyph) {
memcpy(v, &glyph, 4);
return v + glyph.len;
}
static char *copyblock(char *v, const struct TtyRgb chunk[hasatleast 4],
static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4],
struct Pick pick, struct TtyRgb *bg, struct TtyRgb *fg,
struct Glyph *glyph) {
unsigned i;
@ -721,16 +722,16 @@ static char *copyblock(char *v, const struct TtyRgb chunk[hasatleast 4],
} else if (!ttyeq(*bg, chunk[pick.bg])) {
v = setbg(v, (*bg = chunk[pick.bg]));
}
return copyglyph(v, (*glyph = kGlyphs[i][pick.k]));
return CopyGlyph(v, (*glyph = kGlyphs[i][pick.k]));
}
static bool chunkeq(struct TtyRgb c[hasatleast 4],
static bool ChunkEq(struct TtyRgb c[hasatleast 4],
struct TtyRgb c2[hasatleast 4]) {
return ttyeq(c[TL], c[TR]) && ttyeq(c[BL], c[BR]) && ttyeq(c2[TL], c2[TR]) &&
ttyeq(c2[BL], c2[BR]);
}
static struct TtyRgb *copychunk(struct TtyRgb chunk[hasatleast 4],
static struct TtyRgb *CopyChunk(struct TtyRgb chunk[hasatleast 4],
const struct TtyRgb *c, size_t n) {
chunk[TL] = c[0 + 0];
chunk[TR] = c[0 + 1];
@ -739,7 +740,7 @@ static struct TtyRgb *copychunk(struct TtyRgb chunk[hasatleast 4],
return chunk;
}
static noinline char *copyrun(char *v, size_t n,
static noinline char *CopyRun(char *v, size_t n,
struct TtyRgb lastchunk[hasatleast 4],
const struct TtyRgb **c, size_t *x,
struct TtyRgb *bg, struct TtyRgb *fg,
@ -752,12 +753,12 @@ static noinline char *copyrun(char *v, size_t n,
*glyph = kGlyphs[0][0];
}
do {
v = copyglyph(v, *glyph);
v = CopyGlyph(v, *glyph);
*x += 2;
*c += 2;
if (*x >= n) break;
copychunk(chunk, *c, n);
} while (chunkeq(chunk, lastchunk));
CopyChunk(chunk, *c, n);
} while (ChunkEq(chunk, lastchunk));
*x -= 2;
*c -= 2;
return v;
@ -776,21 +777,21 @@ char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t n,
for (y = 0; y < yn; y += 2, c += n) {
if (y) *v++ = '\r', *v++ = '\n';
for (x = 0; x < n; x += 2, c += 2) {
copychunk(chun, c, n);
CopyChunk(chun, c, n);
if (ttyquant()->alg == kTtyQuantTrue) {
if (ttyquant()->blocks == kTtyBlocksCp437) {
p = pickblock_cp437_true(chun[TL], chun[TR], chun[BL], chun[BR]);
p = PickBlockCp437True(chun[TL], chun[TR], chun[BL], chun[BR]);
} else {
p = pickblock_unicode_true(chun[TL], chun[TR], chun[BL], chun[BR]);
p = PickBlockUnicodeTrue(chun[TL], chun[TR], chun[BL], chun[BR]);
}
} else {
if (ttyquant()->blocks == kTtyBlocksCp437) {
p = pickblock_cp437_ansi(chun[TL], chun[TR], chun[BL], chun[BR]);
p = PickBlockCp437Ansi(chun[TL], chun[TR], chun[BL], chun[BR]);
} else {
p = pickblock_unicode_ansi(chun[TL], chun[TR], chun[BL], chun[BR]);
p = PickBlockUnicodeAnsi(chun[TL], chun[TR], chun[BL], chun[BR]);
}
}
v = copyblock(v, chun, p, &bg, &fg, &glyph);
v = CopyBlock(v, chun, p, &bg, &fg, &glyph);
memcpy(lastchunk, chun, sizeof(chun));
}
}

View File

@ -158,6 +158,5 @@ textstartup int ttyraw(enum TtyRawFlags flags) {
} else {
rc = ttyraw_disable();
}
cancolor();
return rc;
}

View File

@ -9,6 +9,7 @@
#endif
#include "libc/calls/calls.h"
#include "libc/log/check.h"
#include "libc/log/color.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"

View File

@ -13,6 +13,7 @@
#include "libc/conv/conv.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/color.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"

View File

@ -26,7 +26,7 @@ int main(int argc, char *argv[]) {
*
* 1. gc() automates calling free() on return.
* 2. xasprintf("foo %s", "bar") is our version of "foo %s" % ("bar")
* 3. Demonstrates correct escaping for bourne shell cf. xaescapeshq()
* 3. Demonstrates correct escaping for bourne shell
*/
if (!fileexists(kProgram)) {
system(gc(xasprintf("%s '%s'", "make -j4",

View File

@ -620,12 +620,12 @@
#define octtobin(c) ((c) - '0')
#define scopy(s1, s2) ((void)strcpy(s2, s1))
/* #define TRACE(param) */
#define TRACE(param) \
do { \
printf("TRACE: "); \
printf param; \
} while (0)
#define TRACE(param)
/* #define TRACE(param) \ */
/* do { \ */
/* printf("TRACE: "); \ */
/* printf param; \ */
/* } while (0) */
#define TRACEV(param)
#define digit_val(c) ((c) - '0')
@ -634,8 +634,6 @@
#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
#define is_special(c) ((is_type + SYNBASE)[(signed char)(c)] & (ISSPECL | ISDIGIT))
/* #define likely(x) __builtin_expect(!!(x), 1) */
/* #define unlikely(x) __builtin_expect(!!(x), 0) */
#define uninitialized_var(x) x = x /* suppress uninitialized warning w/o code */
@ -643,9 +641,7 @@
* Shell variables.
*/
#define vifs varinit[0]
#define vmail (&vifs)[1]
#define vmpath (&vmail)[1]
#define vpath (&vmpath)[1]
#define vpath (&vifs)[1]
#define vps1 (&vpath)[1]
#define vps2 (&vps1)[1]
#define vps4 (&vps2)[1]
@ -1497,7 +1493,8 @@ enum token {
enum token_types { UNOP, BINOP, BUNOP, BBINOP, PAREN };
static struct t_op const ops[] = {{"-r", FILRD, UNOP},
static struct t_op const ops[] = {
{"-r", FILRD, UNOP},
{"-w", FILWR, UNOP},
{"-x", FILEX, UNOP},
{"-e", FILEXIST, UNOP},
@ -1536,7 +1533,8 @@ static struct t_op const ops[] = {{"-r", FILRD, UNOP},
{"-o", BOR, BBINOP},
{"(", LPAREN, PAREN},
{")", RPAREN, PAREN},
{0, 0, 0}};
{0, 0, 0},
};
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § the unbourne shell » text
@ -3644,7 +3642,7 @@ static int evalcommand(union node *cmd, int flags) {
}
/* Now locate the command. */
if (cmdentry.cmdtype != CMDBUILTIN || !(cmdentry.u.cmd->flags & BUILTIN_REGULAR)) {
path = unlikely(path != NULL) ? path : pathval();
path = unlikely(path != NULL) ? path : pathval(); /* wut */
find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
}
jp = NULL;
@ -4213,21 +4211,21 @@ static void hashcd(void) {
* Called with interrupts off.
*/
static void changepath(const char *newval) {
const char *new;
int idx;
int bltin;
new = newval;
const char *neu;
neu = newval;
idx = 0;
bltin = -1;
for (;;) {
if (*new == '%' && prefix(new + 1, "builtin")) {
if (*neu == '%' && prefix(neu + 1, "builtin")) {
bltin = idx;
break;
}
new = strchr(new, ':');
if (!new) break;
neu = strchr(neu, ':');
if (!neu) break;
idx++;
new ++;
neu++;
}
builtinloc = bltin;
clearcmdentry();
@ -9603,6 +9601,9 @@ static char *conv_escape(char *str, int *conv_ch) {
case 'f':
value = '\f';
break; /* form-feed */
case 'e':
value = '\e';
break; /* escape */
case 'n':
value = '\n';
break; /* newline */
@ -10787,6 +10788,7 @@ static int exitcmd(int argc, char **argv) {
*/
int main(int argc, char **argv) {
showcrashreports();
unsetenv("PS1");
char *shinit;
volatile int state;
struct jmploc jmploc;

View File

@ -111,7 +111,7 @@ int fchmod(int, uint32_t) nothrow;
int fchmodat(int, const char *, uint32_t, uint32_t);
int fchown(int, uint32_t, uint32_t);
int fchownat(int, const char *, uint32_t, uint32_t, uint32_t);
int fcntl();
int fcntl(int, int, ...);
int fdatasync(int);
int filecmp(const char *, const char *);
int flock(int, int);
@ -189,7 +189,7 @@ int uname(struct utsname *);
int unlink(const char *);
int unlink_s(const char **);
int unlinkat(int, const char *, int);
int vfork(void);
int vfork(void) returnstwice;
int wait(int *);
int wait3(int *, int, struct rusage *);
int wait4(int, int *, int, struct rusage *);
@ -242,7 +242,7 @@ int vdprintf(int, const char *, va_list) paramsnonnull();
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
void _init_onntconsoleevent(void);
void _init_onwincrash(void);
void _init_wincrash(void);
#define __SIGACTION(FN, SIG, ...) \
({ \
@ -260,14 +260,14 @@ void _init_onwincrash(void);
case SIGSEGV: \
case SIGABRT: \
case SIGFPE: \
YOINK(_init_onwincrash); \
YOINK(_init_wincrash); \
break; \
default: \
break; \
} \
} else { \
YOINK(_init_onntconsoleevent); \
YOINK(_init_onwincrash); \
YOINK(_init_wincrash); \
} \
} \
(FN)(SIG, __VA_ARGS__); \

View File

@ -24,16 +24,17 @@
#include "libc/sysv/errfuns.h"
textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
uint32_t flags;
if (!isfdkind(fd, kFdFile)) return ebadf();
switch (cmd) {
case F_GETFD:
return GetHandleInformation(g_fds.p[fd].handle, &arg) ? (arg ^ FD_CLOEXEC)
: -1;
if (!GetHandleInformation(g_fds.p[fd].handle, &flags)) return -1;
arg = (flags & FD_CLOEXEC) ^ FD_CLOEXEC;
return arg;
case F_SETFD:
return SetHandleInformation(g_fds.p[fd].handle, FD_CLOEXEC,
arg ^ FD_CLOEXEC)
? 0
: -1;
arg ^= FD_CLOEXEC;
if (!SetHandleInformation(g_fds.p[fd].handle, FD_CLOEXEC, arg)) return -1;
return 0;
default:
return 0; /* TODO(jart): Implement me. */
}

View File

@ -31,7 +31,12 @@
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int fcntl(int fd, int cmd, int arg) {
int fcntl(int fd, int cmd, ...) {
va_list va;
unsigned arg;
va_start(va, cmd);
arg = va_arg(va, unsigned);
va_end(va);
if (!IsWindows()) {
return fcntl$sysv(fd, cmd, arg);
} else {

View File

@ -1,40 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/calls/ntmagicpaths.h"
#include "libc/nexgen32e/tinystrcmp.h"
#include "libc/sysv/consts/o.h"
textwindows const char *(fixntmagicpath)(const char *path, unsigned flags) {
const struct NtMagicPaths *mp = &kNtMagicPaths;
asm("" : "+r"(mp));
if (path[0] != '/') return path;
if (tinystrcmp(path, mp->devtty) == 0) {
if ((flags & O_ACCMODE) == O_RDONLY) {
return mp->conin;
} else if ((flags & O_ACCMODE) == O_WRONLY) {
return mp->conout;
}
}
if (tinystrcmp(path, mp->devnull) == 0) return mp->nul;
if (tinystrcmp(path, mp->devstdin) == 0) return mp->conin;
if (tinystrcmp(path, mp->devstdout) == 0) return mp->conout;
return path;
}

View File

@ -261,15 +261,11 @@ void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden;
struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden;
bool32 ntsetprivilege(i64, const char16_t *, u32) hidden;
bool32 onntconsoleevent$nt(u32) hidden;
void onntalarm(void *, uint32_t, uint32_t) hidden;
void __winalarm(void *, uint32_t, uint32_t) hidden;
int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
i64 ntreturn(u32);
i64 winerr(void) nocallback privileged;
const char *__fixntmagicpath(const char *, unsigned) paramsnonnull() hidden;
int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16])
paramsnonnull() hidden;
#define mkntpath(PATH, PATH16) mkntpath2(PATH, -1u, PATH16)
#define mkntpath2(PATH, FLAGS, PATH16) \
({ \
@ -281,16 +277,6 @@ int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16])
Count; \
})
#define fixntmagicpath(PATH, FLAGS) \
({ \
const char *Path2; \
asm("call\tfixntmagicpath" \
: "=a"(Path2) \
: "D"(PATH), "S"(FLAGS), "m"((PATH)[0]) \
: "cc"); \
Path2; \
})
#undef sigset
#undef i32
#undef i64

View File

@ -17,15 +17,31 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/pushpop.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/internal.h"
#include "libc/conv/conv.h"
#include "libc/calls/ntmagicpaths.h"
#include "libc/nexgen32e/tinystrcmp.h"
#include "libc/str/str.h"
#include "libc/str/tpdecode.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
textwindows static const char *FixNtMagicPath(const char *path,
unsigned flags) {
const struct NtMagicPaths *mp = &kNtMagicPaths;
asm("" : "+r"(mp));
if (path[0] != '/') return path;
if (tinystrcmp(path, mp->devtty) == 0) {
if ((flags & O_ACCMODE) == O_RDONLY) {
return mp->conin;
} else if ((flags & O_ACCMODE) == O_WRONLY) {
return mp->conout;
}
}
if (tinystrcmp(path, mp->devnull) == 0) return mp->nul;
if (tinystrcmp(path, mp->devstdin) == 0) return mp->conin;
if (tinystrcmp(path, mp->devstdout) == 0) return mp->conout;
return path;
}
/**
* Copies path for Windows NT.
*
@ -33,13 +49,13 @@
* forward-slashes with backslashes; and (3) remapping several
* well-known paths (e.g. /dev/null NUL) for convenience.
*
* @param flags is used by open()
* @param path16 is shortened so caller can prefix, e.g. \\.\pipe\, and
* due to a plethora of special-cases throughout the Win32 API
* @param flags is used by open(), see fixntmagicpath2()
* @return short count excluding NUL on success, or -1 w/ errno
* @error ENAMETOOLONG
*/
forcealignargpointer textwindows int(mkntpath)(
forcealignargpointer textwindows int mkntpath(
const char *path, unsigned flags,
char16_t path16[hasatleast PATH_MAX - 16]) {
/*
@ -52,7 +68,7 @@ forcealignargpointer textwindows int(mkntpath)(
int rc;
wint_t wc;
size_t i, j;
path = fixntmagicpath(path, flags);
path = FixNtMagicPath(path, flags);
i = 0;
j = 0;
for (;;) {

View File

@ -55,7 +55,7 @@ static struct ItimerNt {
static uint32_t ItimerWorker(void *arg) {
do {
if (!WaitForSingleObject(g_itimernt.ith, -1)) {
onntalarm(NULL, 0, 0);
__winalarm(NULL, 0, 0);
}
} while (g_itimernt.ith && g_itimernt.tid == GetCurrentThreadId());
return 0;

View File

@ -23,5 +23,5 @@
onntconsoleevent$nt:
ezlea onntconsoleevent,ax
jmp nt2sysv
jmp __nt2sysv
.endfn onntconsoleevent$nt,globl,hidden

View File

@ -21,7 +21,7 @@
.text.windows
.source __FILE__
onwincrash$nt:
ezlea onwincrash,ax
jmp nt2sysv
.endfn onwincrash$nt,globl
__wincrash$nt:
ezlea __wincrash,ax
jmp __nt2sysv
.endfn __wincrash$nt,globl

View File

@ -21,7 +21,7 @@
.text.windows
.source __FILE__
onntalarm$nt:
ezlea onntalarm,ax
jmp nt2sysv
.endfn onntalarm$nt,globl,hidden
__winalarm$nt:
ezlea __winalarm,ax
jmp __nt2sysv
.endfn __winalarm$nt,globl,hidden

View File

@ -22,7 +22,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
void onntalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue,
void __winalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue,
uint32_t dwTimerHighValue) {
siginfo_t info;
memset(&info, 0, sizeof(info));

View File

@ -27,7 +27,7 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/sig.h"
textwindows unsigned onwincrash(struct NtExceptionPointers *ep) {
textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
int sig;
struct Goodies {
ucontext_t ctx;

View File

@ -20,8 +20,8 @@
#include "libc/macros.h"
.source __FILE__
.init.start 300,_init_onwincrash
.init.start 300,_init_wincrash
pushpop 1,%rcx
ezlea onwincrash$nt,dx
ezlea __wincrash$nt,dx
ntcall __imp_AddVectoredExceptionHandler
.init.end 300,_init_onwincrash,globl,hidden
.init.end 300,_init_wincrash,globl,hidden

View File

@ -54,9 +54,8 @@ _start: test %rdi,%rdi
mov %rdi,%rcx # auxv
mov %ebx,%edi
call _executive
9: .endfn _start,weak,hidden
ud2
9: ud2
.endfn _start,weak,hidden
/ Macintosh userspace program entrypoint.
/

View File

@ -35,7 +35,7 @@
/**
* Resolves address for internet name.
*
* @param node is either an ip string or a utf-8 hostname
* @param name is either an ip string or a utf-8 hostname
* @param service is the port number as a string
* @param hints may be passed to specialize behavior (optional)
* @param res receives a pointer that must be freed with freeaddrinfo(),

View File

@ -6,137 +6,137 @@
* @see libc/sysv/consts.sh for numbers
*/
#define EPERM EPERM /* operation not permitted */
#define ENOENT ENOENT /* no such file or directory */
#define ESRCH ESRCH /* no such process */
#define EINTR EINTR /* interrupted system call */
#define EIO EIO /* input/output error */
#define ENXIO ENXIO /* no such device or address */
#define E2BIG E2BIG /* argument list too long */
#define ENOEXEC ENOEXEC /* exec format error */
#define EBADF EBADF /* bad file descriptor */
#define ECHILD ECHILD /* no child processes */
#define EAGAIN EAGAIN /* resource temporarily unavailable */
#define ENOMEM ENOMEM /* not enough space */
#define EACCES EACCES /* permission denied */
#define EFAULT EFAULT /* bad address */
#define ENOTBLK ENOTBLK /* block device required */
#define EBUSY EBUSY /* device or resource busy */
#define EEXIST EEXIST /* file exists */
#define EXDEV EXDEV /* improper link */
#define ENODEV ENODEV /* no such device */
#define ENOTDIR ENOTDIR /* not a directory */
#define EISDIR EISDIR /* is a directory */
#define EINVAL EINVAL /* invalid argument */
#define ENFILE ENFILE /* too many open files in system */
#define EMFILE EMFILE /* too many open files */
#define ENOTTY ENOTTY /* inappropriate I/O control op */
#define ETXTBSY ETXTBSY /* text file busy */
#define EFBIG EFBIG /* file too large */
#define ENOSPC ENOSPC /* no space left on device */
#define ESPIPE ESPIPE /* invalid seek */
#define EROFS EROFS /* read-only filesystem */
#define EMLINK EMLINK /* too many links */
#define EPIPE EPIPE /* broken pipe */
#define EDOM EDOM /* argument out of function domain */
#define ERANGE ERANGE /* result too large */
#define EDEADLK EDEADLK /* resource deadlock avoided */
#define ENAMETOOLONG ENAMETOOLONG /* filename too long */
#define ENOLCK ENOLCK /* no locks available */
#define ENOSYS ENOSYS /* system call not implemented */
#define ENOTEMPTY ENOTEMPTY /* directory not empty */
#define ELOOP ELOOP /* too many levels of symbolic links */
#define ENOMSG ENOMSG /* no message of the desired type */
#define EIDRM EIDRM /* identifier removed */
#define ECHRNG ECHRNG /* channel number out of range */
#define EL2NSYNC EL2NSYNC /* level 2 not synchronized */
#define EL3HLT EL3HLT /* level 3 halted */
#define EL3RST EL3RST /* level 3 halted */
#define ELNRNG ELNRNG /* link number out of range */
#define EUNATCH EUNATCH /* protocol driver not attached */
#define ENOCSI ENOCSI /* no csi structure available */
#define EL2HLT EL2HLT /* level 2 halted */
#define EBADE EBADE /* invalid exchange */
#define EBADR EBADR /* invalid request descriptor */
#define EXFULL EXFULL /* exchange full */
#define ENOANO ENOANO /* no anode */
#define EBADRQC EBADRQC /* invalid request code */
#define EBADSLT EBADSLT /* invalid slot */
#define ENOSTR ENOSTR /* no string */
#define ENODATA ENODATA /* no data */
#define ETIME ETIME /* timer expired */
#define ENOSR ENOSR /* out of streams resources */
#define ENONET ENONET /* no network */
#define ENOPKG ENOPKG /* package not installed */
#define EREMOTE EREMOTE /* object is remote */
#define ENOLINK ENOLINK /* link severed */
#define EADV EADV /* todo */
#define ESRMNT ESRMNT /* todo */
#define ECOMM ECOMM /* communication error on send */
#define EPROTO EPROTO /* protocol error */
#define EMULTIHOP EMULTIHOP /* multihop attempted */
#define EDOTDOT EDOTDOT /* todo */
#define EBADMSG EBADMSG /* bad message */
#define EOVERFLOW EOVERFLOW /* value too large for type */
#define ENOTUNIQ ENOTUNIQ /* name not unique on network */
#define EBADFD EBADFD /* fd in bad *state* (cf. EBADF) */
#define EREMCHG EREMCHG /* remote address changed */
#define ELIBACC ELIBACC /* cannot access dso */
#define ELIBBAD ELIBBAD /* corrupted shared library */
#define ELIBSCN ELIBSCN /* a.out section corrupted */
#define ELIBMAX ELIBMAX /* too many shared libraries */
#define ELIBEXEC ELIBEXEC /* cannot exec a dso directly */
#define EILSEQ EILSEQ /* invalid wide character */
#define ERESTART ERESTART /* please restart syscall */
#define ESTRPIPE ESTRPIPE /* streams pipe error */
#define EUSERS EUSERS /* too many users */
#define ENOTSOCK ENOTSOCK /* not a socket */
#define EDESTADDRREQ EDESTADDRREQ /* dest address needed */
#define EMSGSIZE EMSGSIZE /* message too long */
#define EPROTOTYPE EPROTOTYPE /* protocol wrong for socket */
#define ENOPROTOOPT ENOPROTOOPT /* protocol not available */
#define EPROTONOSUPPORT EPROTONOSUPPORT /* protocol not supported */
#define ESOCKTNOSUPPORT ESOCKTNOSUPPORT /* socket type not supported */
#define EOPNOTSUPP EOPNOTSUPP /* operation not supported on socket */
#define EPFNOSUPPORT EPFNOSUPPORT /* protocol family not supported */
#define EAFNOSUPPORT EAFNOSUPPORT /* address family not supported */
#define EADDRINUSE EADDRINUSE /* address already in use */
#define EADDRNOTAVAIL EADDRNOTAVAIL /* address not available */
#define ENETDOWN ENETDOWN /* network is down */
#define ENETUNREACH ENETUNREACH /* network unreachable */
#define ENETRESET ENETRESET /* connection aborted by network */
#define ECONNABORTED ECONNABORTED /* connection aborted */
#define ECONNRESET ECONNRESET /* connection reset */
#define ENOBUFS ENOBUFS /* no buffer space available */
#define EISCONN EISCONN /* socket is connected */
#define ENOTCONN ENOTCONN /* the socket is not connected */
#define ESHUTDOWN ESHUTDOWN /* no send after endpoint shutdown */
#define ETOOMANYREFS ETOOMANYREFS /* too many refs */
#define ETIMEDOUT ETIMEDOUT /* connection timed out */
#define ECONNREFUSED ECONNREFUSED /* connection refused */
#define EHOSTDOWN EHOSTDOWN /* host is down */
#define EHOSTUNREACH EHOSTUNREACH /* host is unreachable */
#define EALREADY EALREADY /* connection already in progress */
#define EINPROGRESS EINPROGRESS /* operation in progress */
#define ESTALE ESTALE /* stale file handle */
#define EUCLEAN EUCLEAN /* structure needs cleaning */
#define ENOTNAM ENOTNAM /* todo */
#define ENAVAIL ENAVAIL /* todo */
#define EISNAM EISNAM /* is a named type file */
#define EREMOTEIO EREMOTEIO /* remote i/o error */
#define EDQUOT EDQUOT /* disk quota exceeded */
#define ENOMEDIUM ENOMEDIUM /* no medium found */
#define EMEDIUMTYPE EMEDIUMTYPE /* wrong medium type */
#define ECANCELED ECANCELED /* operation canceled */
#define ENOKEY ENOKEY /* required key not available */
#define EKEYEXPIRED EKEYEXPIRED /* key has expired */
#define EKEYREVOKED EKEYREVOKED /* key has been revoked */
#define EKEYREJECTED EKEYREJECTED /* key was rejected by service */
#define EOWNERDEAD EOWNERDEAD /* owner died */
#define ENOTRECOVERABLE ENOTRECOVERABLE /* state not recoverable */
#define ERFKILL ERFKILL /* can't op b/c RF-kill */
#define EHWPOISON EHWPOISON /* mempage has h/w error */
#define EWOULDBLOCK EAGAIN /* poll fd and try again */
#define EPERM EPERM // operation not permitted
#define ENOENT ENOENT // no such file or directory
#define ESRCH ESRCH // no such process
#define EINTR EINTR // interrupted system call
#define EIO EIO // input/output error
#define ENXIO ENXIO // no such device or address
#define E2BIG E2BIG // argument list too long
#define ENOEXEC ENOEXEC // exec format error
#define EBADF EBADF // bad file descriptor
#define ECHILD ECHILD // no child processes
#define EAGAIN EAGAIN // resource temporarily unavailable
#define ENOMEM ENOMEM // not enough space
#define EACCES EACCES // permission denied
#define EFAULT EFAULT // bad address
#define ENOTBLK ENOTBLK // block device required
#define EBUSY EBUSY // device or resource busy
#define EEXIST EEXIST // file exists
#define EXDEV EXDEV // improper link
#define ENODEV ENODEV // no such device
#define ENOTDIR ENOTDIR // not a directory
#define EISDIR EISDIR // is a directory
#define EINVAL EINVAL // invalid argument
#define ENFILE ENFILE // too many open files in system
#define EMFILE EMFILE // too many open files
#define ENOTTY ENOTTY // inappropriate I/O control op
#define ETXTBSY ETXTBSY // text file busy
#define EFBIG EFBIG // file too large
#define ENOSPC ENOSPC // no space left on device
#define ESPIPE ESPIPE // invalid seek
#define EROFS EROFS // read-only filesystem
#define EMLINK EMLINK // too many links
#define EPIPE EPIPE // broken pipe
#define EDOM EDOM // argument out of function domain
#define ERANGE ERANGE // result too large
#define EDEADLK EDEADLK // resource deadlock avoided
#define ENAMETOOLONG ENAMETOOLONG // filename too long
#define ENOLCK ENOLCK // no locks available
#define ENOSYS ENOSYS // system call not implemented
#define ENOTEMPTY ENOTEMPTY // directory not empty
#define ELOOP ELOOP // too many levels of symbolic links
#define ENOMSG ENOMSG // no message of the desired type
#define EIDRM EIDRM // identifier removed
#define ECHRNG ECHRNG // channel number out of range
#define EL2NSYNC EL2NSYNC // level 2 not synchronized
#define EL3HLT EL3HLT // level 3 halted
#define EL3RST EL3RST // level 3 halted
#define ELNRNG ELNRNG // link number out of range
#define EUNATCH EUNATCH // protocol driver not attached
#define ENOCSI ENOCSI // no csi structure available
#define EL2HLT EL2HLT // level 2 halted
#define EBADE EBADE // invalid exchange
#define EBADR EBADR // invalid request descriptor
#define EXFULL EXFULL // exchange full
#define ENOANO ENOANO // no anode
#define EBADRQC EBADRQC // invalid request code
#define EBADSLT EBADSLT // invalid slot
#define ENOSTR ENOSTR // no string
#define ENODATA ENODATA // no data
#define ETIME ETIME // timer expired
#define ENOSR ENOSR // out of streams resources
#define ENONET ENONET // no network
#define ENOPKG ENOPKG // package not installed
#define EREMOTE EREMOTE // object is remote
#define ENOLINK ENOLINK // link severed
#define EADV EADV // todo
#define ESRMNT ESRMNT // todo
#define ECOMM ECOMM // communication error on send
#define EPROTO EPROTO // protocol error
#define EMULTIHOP EMULTIHOP // multihop attempted
#define EDOTDOT EDOTDOT // todo
#define EBADMSG EBADMSG // bad message
#define EOVERFLOW EOVERFLOW // value too large for type
#define ENOTUNIQ ENOTUNIQ // name not unique on network
#define EBADFD EBADFD // fd in bad *state* (cf. EBADF)
#define EREMCHG EREMCHG // remote address changed
#define ELIBACC ELIBACC // cannot access dso
#define ELIBBAD ELIBBAD // corrupted shared library
#define ELIBSCN ELIBSCN // a.out section corrupted
#define ELIBMAX ELIBMAX // too many shared libraries
#define ELIBEXEC ELIBEXEC // cannot exec a dso directly
#define EILSEQ EILSEQ // invalid wide character
#define ERESTART ERESTART // please restart syscall
#define ESTRPIPE ESTRPIPE // streams pipe error
#define EUSERS EUSERS // too many users
#define ENOTSOCK ENOTSOCK // not a socket
#define EDESTADDRREQ EDESTADDRREQ // dest address needed
#define EMSGSIZE EMSGSIZE // message too long
#define EPROTOTYPE EPROTOTYPE // protocol wrong for socket
#define ENOPROTOOPT ENOPROTOOPT // protocol not available
#define EPROTONOSUPPORT EPROTONOSUPPORT // protocol not supported
#define ESOCKTNOSUPPORT ESOCKTNOSUPPORT // socket type not supported
#define EOPNOTSUPP EOPNOTSUPP // operation not supported on socket
#define EPFNOSUPPORT EPFNOSUPPORT // protocol family not supported
#define EAFNOSUPPORT EAFNOSUPPORT // address family not supported
#define EADDRINUSE EADDRINUSE // address already in use
#define EADDRNOTAVAIL EADDRNOTAVAIL // address not available
#define ENETDOWN ENETDOWN // network is down
#define ENETUNREACH ENETUNREACH // network unreachable
#define ENETRESET ENETRESET // connection aborted by network
#define ECONNABORTED ECONNABORTED // connection aborted
#define ECONNRESET ECONNRESET // connection reset
#define ENOBUFS ENOBUFS // no buffer space available
#define EISCONN EISCONN // socket is connected
#define ENOTCONN ENOTCONN // the socket is not connected
#define ESHUTDOWN ESHUTDOWN // no send after endpoint shutdown
#define ETOOMANYREFS ETOOMANYREFS // too many refs
#define ETIMEDOUT ETIMEDOUT // connection timed out
#define ECONNREFUSED ECONNREFUSED // connection refused
#define EHOSTDOWN EHOSTDOWN // host is down
#define EHOSTUNREACH EHOSTUNREACH // host is unreachable
#define EALREADY EALREADY // connection already in progress
#define EINPROGRESS EINPROGRESS // operation in progress
#define ESTALE ESTALE // stale file handle
#define EUCLEAN EUCLEAN // structure needs cleaning
#define ENOTNAM ENOTNAM // todo
#define ENAVAIL ENAVAIL // todo
#define EISNAM EISNAM // is a named type file
#define EREMOTEIO EREMOTEIO // remote i/o error
#define EDQUOT EDQUOT // disk quota exceeded
#define ENOMEDIUM ENOMEDIUM // no medium found
#define EMEDIUMTYPE EMEDIUMTYPE // wrong medium type
#define ECANCELED ECANCELED // operation canceled
#define ENOKEY ENOKEY // required key not available
#define EKEYEXPIRED EKEYEXPIRED // key has expired
#define EKEYREVOKED EKEYREVOKED // key has been revoked
#define EKEYREJECTED EKEYREJECTED // key was rejected by service
#define EOWNERDEAD EOWNERDEAD // owner died
#define ENOTRECOVERABLE ENOTRECOVERABLE // state not recoverable
#define ERFKILL ERFKILL // can't op b/c RF-kill
#define EHWPOISON EHWPOISON // mempage has h/w error
#define EWOULDBLOCK EAGAIN // poll fd and try again
#define ENOTSUP ENOTSUP
#if !(__ASSEMBLER__ + __LINKER__ + 0)

View File

@ -1,47 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/escape/escape.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
/**
* Internal function aspecting escaping ops with allocating behavior.
* @see aescapesh(), aescapec()
*/
int aescape(char **escaped, size_t size, const char *unescaped, unsigned length,
int impl(char *escaped, unsigned size, const char *unescaped,
unsigned length)) {
int wrote;
char *p2;
if ((p2 = realloc(*escaped, size)) != NULL) {
*escaped = p2;
if ((wrote = impl(*escaped, size, unescaped, length)) != -1) {
if ((unsigned)wrote <= size - 1) {
return wrote;
} else {
assert(__builtin_return_address(0) != aescape);
return aescape(escaped, wrote + 1, unescaped, length, impl);
}
}
}
free_s(escaped);
return -1;
}

View File

@ -1,64 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/macros.h"
#include "libc/str/str.h"
// TODO(jart): implement me
/**
* Decodes backslash escape sequences in-place.
*
* We support the C standard definitions, and the gotchas that entails:
*
* \newline noop for multi-line str
* \' \" \? \\ ← we try hard to avoid \?
* \a \b \f \n \r \t \v \e \e is A++ GNU extension
* \ octal-digit base-8 literal encoding
* \ octal-digit octal-digit octal: super dependable
* \ octal-digit octal-digit octal-digit longstanding DEC legacy
* \x[0-9A-Fa-f]+ base16 literal encoding
* \u[0-9A-Fa-f]{4} UNICODEs
* \U[0-9A-Fa-f]{8} (astral planes) UNICODEs: Astral Planes
*
* @param n is # bytes in p
* @param p is byte array of string literal content
* @return new byte size of s, or -i to indicate first error at s[i]
* @note we do not check for NUL terminator on input
* @note array is zero-filled if shortened
* @see cescapec(), strlen()
*/
int cunescape(size_t n, char p[n]) {
unsigned char t[32];
unsigned i, j, m, tc, tn, mask;
for (m = n, i = 0; i < n; i += j) {
tc = sizeof(t);
tn = MIN(m - i, tc);
memset(t, 0, tc);
memcpy(t, p + i, tn);
for (mask = j = 0; j < tc; ++j) {
if (p[j] == '\\') mask |= 1u << j;
}
if (j < ARRAYLEN(t)) {
memcpy(p + i, t, tn);
}
}
return m;
}

View File

@ -1,22 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_
#define COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § escaping
*/
unsigned cescapec(int);
int escapec(char *, unsigned, const char *, unsigned)
paramsnonnull((3)) nothrow nocallback;
int escapesh(char *, unsigned, const char *, unsigned) paramsnonnull((3));
bool escapedos(char16_t *, unsigned, const char16_t *, unsigned);
int aescapec(char **, const char *, unsigned) paramsnonnull();
int aescapesh(char **, const char *, unsigned) paramsnonnull();
int aescape(char **, size_t, const char *, unsigned,
int (*)(char *, unsigned, const char *, unsigned)) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_ */

View File

@ -1,57 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += LIBC_ESCAPE
LIBC_ESCAPE_ARTIFACTS += LIBC_ESCAPE_A
LIBC_ESCAPE = $(LIBC_ESCAPE_A_DEPS) $(LIBC_ESCAPE_A)
LIBC_ESCAPE_A = o/$(MODE)/libc/escape/escape.a
LIBC_ESCAPE_A_FILES := $(wildcard libc/escape/*)
LIBC_ESCAPE_A_HDRS = $(filter %.h,$(LIBC_ESCAPE_A_FILES))
LIBC_ESCAPE_A_SRCS_S = $(filter %.S,$(LIBC_ESCAPE_A_FILES))
LIBC_ESCAPE_A_SRCS_C = $(filter %.c,$(LIBC_ESCAPE_A_FILES))
LIBC_ESCAPE_A_SRCS = \
$(LIBC_ESCAPE_A_SRCS_S) \
$(LIBC_ESCAPE_A_SRCS_C)
LIBC_ESCAPE_A_OBJS = \
$(LIBC_ESCAPE_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_ESCAPE_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_ESCAPE_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_ESCAPE_A_CHECKS = \
$(LIBC_ESCAPE_A).pkg \
$(LIBC_ESCAPE_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_ESCAPE_A_DIRECTDEPS = \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV
LIBC_ESCAPE_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_ESCAPE_A_DIRECTDEPS),$($(x))))
$(LIBC_ESCAPE_A): \
libc/escape/ \
$(LIBC_ESCAPE_A).pkg \
$(LIBC_ESCAPE_A_OBJS)
$(LIBC_ESCAPE_A).pkg: \
$(LIBC_ESCAPE_A_OBJS) \
$(foreach x,$(LIBC_ESCAPE_A_DIRECTDEPS),$($(x)_A).pkg)
LIBC_ESCAPE_LIBS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)))
LIBC_ESCAPE_SRCS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_SRCS))
LIBC_ESCAPE_HDRS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_HDRS))
LIBC_ESCAPE_BINS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_BINS))
LIBC_ESCAPE_CHECKS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_CHECKS))
LIBC_ESCAPE_OBJS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_OBJS))
LIBC_ESCAPE_TESTS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_TESTS))
$(LIBC_ESCAPE_OBJS): $(BUILD_FILES) libc/escape/escape.mk
.PHONY: o/$(MODE)/libc/escape
o/$(MODE)/libc/escape: $(LIBC_ESCAPE_CHECKS)

View File

@ -1,73 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/dce.h"
#include "libc/escape/escape.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
#define SHQUOTE_PUTCHAR(c) \
do { \
if (buf != NULL && j < size - 1) { \
buf[j] = (c); \
} \
j++; \
} while (0)
/**
* Quotes memory for inclusion in single-quoted SystemV string literals.
*
* The outer quotation marks are *not* added.
*
* @param buf is the output area, which can't overlap and, no matter
* what, a NUL-terminator will always be placed in the buffer at
* an appropriate place, provided buf!=NULL && size!=0
* @param size is the byte-length of the output area
* @param s is the data, which may have NUL characters
* @param l is the byte-length of s
* @return number of characters written, excluding NUL terminator; or,
* if the output buffer wasn't passed, or was too short, then the
* number of characters that *would* have been written is returned;
* since that's how the snprintf() API works; and never < 0
* @see xaescapesh() for an easier api
*/
int escapesh(char *buf, unsigned size, const char *s, unsigned l) {
assert(size <= INT_MAX && l <= INT_MAX);
if (!IsTrustworthy() && l >= INT_MAX) abort();
unsigned j = 0;
for (unsigned i = 0; i < l; ++i) {
if (s[i] != '\'') {
SHQUOTE_PUTCHAR(s[i]);
} else {
const char *const s2 = "'\"'\"'";
unsigned l2 = 5;
for (unsigned k = 0; k < l2; ++k) {
SHQUOTE_PUTCHAR(s2[k]);
}
}
}
if (buf && size) {
buf[min(j, size - 1)] = '\0';
}
return j;
}

View File

@ -39,7 +39,6 @@
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/conv/conv.h"
#include "libc/escape/escape.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/paland.inc"
#include "libc/fmt/palandprintf.h"
@ -58,7 +57,7 @@ static int ppatoi(const char **str) {
}
/**
* Implements {,v}{,s{,n},{,{,x}as},f,d}printf state machine.
* Implements {,v}{,s{,n},{,{,x}as},f,d}printf domain-specific language.
*
* Type Specifiers
*

View File

@ -18,7 +18,6 @@
02110-1301 USA
*/
#include "libc/bits/weaken.h"
#include "libc/escape/escape.h"
#include "libc/fmt/paland.inc"
#include "libc/fmt/palandprintf.h"
#include "libc/nexgen32e/tinystrlen.h"

View File

@ -35,7 +35,7 @@ const char *geterrname(int code) {
n = &EXFULL + 1 - e;
for (i = 0; i < n; ++i) {
if (code == e[i]) {
return indexdoublenulstring(kErrnoNames, i);
return IndexDoubleNulString(kErrnoNames, i);
}
}
return NULL;

View File

@ -22,9 +22,11 @@
#include "libc/conv/itoa.h"
#include "libc/log/asan.h"
#include "libc/log/backtrace.h"
#include "libc/log/log.h"
#include "libc/mem/hook/hook.h"
#include "libc/runtime/directmap.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
@ -144,16 +146,23 @@ static const char *__asan_describe_access_poison(int c) {
static noreturn void __asan_die(const char *msg, size_t size) {
write(STDERR_FILENO, msg, size);
PrintBacktraceUsingSymbols(STDERR_FILENO, __builtin_frame_address(0),
GetSymbolTable());
DebugBreak();
_Exit(66);
die();
}
static char *__asan_report_start(char *p) {
bool ansi;
const char *term;
term = getenv("TERM");
ansi = !term || strcmp(term, "dumb") != 0;
if (ansi) p = stpcpy(p, "\r\e[J\e[1;91m");
p = stpcpy(p, "asan error");
if (ansi) p = stpcpy(p, "\e[0m");
return stpcpy(p, ": ");
}
static noreturn void __asan_report_deallocate_fault(void *addr, int c) {
char *p, ibuf[21], buf[256];
p = buf;
p = stpcpy(p, "error: ");
p = __asan_report_start(buf);
p = stpcpy(p, __asan_dscribe_free_poison(c));
p = stpcpy(p, " ");
p = mempcpy(p, ibuf, int64toarray_radix10(c, ibuf));
@ -166,8 +175,7 @@ static noreturn void __asan_report_deallocate_fault(void *addr, int c) {
static noreturn void __asan_report_memory_fault(uint8_t *addr, int size,
const char *kind) {
char *p, ibuf[21], buf[256];
p = buf;
p = stpcpy(p, "error: ");
p = __asan_report_start(buf);
p = stpcpy(p, __asan_describe_access_poison(*(char *)SHADOW((intptr_t)addr)));
p = stpcpy(p, " ");
p = mempcpy(p, ibuf, uint64toarray_radix10(size, ibuf));

View File

@ -19,17 +19,19 @@
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/fileno.h"
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
@ -46,12 +48,12 @@ relegated void __check_fail(const char *suffix, const char *opstr,
va_list va;
char sufbuf[8];
int lasterr = errno;
startfatal(file, line);
__start_fatal(file, line);
if (!memccpy(sufbuf, suffix, '\0', sizeof(sufbuf))) strcpy(sufbuf, "?");
strtoupper(sufbuf);
(fprintf)(stderr,
(dprintf)(STDERR_FILENO,
"check failed\r\n"
"\tCHECK_%s(%s, %s);\r\n"
"\t\t → %#lx (%s)\r\n"
@ -59,27 +61,26 @@ relegated void __check_fail(const char *suffix, const char *opstr,
sufbuf, wantstr, gotstr, want, wantstr, opstr, got, gotstr);
if (!isempty(fmt)) {
fputc('\t', stderr);
(dprintf)(STDERR_FILENO, "\t");
va_start(va, fmt);
(vfprintf)(stderr, fmt, va);
(vdprintf)(STDERR_FILENO, fmt, va);
va_end(va);
fputs("\r\n", stderr);
(dprintf)(STDERR_FILENO, "\r\n");
}
(fprintf)(stderr, "\t%s\r\n\t%s%s%s%s\r\n", strerror(lasterr), SUBTLE,
(dprintf)(STDERR_FILENO, "\t%s\r\n\t%s%s%s%s\r\n", strerror(lasterr), SUBTLE,
getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET);
for (i = 1; i < g_argc; ++i) {
(fprintf)(stderr, "\t\t%s%s\r\n", g_argv[i], i < g_argc - 1 ? " \\" : "");
(dprintf)(STDERR_FILENO, "\t\t%s%s\r\n", g_argv[i],
i < g_argc - 1 ? " \\" : "");
}
if (!IsTiny() && lasterr == ENOMEM) {
(fprintf)(stderr, "\r\n");
fflush(stderr);
PrintMemoryIntervals(fileno(stderr), &_mmi);
(dprintf)(STDERR_FILENO, "\r\n");
PrintMemoryIntervals(STDERR_FILENO, &_mmi);
}
fflush(stderr);
die();
unreachable;
}

View File

@ -38,7 +38,7 @@ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
char bx[21];
int lasterr;
lasterr = errno;
startfatal_ndebug();
__start_fatal_ndebug();
__print_string("check failed: 0x");
__print(bx, uint64toarray_radix16(want, bx));
__print_string(" ");

20
libc/log/color.h 100644
View File

@ -0,0 +1,20 @@
#ifndef COSMOPOLITAN_LIBC_LOG_COLOR_H_
#define COSMOPOLITAN_LIBC_LOG_COLOR_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define CLS (cancolor() ? "\r\e[J" : "")
#define RED (cancolor() ? "\e[30;101m" : "")
#define GREEN (cancolor() ? "\e[32m" : "")
#define UNBOLD (cancolor() ? "\e[22m" : "")
#define RED2 (cancolor() ? "\e[91;1m" : "")
#define BLUE1 (cancolor() ? "\e[94;49m" : "")
#define BLUE2 (cancolor() ? "\e[34m" : "")
#define RESET (cancolor() ? "\e[0m" : "")
#define SUBTLE (cancolor() ? "\e[35m" : "")
bool cancolor(void) nothrow nocallback nosideeffect;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_LOG_COLOR_H_ */

View File

@ -1,33 +1,17 @@
#ifndef COSMOPOLITAN_LIBC_LOG_INTERNAL_H_
#define COSMOPOLITAN_LIBC_LOG_INTERNAL_H_
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/log/log.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/ucontext.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define RED (cancolor() ? "\x1b[30;101m" : "")
#define UNBOLD (cancolor() ? "\x1b[22m" : "")
#define RED2 (cancolor() ? "\x1b[91;1m" : "")
#define BLUE1 (cancolor() ? "\x1b[94;49m" : "")
#define BLUE2 (cancolor() ? "\x1b[34m" : "")
#define RESET (cancolor() ? "\x1b[0m" : "")
#define SUBTLE (cancolor() ? "\x1b[35m" : "")
enum NtExceptionHandlerActions;
struct NtExceptionPointers;
extern int kCrashSigs[8];
extern struct sigaction g_oldcrashacts[8];
extern const char kCrashSigNames[8][5] aligned(1);
extern const char kGregNames[17][4] aligned(1);
extern const char kGregOrder[17] aligned(1);
void startfatal(const char *, int) hidden;
void startfatal_ndebug(void) hidden;
void oncrash(int, struct siginfo *, struct ucontext *) relegated;
enum NtExceptionHandlerActions wincrash$nt(
const struct NtExceptionPointers *) relegated;
void __start_fatal(const char *, int) hidden;
void __start_fatal_ndebug(void) hidden;
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View File

@ -39,7 +39,6 @@ void meminfo(int); /* shows malloc statistics &c. */
void memsummary(int); /* light version of same thing */
uint16_t getttycols(uint16_t);
int getttysize(int, struct winsize *) paramsnonnull();
bool cancolor(void) nothrow nocallback;
bool isterminalinarticulate(void) nosideeffect;
char *commandvenv(const char *, const char *) nodiscard;
const char *GetAddr2linePath(void);

View File

@ -32,7 +32,6 @@ LIBC_LOG_A_DIRECTDEPS = \
LIBC_CALLS_HEFTY \
LIBC_CONV \
LIBC_ELF \
LIBC_ESCAPE \
LIBC_FMT \
LIBC_TINYMATH \
LIBC_NEXGEN32E \

View File

@ -24,6 +24,7 @@
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/backtrace.h"
#include "libc/log/color.h"
#include "libc/log/gdb.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
@ -49,18 +50,18 @@ STATIC_YOINK("stoa");
struct siginfo;
const char kGregOrder[17] aligned(1) = {
static const char kGregOrder[17] aligned(1) = {
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
};
const char kGregNames[17][4] aligned(1) = {
static const char kGregNames[17][4] aligned(1) = {
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "RDI",
"RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP",
};
const char kGodHatesFlags[12] aligned(1) = "CVPRAKZSTIDO";
const char kCrashSigNames[8][5] aligned(1) = {"QUIT", "FPE", "ILL", "SEGV",
"TRAP", "ABRT", "BUS"};
static const char kGodHatesFlags[12] aligned(1) = "CVPRAKZSTIDO";
static const char kCrashSigNames[8][5] aligned(1) = {
"QUIT", "FPE", "ILL", "SEGV", "TRAP", "ABRT", "BUS"};
int kCrashSigs[8];
struct sigaction g_oldcrashacts[8];
@ -191,7 +192,7 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
*
* This function never returns, except for traps w/ human supervision.
*/
relegated void oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
intptr_t rip;
int gdbpid, err;
static bool once;

View File

@ -24,69 +24,69 @@
/ caused the crash, particularly in the GDB GUI. They're coded
/ into an array to pinch pennies on code size registering them.
kOncrashThunks:
__oncrash_thunks:
.org 11*0
oncrash_sigquit:
__oncrash_sigquit:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigquit,globl
.endfn __oncrash_sigquit,globl
.org 11*1
oncrash_sigfpe:
__oncrash_sigfpe:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigfpe,globl
.endfn __oncrash_sigfpe,globl
.org 11*2
oncrash_sigill:
__oncrash_sigill:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigill,globl
.endfn __oncrash_sigill,globl
.org 11*3
oncrash_sigsegv:
__oncrash_sigsegv:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigsegv,globl
.endfn __oncrash_sigsegv,globl
.org 11*4
oncrash_sigtrap:
__oncrash_sigtrap:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigtrap,globl
.endfn __oncrash_sigtrap,globl
.org 11*5
oncrash_sigabrt:
__oncrash_sigabrt:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigabrt,globl
.endfn __oncrash_sigabrt,globl
.org 11*6
oncrash_sigbus:
__oncrash_sigbus:
push %rbp
mov %rsp,%rbp
call oncrash
call __oncrash
pop %rbp
ret
.endfn oncrash_sigbus,globl
.endfn __oncrash_sigbus,globl
.endobj kOncrashThunks,globl
.endobj __oncrash_thunks,globl

View File

@ -19,6 +19,7 @@
*/
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"

View File

@ -34,7 +34,7 @@
STATIC_YOINK("die");
STATIC_YOINK("__ubsan_abort");
extern const unsigned char kOncrashThunks[7][11];
extern const unsigned char __oncrash_thunks[7][11];
/**
* Installs crash signal handlers.
@ -73,7 +73,7 @@ void showcrashreports(void) {
}
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i]) {
sa.sa_sigaction = (sigaction_f)kOncrashThunks[i];
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]);
}
}

View File

@ -17,18 +17,19 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/fileno.h"
/**
* Prints initial part of fatal message.
*
* @note this is support code for __check_fail(), __assert_fail(), etc.
* @see startfatal_ndebug()
* @see __start_fatal_ndebug()
*/
relegated void startfatal(const char *file, int line) {
fflush(stdout);
fprintf(stderr, "%s%s%s:%s:%d:%s%s: ", RED, "error", BLUE1, file, line,
program_invocation_short_name, RESET);
relegated void __start_fatal(const char *file, int line) {
dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1,
file, line, program_invocation_short_name, RESET);
}

View File

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/color.h"
#include "libc/runtime/missioncritical.h"
#include "libc/stdio/stdio.h"
@ -24,11 +25,10 @@
* Prints initial part of fatal message.
*
* @note this is support code for __check_fail(), __assert_fail(), etc.
* @see startfatal()
* @see __start_fatal()
*/
relegated void startfatal_ndebug(void) {
fflush(stdout);
fflush(stderr);
relegated void __start_fatal_ndebug(void) {
if (cancolor()) __print_string("\r\e[J");
__print_string("error:");
__print_string(program_invocation_name);
__print_string(": ");

View File

@ -55,7 +55,7 @@ void __ubsan_abort(const struct UbsanSourceLocation *loc,
}
g_runstate |= RUNSTATE_BROKEN;
if (IsDebuggerPresent(false)) DebugBreak();
startfatal(loc->file, loc->line);
__start_fatal(loc->file, loc->line);
fprintf(stderr, "%s\r\n", description);
die();
unreachable;
@ -74,7 +74,7 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *type_mismatch,
uintptr_t pointer) {
struct UbsanSourceLocation *loc = &type_mismatch->location;
const char *description;
const char *kind = indexdoublenulstring(kUbsanTypeCheckKinds,
const char *kind = IndexDoubleNulString(kUbsanTypeCheckKinds,
type_mismatch->type_check_kind);
if (pointer == 0) {
description = "null pointer access";

View File

@ -18,6 +18,7 @@
02110-1301 USA
*/
#include "libc/log/bsd.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"

View File

@ -18,6 +18,7 @@
02110-1301 USA
*/
#include "libc/log/bsd.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"

View File

@ -32,6 +32,7 @@
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
@ -113,8 +114,8 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
va_end(va);
fputs("\r\n", f);
if (level == kLogFatal) {
startfatal(file, line);
(fprintf)(stderr, "fatal error see logfile\r\n");
__start_fatal(file, line);
(dprintf)(STDERR_FILENO, "fatal error see logfile\r\n");
die();
unreachable;
}

View File

@ -18,6 +18,7 @@
02110-1301 USA
*/
#include "libc/log/bsd.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"

View File

@ -18,6 +18,7 @@
02110-1301 USA
*/
#include "libc/log/bsd.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"

View File

@ -17,15 +17,15 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/runtime/gc.h"
#include "libc/x/x.h"
#include "libc/mem/mem.h"
#include "third_party/dlmalloc/dlmalloc.h"
/**
* Single-quotes string for bourne shell.
* Releases freed memory back to system.
*
* @return escaped string which must make its way to free()
* @param pad can specify how many bytes of memory to leave available
* @return 1 if it actually released any memory, else 0
*/
char *xaescapeshq(const char *unescaped) {
return xasprintf("'%s'", gc(xaescape(unescaped, escapesh)));
int malloc_trim(size_t pad) {
return dlmalloc_trim(pad);
}

View File

@ -29,7 +29,8 @@
/ @param %rcx,%rdx,%r8,%r9
/ @return %rax,%xmm0
/ @note this is so much slower than sysv2nt()
nt2sysv:push %rbp
__nt2sysv:
push %rbp
mov %rsp,%rbp
.profilable
sub $0x100,%rsp
@ -53,5 +54,5 @@ nt2sysv:push %rbp
pop %rbx
leave
ret
.endfn nt2sysv,globl,hidden
.endfn __nt2sysv,globl,hidden
.source __FILE__

View File

@ -105,15 +105,6 @@ strnlen_s:
.leafepilogue
.endfn strnlen_s,globl
/ Returns length of NUL-terminated string.
/
/ @param rdi is non-null NUL-terminated string pointer
/ @return rax is the number of bytes, excluding the NUL
/ @asyncsignalsafe
strlen: or $-1,%rsi
/ 𝑠𝑙𝑖𝑑𝑒
.endfn strlen,globl
/ Returns length of NUL-terminated memory, with limit.
/
/ @param rdi is non-null memory
@ -129,7 +120,7 @@ strnlen:.leafprologue
.endfn strnlen,globl
/ Swiss army knife of string character scanning.
/ Sixteen fast functions in one.
/ Fourteen fast functions in one.
/
/ @param rdi is non-null string memory
/ @param rsi is max number of bytes to consider

View File

@ -29,6 +29,7 @@ LIBC_RAND_A_DIRECTDEPS = \
LIBC_TINYMATH \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \
LIBC_STR \
LIBC_SYSV_CALLS \
LIBC_SYSV

View File

@ -25,18 +25,18 @@
.source __FILE__
.init.start 400,_init_g_stderr
lea g_stderr(%rip),%rax
ezlea g_stderr,ax
push $_IOLBF
pop (%rax) # f.fd
push STDERR_FILENO
pop 12(%rax)
mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode
lea g_stderr_buf(%rip),%rcx
ezlea g_stderr_buf,cx
mov %rcx,24(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size
lea fwritebuf(%rip),%rcx
lea fswritebuf(%rip),%rdx
ezlea fwritebuf,cx
ezlea fswritebuf,dx
testb IsMetal()
cmove %rcx,%rdx
mov %rdx,48(%rax) # f.writer

View File

@ -25,14 +25,14 @@
.source __FILE__
.init.start 400,_init_g_stdin
lea g_stdin(%rip),%rax
ezlea g_stdin,ax
mov O_RDONLY,%edx
mov %edx,4(%rax) # f.iomode
lea g_stdin_buf(%rip),%rcx
ezlea g_stdin_buf,cx
mov %rcx,24(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size
lea freadbuf(%rip),%rcx
lea fsreadbuf(%rip),%rdx
ezlea freadbuf,cx
ezlea fsreadbuf,dx
testb IsMetal()
cmove %rcx,%rdx
mov %rdx,40(%rax) # f.reader

View File

@ -25,16 +25,16 @@
.source __FILE__
.init.start 400,_init_g_stdout
lea g_stdout(%rip),%rax
ezlea g_stdout,ax
push STDOUT_FILENO
pop 12(%rax) # f.fd
mov O_WRONLY,%edx
mov %edx,4(%rax) # f.iomode
lea g_stdout_buf(%rip),%rcx
ezlea g_stdout_buf,cx
mov %rcx,24(%rax) # f.buf
movl $BUFSIZ,32(%rax) # f.size
lea fwritebuf(%rip),%rcx
lea fswritebuf(%rip),%rdx
ezlea fwritebuf,cx
ezlea fswritebuf,dx
testb IsMetal()
cmovz %rcx,%rdx
mov %rdx,48(%rax) # f.writer

View File

@ -29,7 +29,6 @@ LIBC_STDIO_A_DIRECTDEPS = \
LIBC_BITS \
LIBC_CALLS \
LIBC_CONV \
LIBC_ESCAPE \
LIBC_FMT \
LIBC_MEM \
LIBC_NEXGEN32E \

View File

@ -22,7 +22,6 @@
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/escape/escape.h"
#include "libc/mem/mem.h"
#include "libc/nt/accounting.h"
#include "libc/nt/enum/startf.h"

View File

@ -25,11 +25,10 @@
* @param s is a NUL-terminated string
* @param suffix is also NUL-terminated
*/
bool(endswith)(const char *s, const char *suffix) {
size_t l1, l2;
if (s == suffix) return true;
l1 = strlen(s);
l2 = strnlen(suffix, l1);
if (l2 > l1) return false;
return memcmp(s + (l1 - l2) * sizeof(char), suffix, l2 * sizeof(char)) == 0;
bool endswith(const char *s, const char *suffix) {
size_t n, m;
n = strlen(s);
m = strlen(suffix);
if (m > n) return false;
return memcmp(s + n - m, suffix, m) == 0;
}

View File

@ -17,7 +17,6 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/str/str.h"
static textwindows bool shouldescapedos(const char16_t c) {

View File

@ -20,11 +20,11 @@
#include "libc/str/str.h"
int getkvlin(const char *name, const char *const unsorted[]) {
unsigned i, n;
if (unsorted) {
unsigned namelen = strlen(name);
for (int i = 0; unsorted[i]; ++i) {
if (strncmp(unsorted[i], name, namelen) == 0 &&
unsorted[i][namelen] == '=') {
n = strlen(name);
for (i = 0; unsorted[i]; ++i) {
if (strncmp(unsorted[i], name, n) == 0 && unsorted[i][n] == '=') {
return i;
}
}

View File

@ -19,11 +19,14 @@
*/
#include "libc/str/str.h"
const char *indexdoublenulstring(const char *p, unsigned i) {
const char *IndexDoubleNulString(const char *s, unsigned i) {
size_t n;
while (i--) {
const char *p2 = rawmemchr(p, '\0');
if (p2 == p) return NULL;
p = p2 + 1;
if ((n = strlen(s))) {
s += n + 1;
} else {
return NULL;
}
return p;
}
return s;
}

View File

@ -26,27 +26,12 @@
hidden extern const uint32_t kSha256Tab[64];
extern const struct TpEncode {
uint8_t mark;
uint8_t len;
} kTpDecoderRing[32];
forceinline struct TpEncode UseTpDecoderRing(wint_t c) {
unsigned msb;
if (c) {
asm("bsr\t%1,%0" : "=r"(msb) : "rm"(c) : "cc");
} else {
msb = 0;
}
return kTpDecoderRing[msb];
}
nodebuginfo forceinline bool32 ismoar(wint_t c) {
return (c & 0b11000000) == 0b11000000;
return (c & 0300) == 0300;
}
nodebuginfo forceinline bool32 iscont(wint_t c) {
return (c & 0b11000000) == 0b10000000;
return (c & 0300) == 0200;
}
char *strstr$sse42(const char *, const char *) strlenesque hidden;

View File

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
int isascii(int c) {
return 0x00 <= c && c <= 0x7F;

View File

@ -1,64 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/**
* Checks if memory address contains non-plain text.
*
* @param data points to memory that's interpreted as char
* @param size is usually strlen(data) and provided by caller
* @return NULL if plain text, or pointer to first non-text datum
* @type char may be 6/7/8/16/32/64-bit signed/unsigned single/multi
* @author Justine Alexandra Roberts Tunney <jtunney@gmail.com>
* @see ASA X3.4, ISO/IEC 646, ITU T.50, ANSI X3.64-1979
* @perf 27gBps on i7-6700 w/ -O3 -mavx2
* @cost 143 bytes of code w/ -Os
*/
void *isnotplaintext(const void *data, size_t size) {
/*
* ASCII, EBCDIC, UNICODE, ISO IR-67, etc. all agree upon the
* encoding of the NUL, SOH, STX, and ETX characters due to a
* longstanding human tradition of using them for the purpose
* of delimiting text from non-text, b/c fixed width integers
* makes their presence in binary formats nearly unavoidable.
*/
#define isnotplain(C) (0 <= (C) && (C) < 4)
char no;
unsigned i;
const char *p, *pe;
if (CHAR_BIT > 6) {
p = (const char *)data;
pe = (const char *)(p + size);
for (; ((intptr_t)p & 31) && p < pe; ++p) {
if (isnotplain(*p)) return p;
}
for (; p + 64 < pe; p += 64) {
no = 0;
for (i = 0; i < 64; ++i) {
no |= isnotplain(p[i]);
}
if (no & 1) break;
}
for (; p < pe; ++p) {
if (isnotplain(*p)) return p;
}
}
return 0;
#undef isnotplain
}

View File

@ -1,56 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.source __FILE__
/ Thompson-Pike Decoder Ring.
/
/ The IA-32 BSR instruction can be used to turn a 32-bit
/ number into an index for this table.
/
/ @see libc/str/internal.h
.rodata
.align 2
kTpDecoderRing:
.rept 7 # MSB6 (0x7F)
.byte 0b00000000,1 # mark,len
/ 0b11000000 # mask
.endr
.rept 4 # MSB10 (0x7FF)
.byte 0b11000000,2 # mark,len
/ 0b11100000 # mask
.endr
.rept 5 # MSB15 (0xFFFF)
.byte 0b11100000,3 # mark,len
/ 0b11110000 # mask
.endr
.rept 5 # MSB20 (0x1FFFFF)
.byte 0b11110000,4 # mark,len
/ 0b11111000 # mask
.endr
.rept 5 # MSB25 (0x3FFFFFF)
.byte 0b11111000,5 # mark,len
/ 0b11111100 # mask
.endr
.rept 6 # MSB31 (0xffffffff)
.byte 0b11111100,6 # mark,len
.endr
.endobj kTpDecoderRing,globl,hidden
.previous

View File

@ -21,11 +21,11 @@
/**
* Returns true if s has prefix.
*
* @param s is a NUL-terminated string
* @param prefix is also NUL-terminated
*/
bool(startswith)(const char *s, const char *prefix) {
if (s == prefix) return true;
bool startswith(const char *s, const char *prefix) {
for (;;) {
if (!*prefix) return true;
if (!*s) return false;

View File

@ -17,20 +17,45 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/intrin/pcmpeqb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/str/str.h"
/**
* Copies string and advances destination pointer.
* Copies bytes from 𝑠 to 𝑑 until a NUL is encountered.
*
* @param 𝑑 is destination memory
* @param 𝑠 is a NUL-terminated string
* @note 𝑑 and 𝑠 can't overlap
* @return pointer to nul byte
* @see strcpy(), memccpy()
* @asyncsignalsafe
*/
char *stpcpy(char *dst, const char *src) {
char c;
for (;;) {
c = *src;
*dst = c;
if (!c) break;
++src;
++dst;
char *stpcpy(char *d, const char *s) {
size_t i;
uint8_t v1[16], v2[16], vz[16];
i = 0;
while (((uintptr_t)(s + i) & 15)) {
if (!(d[i] = s[i])) {
return d + i;
}
++i;
}
for (;;) {
memset(vz, 0, 16);
memcpy(v1, s + i, 16);
pcmpeqb(v2, v1, vz);
if (!pmovmskb(v2)) {
memcpy(d + i, v1, 16);
i += 16;
} else {
break;
}
}
for (;;) {
if (!(d[i] = s[i])) {
return d + i;
}
++i;
}
return dst;
}

View File

@ -30,8 +30,7 @@ int tolower(int);
int ispunct(int);
int toupper(int);
int hextoint(int);
void *isnotplaintext(const void *, size_t) nothrow nocallback nosideeffect;
int cescapec(int);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § characters » thompson-pike encoding
@ -173,7 +172,7 @@ bool wcsstartswith(const wchar_t *, const wchar_t *) strlenesque;
bool endswith(const char *, const char *) strlenesque;
bool endswith16(const char16_t *, const char16_t *) strlenesque;
bool wcsendswith(const wchar_t *, const wchar_t *) strlenesque;
const char *indexdoublenulstring(const char *, unsigned) strlenesque;
const char *IndexDoubleNulString(const char *, unsigned) strlenesque;
int getkvlin(const char *, const char *const[]);
wchar_t *wmemset(wchar_t *, wchar_t, size_t) memcpyesque;
char16_t *memset16(char16_t *, char16_t, size_t) memcpyesque;
@ -194,6 +193,8 @@ char *chomp(char *);
char16_t *chomp16(char16_t *);
wchar_t *wchomp(wchar_t *);
bool escapedos(char16_t *, unsigned, const char16_t *, unsigned);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § strings » multibyte
*/
@ -341,27 +342,6 @@ extern int (*const hook$wcsncmp)(const wchar_t *, const wchar_t *, size_t);
: strncasecmp16, default \
: strncasecmp)(s1, s2, n)
#define startswith(s, c) \
_Generic(*(s), wchar_t \
: wcsstartswith, char16_t \
: startswith16, default \
: startswith)(s, c)
#define endswith(s, c) \
_Generic(*(s), wchar_t \
: wcsendswith, char16_t \
: endswith16, default \
: endswith)(s, c)
#define strclen(s) \
_Generic(*(s), wchar_t : wcslen, char16_t : strclen16, default : strclen)(s)
#define strnclen(s, n) \
_Generic(*(s), wchar_t \
: wcslen, char16_t \
: strnclen16, default \
: strnclen)(s, n)
#define chomp(s) \
_Generic(*(s), wchar_t : wchomp, char16_t : chomp16, default : chomp)(s)

View File

@ -28,6 +28,7 @@ LIBC_STR_A_CHECKS = \
$(LIBC_STR_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_STR_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_STUBS \
LIBC_NEXGEN32E

View File

@ -17,23 +17,23 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/internal.h"
#include "libc/str/str.h"
/**
* Returns number of characters in UTF-8 string.
*/
size_t(strclen)(const char *s) { return strnclen(s, -1ull); }
size_t strclen(const char *s) {
return strnclen(s, -1);
}
noinline size_t(strnclen)(const char *s, size_t n) {
const unsigned char *p = (const unsigned char *)s;
size_t l = 0;
noinline size_t strnclen(const char *s, size_t n) {
size_t r = 0;
if (n) {
while (*p && n && iscont(*p)) ++p, --n;
while (*p) {
if (!iscont(*p++)) l++;
while (n && *s && (*s & 0300) == 0200) ++s, --n;
while (*s) {
if ((*s++ & 0300) != 0200) r++;
if (!--n) break;
}
}
return l;
return r;
}

View File

@ -17,7 +17,10 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/intrin/pcmpeqb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/limits.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/str/str.h"
/**
@ -31,6 +34,30 @@
* @asyncsignalsafe
*/
char *strcpy(char *d, const char *s) {
memccpy(d, s, '\0', SIZE_MAX);
size_t i;
uint8_t v1[16], v2[16], vz[16];
i = 0;
while (((uintptr_t)(s + i) & 15)) {
if (!(d[i] = s[i])) {
return d;
}
++i;
}
for (;;) {
memset(vz, 0, 16);
memcpy(v1, s + i, 16);
pcmpeqb(v2, v1, vz);
if (!pmovmskb(v2)) {
memcpy(d + i, v1, 16);
i += 16;
} else {
break;
}
}
for (;;) {
if (!(d[i] = s[i])) {
return d;
}
++i;
}
}

View File

@ -17,22 +17,34 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/assert.h"
#include "libc/intrin/pcmpeqb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
/**
* Aspects 2-arity memory op with allocating behavior.
* Used to turn FOO() into aFOO() without too much duplicated code.
* Returns length of NUL-terminated string.
*
* @param s is non-null NUL-terminated string pointer
* @return number of bytes (excluding NUL)
* @asyncsignalsafe
*/
char *xaescape(const char *unescaped,
int impl(char *escaped, unsigned size, const char *unescaped,
unsigned length)) {
char *escaped = NULL;
if (aescape(&escaped, 32, unescaped, strlen(unescaped), impl) == -1) {
xdie();
size_t strlen(const char *s) {
const char *p;
unsigned k, m;
uint8_t v1[16], vz[16];
k = (uintptr_t)s & 15;
p = (const char *)((uintptr_t)s & -16);
memset(vz, 0, 16);
memcpy(v1, p, 16);
pcmpeqb(v1, v1, vz);
m = pmovmskb(v1) >> k << k;
while (!m) {
p += 16;
memcpy(v1, p, 16);
pcmpeqb(v1, v1, vz);
m = pmovmskb(v1);
}
return escaped;
return p + bsf(m) - s;
}

View File

@ -2,10 +2,10 @@
#define COSMOPOLITAN_LIBC_STR_THOMPIKE_H_
#include "libc/nexgen32e/bsr.h"
#define ThomPikeCont(x) (((x)&0b11000000) == 0b10000000)
#define ThomPikeCont(x) (((x)&0300) == 0200)
#define ThomPikeByte(x) ((x) & (((1 << ThomPikeMsb(x)) - 1) | 3))
#define ThomPikeLen(x) (7 - ThomPikeMsb(x))
#define ThomPikeMsb(x) (((x)&0xff) < 252 ? bsr(~(x)&0xff) : 1)
#define ThomPikeMerge(x, y) ((x) << 6 | (y)&0b00111111)
#define ThomPikeMerge(x, y) ((x) << 6 | (y)&077)
#endif /* COSMOPOLITAN_LIBC_STR_THOMPIKE_H_ */

View File

@ -29,7 +29,7 @@
/ @return is in %rax, %xmm0, or %st
/ @note GCC 4.8+ and Clang can avoid this indirection
/ @note thunk that jumps here must setup frame
/ @note this is so much faster than nt2sysv()
/ @note this is so much faster than __nt2sysv()
__sysv2nt14:
pushq 72(%rbp)
pushq 64(%rbp)

View File

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.inc"
.scall vfork 0x004200422042003a globl

View File

@ -293,14 +293,14 @@ syscon spawn POSIX_SPAWN_SETSCHEDPARAM 0x10 0 4 4 0
syscon spawn POSIX_SPAWN_SETSCHEDULER 0x20 0 8 8 0
syscon spawn POSIX_SPAWN_USEVFORK 0x40 0 0 0 0
# mprotect(), etc.
# mmap(), mprotect(), etc.
# digital restrictions management for the people
#
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
syscon mprot PROT_NONE 0 0 0 0 0 # unix consensus (nt needs special business logic here)
syscon mprot PROT_READ 1 1 1 1 1 # unix consensus
syscon mprot PROT_WRITE 2 2 2 2 2 # unix consensus
syscon mprot PROT_EXEC 4 4 4 4 4 # unix consensus
syscon mprot PROT_NONE 0 0 0 0 0 # mmap, mprotect, unix consensus (nt needs special business logic here)
syscon mprot PROT_READ 1 1 1 1 1 # mmap, mprotect, unix consensus
syscon mprot PROT_WRITE 2 2 2 2 2 # mmap, mprotect, unix consensus
syscon mprot PROT_EXEC 4 4 4 4 4 # mmap, mprotect, unix consensus
syscon mprot PROT_GROWSDOWN 0x01000000 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap() (todo: what was 0x01000000 on nt)
syscon mprot PROT_GROWSUP 0x02000000 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap()
@ -2798,6 +2798,7 @@ syscon nr __NR_access 0x0015 0x2000021 0x0021 0x0021 -1
syscon nr __NR_sched_yield 0x0018 0x100003c 0x014b 0x012a -1
syscon nr __NR_sendfile 0x0028 0x2000151 0x0189 0xffff -1
syscon nr __NR_fork 0x0039 0x2000002 0x0002 0x0002 -1
syscon nr __NR_vfork 0x003a 0x2000042 0x0042 0x0042 -1
syscon nr __NR_gettimeofday 0x0060 0x2000074 0x0074 0x0043 -1
syscon nr __NR_arch_prctl 0x009e 0x000ffff 0x00a5 0x00a5 -1
syscon nr __NR_gettid 0x00ba 0x200011e 0xffff 0xffff -1

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon mmap MAP_FIXED 16 16 16 16 16
.syscon mmap MAP_FIXED 0x10 0x10 0x10 0x10 0x10

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon mmap MAP_NONBLOCK 0x010000 0 0 0 0
.syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0

View File

@ -0,0 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon nr __NR_vfork 0x003a 0x2000042 0x0042 0x0042 -1

View File

@ -91,7 +91,7 @@ scall 'socketpair$sysv' 0x0087008720870035 globl hidden
scall 'setsockopt$sysv' 0x0069006920690036 globl hidden
scall 'getsockopt$sysv' 0x0076007620760037 globl hidden
scall 'fork$sysv' 0x0002000220020039 globl hidden
scall vfork 0x004200422042003a globl
#scall vfork 0x004200422042003a globl # needs to be called via vfork.S
scall posix_spawn 0xffffffff20f4ffff globl hidden # TODO: put in spawnve()
scall 'execve$sysv' 0x003b003b203b003b globl hidden
scall 'wait4$sysv' 0x000b00072007003d globl hidden

View File

@ -107,18 +107,18 @@ systemfive.linux:
systemfive.error:
neg %eax
/ 𝑠𝑙𝑖𝑑𝑒
.endfn systemfive.error
.endfn systemfive.error,globl,hidden
systemfive.errno:
mov %eax,errno(%rip)
push $-1
pop %rax
stc
ret
.endfn systemfive.errno
.endfn systemfive.errno,globl,hidden
systemfive.enosys:
mov ENOSYS(%rip),%eax
jmp systemfive.errno
.endfn systemfive.enosys
.endfn systemfive.enosys,globl,hidden
systemfive.openbsd:
shr $48,%rax
jmp systemfive.bsd

View File

@ -34,6 +34,7 @@ LIBC_SYSV_A_FILES := \
libc/sysv/restorert.S \
libc/sysv/syscall.S \
libc/sysv/systemfive.S \
libc/sysv/vfork.S \
$(wildcard libc/sysv/stubs/*) \
$(wildcard libc/sysv/consts/*) \
$(wildcard libc/sysv/errfuns/*)
@ -86,6 +87,7 @@ LIBC_SYSV_CALLS_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_SYSV_CALLS_A_DIRECTDEPS),$($(x))))
$(LIBC_SYSV_CALLS_A): \
libc/sysv/calls/ \
$(LIBC_SYSV_CALLS_A).pkg \
$(LIBC_SYSV_CALLS_A_OBJS)

View File

@ -1,5 +1,5 @@
/*-*- 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
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -17,12 +17,32 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/dce.h"
#include "libc/macros.h"
/**
* Delegates to escapesh(), allocating as much memory as needed.
* @return bytes written excluding NUL, or -1 on alloc error or overflow
*/
int aescapesh(char **escaped, const char *unescaped, unsigned length) {
return aescape(escaped, 32, unescaped, length, escapesh);
}
/ Forks process without copying page tables.
/
/ This is the same as fork() except it's optimized for the case
/ where the caller invokes exec() immediately afterwards.
/
/ @return pid of child process or 0 if forked process
/ @returnstwice
vfork: mov __NR_vfork(%rip),%eax
cmp $-1,%eax
je systemfive.enosys
pop %rsi
testb IsBsd()
jnz vfork.bsd
syscall
push %rsi
cmp $-4095,%rax
jae systemfive.error
ret
.endfn vfork,globl
vfork.bsd:
syscall
push %rsi
jc systemfive.errno
ret
.endfn vfork.bsd

View File

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/math.h"

View File

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/color.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/math.h"

View File

@ -17,8 +17,6 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/struct/timespec.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/time/time.h"

View File

@ -17,52 +17,65 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/limits.h"
#include "libc/sysv/errfuns.h"
#include "libc/macros.h"
#include "libc/str/thompike.h"
#include "libc/unicode/unicode.h"
/**
* Escapes memory for inclusion in C string literals (or Python, etc.)
* Returns monospace display width of UTF-8 string.
*
* The outer quotation marks are *not* added.
* - Control codes are discounted
* - ANSI escape sequences are discounted
* - East asian glyphs, emoji, etc. count as two
*
* @param buf is the output area, which can't overlap and, no matter
* what, a NUL-terminator will always be placed in the buffer at
* an appropriate place, provided buf!=NULL && size!=0
* @param size is the byte-length of the output area
* @param s is the data, which may have NUL characters
* @param l is the byte-length of s or -1 if s is NUL-terminated
* @return number of characters written, excluding NUL terminator; or,
* if the output buffer wasn't passed, or was too short, then the
* number of characters that *would* have been written is returned;
* since that's how the snprintf() API works; or -1 on overflow
* @see xaescapec() for an easier api
* @param s is NUL-terminated string
* @param n is max bytes to consider
* @return monospace display width
*/
int escapec(char *buf, unsigned size, const char *s, unsigned l) {
if (l >= INT_MAX) return eoverflow();
unsigned i, j = 0;
for (i = 0; i < l; ++i) {
unsigned t = cescapec(s[i]);
if (t) {
while (t) {
if (j < size) {
buf[j] = (unsigned char)t;
t >>= 8;
int strnwidth(const char *s, size_t n) {
wint_t c, w;
unsigned l, r;
enum { kAscii, kUtf8, kEsc, kCsi } t;
for (w = r = t = l = 0; n--;) {
if ((c = *s++ & 0xff)) {
switch (t) {
case kAscii:
if (0x20 <= c && c <= 0x7E || c == '\t') {
++l;
} else if (c == 033) {
t = kEsc;
} else if (c >= 0300) {
t = kUtf8;
w = ThomPikeByte(c);
r = ThomPikeLen(c) - 1;
}
j++;
break;
case kUtf8:
if (ThomPikeCont(c)) {
w = ThomPikeMerge(w, c);
if (--r) break;
}
l += MAX(0, wcwidth(w));
t = kAscii;
break;
case kEsc:
if (c == '[') {
t = kCsi;
} else if (!(040 <= c && c < 060)) {
t = kAscii;
}
break;
case kCsi:
if (!(060 <= c && c < 0100)) {
t = kAscii;
}
break;
default:
unreachable;
}
} else {
if (l == -1) {
break;
}
}
}
if (buf && size) {
if (j < size) {
buf[j] = '\0';
} else {
buf[size - 1] = '\0';
}
}
return j;
return l;
}

View File

@ -17,56 +17,18 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/limits.h"
#include "libc/str/internal.h"
#include "libc/str/str.h"
#include "libc/str/tpdecode.h"
#include "libc/unicode/unicode.h"
#define kOneTrueTabWidth 8
/**
* Returns monospace display width in UTF-8 string.
* Returns monospace display width of UTF-8 string.
*
* - Control codes are discounted
* - ANSI escape sequences are discounted
* - East asian glyphs, emoji, etc. count as two
*
* @param s is NUL-terminated string
* @return monospace display width
*/
int(strwidth)(const char *s) {
return strnwidth(s, SIZE_MAX);
}
int(strnwidth)(const char *s, size_t n) {
/* TODO(jart): Fix this function. */
size_t l;
wint_t wc;
const unsigned char *p, *pe;
l = 0;
if (n) {
p = (const unsigned char *)s;
pe = (const unsigned char *)(n == SIZE_MAX ? INTPTR_MAX : (intptr_t)s + n);
for (;;) {
while (p < pe && iscont(*p)) p++;
if (p == pe || !*p) break;
if (*p == L'\t') {
if (l & (kOneTrueTabWidth - 1)) {
l += kOneTrueTabWidth - (l & (kOneTrueTabWidth - 1));
} else {
l += kOneTrueTabWidth;
}
++p;
} else if (*p == L'\e') {
while (++p < pe && *p) {
if (*p == '[' || *p == ';' || isdigit(*p)) {
continue;
} else {
++p;
break;
}
}
} else {
p += abs(tpdecode((const char *)p, &wc));
l += max(0, wcwidth(wc));
}
}
}
return l;
int strwidth(const char *s) {
return strnwidth(s, -1);
}

View File

@ -3,19 +3,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § characters » unicode
*/
extern const uint8_t kEastAsianWidth[];
extern const uint32_t kEastAsianWidthBits;
extern const uint8_t kCombiningChars[];
extern const uint32_t kCombiningCharsBits;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § strings » multibyte » unicode
*/
int wcwidth(wchar_t) pureconst;
int wcswidth(const wchar_t *) strlenesque;
int wcsnwidth(const wchar_t *, size_t) strlenesque;
@ -24,26 +11,6 @@ int strnwidth(const char *, size_t) strlenesque;
int strwidth16(const char16_t *) strlenesque;
int strnwidth16(const char16_t *, size_t) strlenesque;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § unicode » generic typing
*/
#if __STDC_VERSION__ + 0 >= 201112
#define strwidth(s) \
_Generic(*(s), wchar_t \
: wcswidth, char16_t \
: strwidth16, default \
: strwidth)(s)
#define strnwidth(s, n) \
_Generic(*(s), wchar_t \
: wcswidth, char16_t \
: strnwidth16, default \
: strnwidth)(s, n)
#endif /* C11 */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_UNICODE_UNICODE_H_ */

View File

@ -19,6 +19,11 @@
*/
#include "libc/unicode/unicode.h"
extern const uint8_t kEastAsianWidth[];
extern const uint32_t kEastAsianWidthBits;
extern const uint8_t kCombiningChars[];
extern const uint32_t kCombiningCharsBits;
/**
* Returns cell width of monospace character.
*/

View File

@ -68,11 +68,6 @@ char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL;
char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL;
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
char *xinet_ntop(int, const void *) _XPNN _XMAL;
char *xaescapec(const char *) _XPNN _XMAL;
char *xaescapesh(const char *) _XPNN _XMAL;
char *xaescapeshq(const char *) _XPNN _XMAL;
char *xaescape(const char *, int (*)(char *, unsigned, const char *,
unsigned)) _XPNN hidden _XMAL;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § eXtended apis » time

View File

@ -35,7 +35,6 @@ LIBC_X_A_CHECKS = \
LIBC_X_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_ESCAPE \
LIBC_FMT \
LIBC_MEM \
LIBC_NEXGEN32E \

View File

@ -1,31 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/x/x.h"
/**
* Delegates NUL-terminated string to escapec() or dies.
*
* The surrounding quotes are *not* included. Death hapens only on
* allocation error or int32 overflow, which are extremely unlikely.
*
* @return escaped string which must make its way to free()
*/
char *xaescapec(const char *unescaped) { return xaescape(unescaped, escapec); }

View File

@ -1,34 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/escape/escape.h"
#include "libc/x/x.h"
/**
* Delegates NUL-terminated string to escapesh() or dies.
*
* The surrounding single quotes are *not* included. Death hapens only
* on allocation error or int32 overflow.
*
* @return escaped string which must make its way to free()
* @see xaescapeshq() which adds quotes
*/
char *xaescapesh(const char *unescaped) {
return xaescape(unescaped, escapesh);
}

View File

@ -38,6 +38,7 @@ NET_HTTP_A_DIRECTDEPS = \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_TIME \

Some files were not shown because too many files have changed in this diff Show More