mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 03:08:31 +00:00
Make terminal ui binaries work well everywhere
Here's some screenshots of an emulator tui program that was compiled on Linux, then scp'd it to Windows, Mac, and FreeBSD. https://justine.storage.googleapis.com/blinkenlights-cmdexe.png https://justine.storage.googleapis.com/blinkenlights-imac.png https://justine.storage.googleapis.com/blinkenlights-freebsd.png https://justine.storage.googleapis.com/blinkenlights-lisp.png How is this even possible that we have a nontrivial ui binary that just works on Mac, Windows, Linux, and BSD? Surely a first ever achievement. Fixed many bugs. Bootstrapped John McCarthy's metacircular evaluator on bare metal in half the size of Altair BASIC (about 2.5kb) and ran it in emulator for fun and profit.
This commit is contained in:
parent
680daf1210
commit
9e3e985ae5
276 changed files with 7026 additions and 3790 deletions
|
@ -25,9 +25,6 @@
|
|||
|
||||
/ Terminates process, ignoring destructors and atexit() handlers.
|
||||
/
|
||||
/ Normally exit() or quick_exit() is better. This won't even flush
|
||||
/ stdio streams. Sometimes that makes sense, like after fork().
|
||||
/
|
||||
/ @param edi is exit code ∈ [0,256)
|
||||
/ @note _exit() is same thing
|
||||
/ @asyncsignalsafe
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* Frees symbol table.
|
||||
* @return 0 on success or -1 on system error
|
||||
*/
|
||||
int closesymboltable(struct SymbolTable **table) {
|
||||
int CloseSymbolTable(struct SymbolTable **table) {
|
||||
int rc;
|
||||
struct SymbolTable *t;
|
||||
rc = 0;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/memory.h"
|
||||
|
|
|
@ -57,42 +57,14 @@ _executive:
|
|||
ud2
|
||||
|
||||
#ifdef __PG__
|
||||
/ Enables plaintext function tracing if --ftrace flag passed.
|
||||
/
|
||||
/ The --ftrace CLI arg is removed before main() is called. This
|
||||
/ code is intended for diagnostic purposes and assumes binaries
|
||||
/ are trustworthy and stack isn't corrupted. Logging plain text
|
||||
/ allows program structure to easily be visualized and hotspots
|
||||
/ identified w/ sed | sort | uniq -c | sort. A compressed trace
|
||||
/ can be made by appending --ftrace 2>&1 | gzip -4 >trace.gz to
|
||||
/ the CLI arguments. Have fun.
|
||||
/
|
||||
/ @see libc/runtime/ftrace.greg.c
|
||||
/ @see libc/crt/crt.S
|
||||
.init.start 800,_init_ftrace
|
||||
push %rdi
|
||||
push %rsi
|
||||
xor %edx,%edx
|
||||
loadstr "--ftrace",di
|
||||
xor %ecx,%ecx
|
||||
0: inc %ecx
|
||||
mov (%r13,%rcx,8),%rsi
|
||||
test %edx,%edx
|
||||
jz 1f
|
||||
mov %rsi,-8(%r13,%rcx,8)
|
||||
1: test %rsi,%rsi
|
||||
jz 2f
|
||||
test %edx,%edx
|
||||
jnz 0b
|
||||
call tinystrcmp
|
||||
test %eax,%eax
|
||||
setz %dl
|
||||
jmp 0b
|
||||
2: sub %rdx,%r12
|
||||
test %edx,%edx
|
||||
jz 2f
|
||||
mov %r12d,%edi
|
||||
mov %r13,%rsi
|
||||
call ftrace_init
|
||||
2: pop %rsi
|
||||
mov %eax,%r12d
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
.init.end 800,_init_ftrace
|
||||
#endif /* -pg */
|
||||
#endif
|
||||
|
|
|
@ -28,25 +28,25 @@ struct FindComBinary {
|
|||
char buf[PATH_MAX];
|
||||
};
|
||||
|
||||
static struct FindComBinary findcombinary_;
|
||||
static struct FindComBinary g_findcombinary;
|
||||
|
||||
/**
|
||||
* Returns path of binary without debug information, or null.
|
||||
*
|
||||
* @return path to non-debug binary, or -1 w/ errno
|
||||
*/
|
||||
const char *findcombinary(void) {
|
||||
const char *FindComBinary(void) {
|
||||
size_t len;
|
||||
const char *p;
|
||||
if (!findcombinary_.once) {
|
||||
findcombinary_.once = true;
|
||||
if (!g_findcombinary.once) {
|
||||
g_findcombinary.once = true;
|
||||
if ((p = (const char *)getauxval(AT_EXECFN)) &&
|
||||
(len = strlen(p)) < ARRAYLEN(findcombinary_.buf)) {
|
||||
findcombinary_.res = memcpy(findcombinary_.buf, p, len + 1);
|
||||
if (len > 4 && memcmp(&findcombinary_.buf[len - 4], ".dbg", 4) == 0) {
|
||||
findcombinary_.buf[len - 4] = '\0';
|
||||
(len = strlen(p)) < ARRAYLEN(g_findcombinary.buf)) {
|
||||
g_findcombinary.res = memcpy(g_findcombinary.buf, p, len + 1);
|
||||
if (len > 4 && memcmp(&g_findcombinary.buf[len - 4], ".dbg", 4) == 0) {
|
||||
g_findcombinary.buf[len - 4] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
return findcombinary_.res;
|
||||
return g_findcombinary.res;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
*
|
||||
* @return path to debug binary, or -1 w/ errno
|
||||
*/
|
||||
const char *finddebugbinary(void) {
|
||||
const char *FindDebugBinary(void) {
|
||||
static char buf[PATH_MAX];
|
||||
if (buf[0]) return &buf[0];
|
||||
const char *const trybins[] = {program_invocation_name,
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/repmovsb.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
@ -50,7 +51,7 @@ static char g_buf[512];
|
|||
static const char *g_lastsymbol;
|
||||
static struct SymbolTable *g_symbols;
|
||||
|
||||
forceinline int getnestinglevel(struct StackFrame *frame) {
|
||||
forceinline int GetNestingLevel(struct StackFrame *frame) {
|
||||
int nesting = -2;
|
||||
while (frame) {
|
||||
++nesting;
|
||||
|
@ -81,7 +82,7 @@ privileged interruptfn void ftrace_hook(void) {
|
|||
frame->addr - g_symbols->addr_base)]
|
||||
.name_rva];
|
||||
if (symbol != g_lastsymbol &&
|
||||
(nesting = getnestinglevel(frame)) * 2 < ARRAYLEN(g_buf) - 3) {
|
||||
(nesting = GetNestingLevel(frame)) * 2 < ARRAYLEN(g_buf) - 4) {
|
||||
i = 2;
|
||||
j = 0;
|
||||
while (nesting--) {
|
||||
|
@ -91,6 +92,7 @@ privileged interruptfn void ftrace_hook(void) {
|
|||
while (i < ARRAYLEN(g_buf) - 2 && symbol[j]) {
|
||||
g_buf[i++] = symbol[j++];
|
||||
}
|
||||
g_buf[i++] = '\r';
|
||||
g_buf[i++] = '\n';
|
||||
__print(g_buf, i);
|
||||
}
|
||||
|
@ -100,13 +102,42 @@ privileged interruptfn void ftrace_hook(void) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Installs plaintext function tracer. Do not call.
|
||||
* Enables plaintext function tracing if --ftrace flag passed.
|
||||
*
|
||||
* The --ftrace CLI arg is removed before main() is called. This
|
||||
* code is intended for diagnostic purposes and assumes binaries
|
||||
* are trustworthy and stack isn't corrupted. Logging plain text
|
||||
* allows program structure to easily be visualized and hotspots
|
||||
* identified w/ sed | sort | uniq -c | sort. A compressed trace
|
||||
* can be made by appending --ftrace 2>&1 | gzip -4 >trace.gz to
|
||||
* the CLI arguments. Have fun.
|
||||
*
|
||||
* @see libc/runtime/_init.S for documentation
|
||||
*/
|
||||
textstartup void ftrace_init(void) {
|
||||
g_buf[0] = '+';
|
||||
g_buf[1] = ' ';
|
||||
if ((g_symbols = opensymboltable(finddebugbinary()))) {
|
||||
__hook(ftrace_hook, g_symbols);
|
||||
textstartup int ftrace_init(int argc, char *argv[]) {
|
||||
int i;
|
||||
bool foundflag;
|
||||
foundflag = false;
|
||||
for (i = 1; i <= argc; ++i) {
|
||||
if (!foundflag) {
|
||||
if (argv[i]) {
|
||||
if (strcmp(argv[i], "--ftrace") == 0) {
|
||||
foundflag = true;
|
||||
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
||||
strcpy(argv[i], "--ftrace");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
argv[i - 1] = argv[i];
|
||||
}
|
||||
}
|
||||
if (foundflag) {
|
||||
--argc;
|
||||
g_buf[0] = '+';
|
||||
g_buf[1] = ' ';
|
||||
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
|
||||
__hook(ftrace_hook, g_symbols);
|
||||
}
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "libc/str/appendchar.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
||||
/* TODO(jart): Make early-stage data structures happen. */
|
||||
#undef isspace
|
||||
|
@ -39,11 +40,7 @@ struct DosArgv {
|
|||
wint_t wc;
|
||||
};
|
||||
|
||||
static textwindows void decodedosargv(struct DosArgv *st) {
|
||||
st->s += getutf16(st->s, &st->wc);
|
||||
}
|
||||
|
||||
static textwindows void appenddosargv(struct DosArgv *st, wint_t wc) {
|
||||
static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
|
||||
AppendChar(&st->p, st->pe, wc);
|
||||
}
|
||||
|
||||
|
@ -66,7 +63,7 @@ static textwindows void appenddosargv(struct DosArgv *st, wint_t wc) {
|
|||
* @see libc/runtime/ntspawn.c
|
||||
* @note kudos to Simon Tatham for figuring out quoting behavior
|
||||
*/
|
||||
textwindows int getdosargv(const char16_t *cmdline, char *buf, size_t size,
|
||||
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size,
|
||||
char **argv, size_t max) {
|
||||
bool inquote;
|
||||
size_t i, argc, slashes, quotes;
|
||||
|
@ -75,9 +72,9 @@ textwindows int getdosargv(const char16_t *cmdline, char *buf, size_t size,
|
|||
st.p = buf;
|
||||
st.pe = buf + size;
|
||||
argc = 0;
|
||||
decodedosargv(&st);
|
||||
st.wc = DecodeNtsUtf16(&st.s);
|
||||
while (st.wc) {
|
||||
while (st.wc && iswspace(st.wc)) decodedosargv(&st);
|
||||
while (st.wc && iswspace(st.wc)) st.wc = DecodeNtsUtf16(&st.s);
|
||||
if (!st.wc) break;
|
||||
if (++argc < max) {
|
||||
argv[argc - 1] = st.p < st.pe ? st.p : NULL;
|
||||
|
@ -88,27 +85,27 @@ textwindows int getdosargv(const char16_t *cmdline, char *buf, size_t size,
|
|||
if (st.wc == '"' || st.wc == '\\') {
|
||||
slashes = 0;
|
||||
quotes = 0;
|
||||
while (st.wc == '\\') decodedosargv(&st), slashes++;
|
||||
while (st.wc == '"') decodedosargv(&st), quotes++;
|
||||
while (st.wc == '\\') st.wc = DecodeNtsUtf16(&st.s), slashes++;
|
||||
while (st.wc == '"') st.wc = DecodeNtsUtf16(&st.s), quotes++;
|
||||
if (!quotes) {
|
||||
while (slashes--) appenddosargv(&st, '\\');
|
||||
while (slashes--) AppendDosArgv(&st, '\\');
|
||||
} else {
|
||||
while (slashes >= 2) appenddosargv(&st, '\\'), slashes -= 2;
|
||||
if (slashes) appenddosargv(&st, '"'), quotes--;
|
||||
while (slashes >= 2) AppendDosArgv(&st, '\\'), slashes -= 2;
|
||||
if (slashes) AppendDosArgv(&st, '"'), quotes--;
|
||||
if (quotes > 0) {
|
||||
if (!inquote) quotes--;
|
||||
for (i = 3; i <= quotes + 1; i += 3) appenddosargv(&st, '"');
|
||||
for (i = 3; i <= quotes + 1; i += 3) AppendDosArgv(&st, '"');
|
||||
inquote = (quotes % 3 == 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
appenddosargv(&st, st.wc);
|
||||
decodedosargv(&st);
|
||||
AppendDosArgv(&st, st.wc);
|
||||
st.wc = DecodeNtsUtf16(&st.s);
|
||||
}
|
||||
}
|
||||
appenddosargv(&st, '\0');
|
||||
AppendDosArgv(&st, '\0');
|
||||
}
|
||||
appenddosargv(&st, '\0');
|
||||
AppendDosArgv(&st, '\0');
|
||||
if (size) buf[min(st.p - buf, size - 1)] = '\0';
|
||||
if (max) argv[min(argc, max - 1)] = NULL;
|
||||
return argc;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/str/appendchar.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
|
@ -34,25 +35,28 @@
|
|||
* @param max is the pointer count capacity of envp
|
||||
* @return number of variables decoded, excluding NULL-terminator
|
||||
*/
|
||||
static inline int getdosenviron(const char16_t *env, char *buf, size_t size,
|
||||
static inline int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
||||
char **envp, size_t max) {
|
||||
const char16_t *s = env;
|
||||
size_t envc = 0;
|
||||
wint_t wc;
|
||||
size_t envc;
|
||||
char *p, *pe;
|
||||
bool endstring;
|
||||
const char16_t *s;
|
||||
s = env;
|
||||
envc = 0;
|
||||
if (size) {
|
||||
wint_t wc;
|
||||
char *p = buf;
|
||||
char *pe = buf + size - 1;
|
||||
p = buf;
|
||||
pe = buf + size - 1;
|
||||
if (p < pe) {
|
||||
s += getutf16(s, &wc);
|
||||
wc = DecodeNtsUtf16(&s);
|
||||
while (wc) {
|
||||
if (++envc < max) {
|
||||
envp[envc - 1] = p < pe ? p : NULL;
|
||||
}
|
||||
bool endstring;
|
||||
do {
|
||||
AppendChar(&p, pe, wc);
|
||||
endstring = !wc;
|
||||
s += getutf16(s, &wc);
|
||||
wc = DecodeNtsUtf16(&s);
|
||||
} while (!endstring);
|
||||
buf[min(p - buf, size - 2)] = u'\0';
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ privileged interruptfn void GOT_HERE(long num) {
|
|||
msg[len++] = 'e';
|
||||
msg[len++] = ' ';
|
||||
len += int64toarray_radix10(num, &msg[len]);
|
||||
msg[len++] = '\r';
|
||||
msg[len++] = '\n';
|
||||
msg[len] = '\0';
|
||||
__print(msg, len);
|
||||
|
|
|
@ -25,7 +25,7 @@ void *__cxa_finalize(void *) hidden;
|
|||
void _executive(int, char **, char **, long (*)[2]) hidden noreturn;
|
||||
void __stack_chk_fail(void) noreturn relegated;
|
||||
void __stack_chk_fail_local(void) noreturn relegated hidden;
|
||||
int getdosargv(const char16_t *, char *, size_t, char **, size_t) hidden;
|
||||
int GetDosArgv(const char16_t *, char *, size_t, char **, size_t) hidden;
|
||||
|
||||
forceinline void AssertNeverCalledWhileTerminating(void) {
|
||||
if (!NoDebug() && (g_runstate & RUNSTATE_TERMINATE)) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
|
@ -28,12 +29,13 @@
|
|||
*/
|
||||
bool isheap(void *p) {
|
||||
int x, i;
|
||||
#if 1
|
||||
register intptr_t rsp asm("rsp");
|
||||
if ((intptr_t)p >= rsp) return false;
|
||||
#endif
|
||||
if ((intptr_t)p <= (intptr_t)_end) return false;
|
||||
x = (intptr_t)p >> 16;
|
||||
i = FindMemoryInterval(&_mmi, x);
|
||||
return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y;
|
||||
register uintptr_t rsp asm("rsp");
|
||||
if (ROUNDDOWN(rsp, STACKSIZE) == ROUNDDOWN((intptr_t)p, STACKSIZE)) {
|
||||
return false;
|
||||
} else {
|
||||
if ((intptr_t)p <= (intptr_t)_end) return false;
|
||||
x = (intptr_t)p >> 16;
|
||||
i = FindMemoryInterval(&_mmi, x);
|
||||
return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,5 +24,5 @@
|
|||
|
||||
void *mapanon(size_t mapsize) {
|
||||
return mmap(NULL, mapsize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_NONBLOCK | MAP_ANONYMOUS, -1, 0);
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define kAutomapStart 0x0000100000000000
|
||||
#define kAutomapSize 0x0000100000000000
|
||||
#define kAutomapStart 0x0000100080000000 // asan can't spread its poison here
|
||||
#define kAutomapSize 0x00000fff80000000
|
||||
#define kFixedmapStart 0x0000200000000000
|
||||
|
||||
struct MemoryIntervals {
|
||||
|
@ -12,8 +14,8 @@ struct MemoryIntervals {
|
|||
struct MemoryInterval {
|
||||
int x;
|
||||
int y;
|
||||
} p[64];
|
||||
long h[64];
|
||||
} p[128];
|
||||
long h[128];
|
||||
};
|
||||
|
||||
extern struct MemoryIntervals _mmi;
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
/**
|
||||
* Maps debuggable binary into memory and indexes symbol addresses.
|
||||
*
|
||||
* @return object freeable with closesymboltable(), or NULL w/ errno
|
||||
* @return object freeable with CloseSymbolTable(), or NULL w/ errno
|
||||
*/
|
||||
struct SymbolTable *opensymboltable(const char *filename) {
|
||||
struct SymbolTable *OpenSymbolTable(const char *filename) {
|
||||
unsigned i, j;
|
||||
struct SymbolTable *t;
|
||||
const Elf64_Sym *symtab, *sym;
|
||||
|
@ -56,7 +56,7 @@ struct SymbolTable *opensymboltable(const char *filename) {
|
|||
t->count = j;
|
||||
carsort1000(t->count, (void *)t->symbols);
|
||||
} else {
|
||||
closesymboltable(&t);
|
||||
CloseSymbolTable(&t);
|
||||
}
|
||||
return t == MAP_FAILED ? NULL : t;
|
||||
}
|
||||
|
|
|
@ -28,18 +28,18 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
|
|||
int i, frames, maptally, gaptally;
|
||||
maptally = 0;
|
||||
gaptally = 0;
|
||||
(dprintf)(fd, "%s%zd%s\n", "mm->i == ", mm->i, ";");
|
||||
(dprintf)(fd, "%s%zd%s\r\n", "mm->i == ", mm->i, ";");
|
||||
for (i = 0; i < mm->i; ++i) {
|
||||
if (i && mm->p[i].x != mm->p[i - 1].y + 1) {
|
||||
frames = mm->p[i].x - mm->p[i - 1].y - 1;
|
||||
gaptally += frames;
|
||||
(dprintf)(fd, "%s%,zd%s\n", "/* ", frames, " */");
|
||||
(dprintf)(fd, "%s%,zd%s\r\n", "/* ", frames, " */");
|
||||
}
|
||||
frames = mm->p[i].y + 1 - mm->p[i].x;
|
||||
maptally += frames;
|
||||
(dprintf)(fd, "%s%3u%s0x%08x,0x%08x%s%,zd%s\n", "mm->p[", i, "]=={",
|
||||
(dprintf)(fd, "%s%3u%s0x%08x,0x%08x%s%,zd%s\r\n", "mm->p[", i, "]=={",
|
||||
mm->p[i].x, mm->p[i].y, "}; /* ", frames, " */");
|
||||
}
|
||||
(dprintf)(fd, "%s%,zd%s%,zd%s\n\n", "/* ", maptally, " frames mapped w/ ",
|
||||
(dprintf)(fd, "%s%,zd%s%,zd%s\r\n\r\n", "/* ", maptally, " frames mapped w/ ",
|
||||
gaptally, " frames gapped */");
|
||||
}
|
||||
|
|
|
@ -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/bits/weaken.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Terminates process normally, running minimal cleanup.
|
||||
* @noreturn
|
||||
*/
|
||||
noreturn textexit void quick_exit(int rc) {
|
||||
if (weaken(fflush)) {
|
||||
if (weaken(stdout)) weaken(fflush)(*weaken(stdout));
|
||||
if (weaken(stderr)) weaken(fflush)(*weaken(stderr));
|
||||
}
|
||||
_Exit(rc);
|
||||
}
|
|
@ -41,7 +41,6 @@ void *mapanon(size_t) vallocesque attributeallocsize((1));
|
|||
int setjmp(jmp_buf) libcesque returnstwice paramsnonnull();
|
||||
void longjmp(jmp_buf, int) libcesque noreturn paramsnonnull();
|
||||
void exit(int) noreturn;
|
||||
void quick_exit(int) noreturn;
|
||||
void _exit(int) libcesque noreturn;
|
||||
void _Exit(int) libcesque noreturn;
|
||||
long _setstack(void *, void *, ...);
|
||||
|
|
|
@ -1,27 +1,8 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 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 │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifndef COSMOPOLITAN_LIBC_SYMBOLS_H_
|
||||
#define COSMOPOLITAN_LIBC_SYMBOLS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/runtime/ezmap.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Symbol {
|
||||
|
@ -46,13 +27,11 @@ struct SymbolTable {
|
|||
struct Symbol symbols[];
|
||||
};
|
||||
|
||||
struct SymbolTable *getsymboltable(void);
|
||||
const char *findcombinary(void);
|
||||
const char *finddebugbinary(void);
|
||||
struct SymbolTable *opensymboltable(const char *) nodiscard;
|
||||
int closesymboltable(struct SymbolTable **);
|
||||
const struct Symbol *bisectsymbol(struct SymbolTable *, intptr_t, int64_t *);
|
||||
const char *getsymbolname(struct SymbolTable *, const struct Symbol *);
|
||||
struct SymbolTable *GetSymbolTable(void);
|
||||
const char *FindComBinary(void);
|
||||
const char *FindDebugBinary(void);
|
||||
struct SymbolTable *OpenSymbolTable(const char *) nodiscard;
|
||||
int CloseSymbolTable(struct SymbolTable **);
|
||||
void __hook(void (*)(void), struct SymbolTable *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
static struct CmdExe {
|
||||
bool result;
|
||||
struct OldNtConsole {
|
||||
unsigned codepage;
|
||||
unsigned mode;
|
||||
uint32_t codepage;
|
||||
uint32_t mode;
|
||||
int64_t handle;
|
||||
} oldin, oldout;
|
||||
} g_cmdexe;
|
||||
|
@ -82,6 +82,8 @@ static textwindows void NormalizeCmdExe(void) {
|
|||
SetConsoleCP(kNtCpUtf8);
|
||||
GetConsoleMode(handle, &g_cmdexe.oldin.mode);
|
||||
SetConsoleMode(handle, g_cmdexe.oldin.mode | kNtEnableProcessedInput |
|
||||
kNtEnableEchoInput | kNtEnableLineInput |
|
||||
kNtEnableWindowInput |
|
||||
kNtEnableVirtualTerminalInput);
|
||||
}
|
||||
if (GetFileType((handle = hstdout)) == kNtFileTypeChar ||
|
||||
|
@ -92,7 +94,10 @@ static textwindows void NormalizeCmdExe(void) {
|
|||
SetConsoleOutputCP(kNtCpUtf8);
|
||||
GetConsoleMode(handle, &g_cmdexe.oldout.mode);
|
||||
SetConsoleMode(handle, g_cmdexe.oldout.mode | kNtEnableProcessedOutput |
|
||||
kNtEnableVirtualTerminalProcessing);
|
||||
kNtEnableWrapAtEolOutput |
|
||||
(NtGetVersion() >= kNtVersionWindows10
|
||||
? kNtEnableVirtualTerminalProcessing
|
||||
: 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,11 +141,11 @@ textwindows int WinMain(void *hInstance, void *hPrevInstance,
|
|||
*(/*unconst*/ int *)&hostos = WINDOWS;
|
||||
cmd16 = GetCommandLine();
|
||||
env16 = GetEnvironmentStrings();
|
||||
count = getdosargv(cmd16, argblock, ARG_MAX, argarray, 512);
|
||||
count = GetDosArgv(cmd16, argblock, ARG_MAX, argarray, 512);
|
||||
for (i = 0; argarray[0][i]; ++i) {
|
||||
if (argarray[0][i] == '\\') argarray[0][i] = '/';
|
||||
}
|
||||
getdosenviron(env16, envblock, ENV_MAX, envarray, 512);
|
||||
GetDosEnviron(env16, envblock, ENV_MAX, envarray, 512);
|
||||
FreeEnvironmentStrings(env16);
|
||||
_executive(count, argarray, envarray, auxarray);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue