Make more improvements

This change includes many bug fixes, for the NT polyfills, strings,
memory, boot, and math libraries which were discovered by adding more
tools for recreational programming, such as PC emulation. Lemon has also
been vendored because it works so well at parsing languages.
main
Justine Tunney 2020-09-28 01:13:56 -07:00
parent 416fd86676
commit 23d333c090
201 changed files with 14558 additions and 3082 deletions

View File

@ -139,6 +139,7 @@ include dsp/tty/tty.mk # ├──online
include libc/dns/dns.mk # │ include libc/dns/dns.mk # │
include libc/crypto/crypto.mk # │ include libc/crypto/crypto.mk # │
include net/http/http.mk #─┘ include net/http/http.mk #─┘
include third_party/lemon/lemon.mk
include third_party/linenoise/linenoise.mk include third_party/linenoise/linenoise.mk
include third_party/editline/editline.mk include third_party/editline/editline.mk
include third_party/duktape/duktape.mk include third_party/duktape/duktape.mk
@ -157,6 +158,8 @@ include tool/build/lib/buildlib.mk
include tool/build/emucrt/emucrt.mk include tool/build/emucrt/emucrt.mk
include tool/build/emubin/emubin.mk include tool/build/emubin/emubin.mk
include tool/build/build.mk include tool/build/build.mk
include tool/calc/calc.mk
include tool/tags/tags.mk
include tool/decode/lib/decodelib.mk include tool/decode/lib/decodelib.mk
include tool/decode/decode.mk include tool/decode/decode.mk
include tool/hash/hash.mk include tool/hash/hash.mk

View File

@ -1051,7 +1051,6 @@ realmodeloader:
mov %sp,%bp mov %sp,%bp
call rlinit call rlinit
call sinit4 call sinit4
mov $VIDYA_MODE,%di
call vinit call vinit
mov %es,XLM(VIDEO_POSITION_FAR_POINTER) mov %es,XLM(VIDEO_POSITION_FAR_POINTER)
mov %ax,XLM(VIDEO_POSITION_FAR_POINTER)+2 mov %ax,XLM(VIDEO_POSITION_FAR_POINTER)+2
@ -1291,32 +1290,16 @@ sputc: push %ax
ret ret
.endfn sputc,globl .endfn sputc,globl
/ Asks BIOS to initialize MDA/CGA display w/o cursor/blinking. / Asks BIOS to initialize Monochrome Display Adapter.
/ /
/ @param dil video mode
/ @return es:ax start of video page / @return es:ax start of video page
/ @mode real / @mode real
vinit: push %bp vinit: push $7
mov %sp,%bp pop %ax
push %bx int $VIDYA_SERVICE
bbmov VIDYA_ADDR_CGA>>4,%ax,%ah,%al bbmov VIDYA_ADDR_MDA>>4,%ax,%ah,%al
mov %ax,%es mov %ax,%es
mov %di,%ax
cmp $VIDYA_MODE_CGA,%al
je 1f
xor %ch,%ch # aka movesdi VIDYA_ADDR_MDA
1: xor %di,%di
bbmov VIDYA_SET_MODE,%ax,%ah,%al
int $VIDYA_SERVICE
bbmov VIDYA_SET_CURSOR,,%ah,%al
bbmov VIDYA_SET_CURSOR_NONE,,%ch,%cl # since we don't support it
int $VIDYA_SERVICE
bbmov VIDYA_SET_BLINKING,,%ah,%al # cargo culting (ega?)
bbmov VIDYA_SET_BLINKING_NONE,,%bh,%bl
int $VIDYA_SERVICE
xor %ax,%ax xor %ax,%ax
pop %bx
pop %bp
ret ret
.endfn vinit,globl .endfn vinit,globl

View File

@ -18,7 +18,7 @@ CONFIG_CCFLAGS += \
-Og -Og
TARGET_ARCH ?= \ TARGET_ARCH ?= \
-march=k8-sse3 -msse3
RAGELFLAGS ?= -G2 RAGELFLAGS ?= -G2

View File

@ -155,8 +155,7 @@ MATHEMATICAL = \
DEFAULT_CPPFLAGS = \ DEFAULT_CPPFLAGS = \
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \ -DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \
-nostdinc \ -nostdinc \
-iquote . \ -iquote .
-include libc/integral/normalize.inc
DEFAULT_CFLAGS = \ DEFAULT_CFLAGS = \
-std=gnu2x -std=gnu2x
@ -217,7 +216,8 @@ cpp.flags = \
$(DEFAULT_CPPFLAGS) \ $(DEFAULT_CPPFLAGS) \
$(CONFIG_CPPFLAGS) \ $(CONFIG_CPPFLAGS) \
$(CPPFLAGS) \ $(CPPFLAGS) \
$(OVERRIDE_CPPFLAGS) $(OVERRIDE_CPPFLAGS) \
-include libc/integral/normalize.inc
copt.flags = \ copt.flags = \
$(TARGET_ARCH) \ $(TARGET_ARCH) \
@ -317,18 +317,20 @@ OBJECTIFY.c99.c = $(CC) $(OBJECTIFY.c.flags) -std=c99 -Wextra -Werror -pedantic-
OBJECTIFY.c11.c = $(CC) $(OBJECTIFY.c.flags) -std=c11 -Wextra -Werror -pedantic-errors -c OBJECTIFY.c11.c = $(CC) $(OBJECTIFY.c.flags) -std=c11 -Wextra -Werror -pedantic-errors -c
OBJECTIFY.c2x.c = $(CC) $(OBJECTIFY.c.flags) -std=c2x -Wextra -Werror -pedantic-errors -c OBJECTIFY.c2x.c = $(CC) $(OBJECTIFY.c.flags) -std=c2x -Wextra -Werror -pedantic-errors -c
# No-Clobber ABI (clobbers nothing, except rax and flags) OBJECTIFY.real.c = \
# $(GCC) \
# This ABI is intended for core library functions that're frequently $(OBJECTIFY.c.flags) \
# called by just about everything, e.g. memcpy, malloc, etc. By offering -wrapper build/realify.sh \
# this guarantee, callers can optionally call these functions via asm(), -ffixed-r8 \
# which reduces register allocator pressure at call sites. -ffixed-r9 \
# -ffixed-r10 \
# This makes unrelated caller code faster, but the NCABI functions -ffixed-r11 \
# themselves a tiny bit slower. That's OK, since modern NexGen-32e CPUs -ffixed-r12 \
# seem to have one fifth of their execution engines devoted to pushing -ffixed-r13 \
# and popping, probably so legacy IA-32 code keeps going fast; so we use -ffixed-r14 \
# it to our advantage. -ffixed-r15 \
-c
OBJECTIFY.ncabi.c = \ OBJECTIFY.ncabi.c = \
$(GCC) \ $(GCC) \
$(OBJECTIFY.c.flags) \ $(OBJECTIFY.c.flags) \
@ -350,9 +352,6 @@ OBJECTIFY.ncabi.c = \
-c \ -c \
-xc -xc
# Initializer ABI
#
# Doesn't clobber RDI and RSI.
OBJECTIFY.initabi.c = \ OBJECTIFY.initabi.c = \
$(GCC) \ $(GCC) \
$(OBJECTIFY.c.flags) \ $(OBJECTIFY.c.flags) \

177
build/realify.sed 100644
View File

@ -0,0 +1,177 @@
#-*-mode:sed;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: et ft=sed ts=8 tw=8 fenc=utf-8 :vi─────────────────┘
#
# SYNOPSIS
#
# sed -i -f build/realify.sed foo.s
#
# OVERVIEW
#
# This converts ints and longs to shorts while preserving System V ABI
# x86_64 compatibility. This works better than gcc -m16 because we can
# avoid the ASZ and OSZ prefixes in most cases while also avoiding the
# legacy 32-bit calling conventions.
# remove comments
s/[ \t][ \t]*#.*//
# preserve hardcoded stack offsets
s/leave\(q\|\)/leavew ; add $6,%sp/
s/call\(q\|\)\t/sub $6,%sp ; callw /
s/ret\(q\|\)/retw\t$6/
s/pushq\t\(.*\)/sub $6,%sp ; push \1/
s/popq\t\(.*\)/pop \1 ; add $6,%sp/
# can be used instead if
# 1. functions have 6 args or fewer
# 2. long double parameters forceinline
#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 ; push \1/
#s/popq\t\(.*\)/pop \1 ; add $6,%sp/
# 32-bitify
s/rax/eax/g
s/rbx/ebx/g
s/rcx/ecx/g
s/rdx/edx/g
s/rbp/ebp/g
s/rdi/edi/g
s/rsi/esi/g
s/rsp/esp/g
# unextension
s/movswl/mov/
s/movzwl/mov/
s/movslq/mov/
s/movzlq/mov/
# unsuffix
s/^\(\t\(fild\|fist\|fistp\|fiadd\|fisub\|fisubr\|fimul\|fidiv\|fidivr\|ficom\)\)q\t/\1\t/
s/^\(\t\(mov\|add\|adc\|cmp\|test\|lea\|sbb\|mul\|imul\|div\|idiv\|in\|out\|xor\|sub\|and\|or\|rol\|ror\|rcl\|rcr\|shl\|shr\|sal\|sar\|inc\|dec\|not\|neg\)\)l\t/\1w\t/
s/^\(\t[a-z]*\)q\t/\1w\t/
# remove fluff
s/mov\t%eax,%eax//
s/mov\t%ebx,%ebx//
s/mov\t%ecx,%ecx//
s/mov\t%edx,%edx//
s/mov\t%ebp,%ebp//
s/mov\t%edi,%edi//
s/mov\t%esi,%esi//
s/mov\t%esp,%esp//
# make pic absolute
s/(%rip)//
# legal real mode modrm
s/(%ebx)/(%bx)/
s/(%edi)/(%di)/
s/(%esi)/(%si)/
s/(%ebp)/(%bp)/
s/(%ebx,%esi\(,1\|\))/(%bx,%si)/
s/(%ebx,%edi\(,1\|\))/(%bx,%di)/
s/(%ebp,%esi\(,1\|\))/(%bp,%si)/
s/(%ebp,%edi\(,1\|\))/(%bp,%di)/
# we need the asz prefix
s/(%eax,%eax/(%EAX,%EAX/
s/(%eax,%ebp/(%EAX,%EBP/
s/(%eax,%ebx/(%EAX,%EBX/
s/(%eax,%ecx/(%EAX,%ECX/
s/(%eax,%edi/(%EAX,%EDI/
s/(%eax,%edx/(%EAX,%EDX/
s/(%eax,%esi/(%EAX,%ESI/
s/(%eax,%esp/(%EAX,%ESP/
s/(%ebp,%eax/(%EBP,%EAX/
s/(%ebp,%ebp/(%EBP,%EBP/
s/(%ebp,%ebx/(%EBP,%EBX/
s/(%ebp,%ecx/(%EBP,%ECX/
s/(%ebp,%edi/(%EBP,%EDI/
s/(%ebp,%edx/(%EBP,%EDX/
s/(%ebp,%esi/(%EBP,%ESI/
s/(%ebp,%esp/(%EBP,%ESP/
s/(%ebx,%eax/(%EBX,%EAX/
s/(%ebx,%ebp/(%EBX,%EBP/
s/(%ebx,%ebx/(%EBX,%EBX/
s/(%ebx,%ecx/(%EBX,%ECX/
s/(%ebx,%edi/(%EBX,%EDI/
s/(%ebx,%edx/(%EBX,%EDX/
s/(%ebx,%esi/(%EBX,%ESI/
s/(%ebx,%esp/(%EBX,%ESP/
s/(%ecx,%eax/(%ECX,%EAX/
s/(%ecx,%ebp/(%ECX,%EBP/
s/(%ecx,%ebx/(%ECX,%EBX/
s/(%ecx,%ecx/(%ECX,%ECX/
s/(%ecx,%edi/(%ECX,%EDI/
s/(%ecx,%edx/(%ECX,%EDX/
s/(%ecx,%esi/(%ECX,%ESI/
s/(%ecx,%esp/(%ECX,%ESP/
s/(%edi,%eax/(%EDI,%EAX/
s/(%edi,%ebp/(%EDI,%EBP/
s/(%edi,%ebx/(%EDI,%EBX/
s/(%edi,%ecx/(%EDI,%ECX/
s/(%edi,%edi/(%EDI,%EDI/
s/(%edi,%edx/(%EDI,%EDX/
s/(%edi,%esi/(%EDI,%ESI/
s/(%edi,%esp/(%EDI,%ESP/
s/(%edx,%eax/(%EDX,%EAX/
s/(%edx,%ebp/(%EDX,%EBP/
s/(%edx,%ebx/(%EDX,%EBX/
s/(%edx,%ecx/(%EDX,%ECX/
s/(%edx,%edi/(%EDX,%EDI/
s/(%edx,%edx/(%EDX,%EDX/
s/(%edx,%esi/(%EDX,%ESI/
s/(%edx,%esp/(%EDX,%ESP/
s/(%esi,%eax/(%ESI,%EAX/
s/(%esi,%ebp/(%ESI,%EBP/
s/(%esi,%ebx/(%ESI,%EBX/
s/(%esi,%ecx/(%ESI,%ECX/
s/(%esi,%edi/(%ESI,%EDI/
s/(%esi,%edx/(%ESI,%EDX/
s/(%esi,%esi/(%ESI,%ESI/
s/(%esi,%esp/(%ESI,%ESP/
s/(%esp,%eax/(%ESP,%EAX/
s/(%esp,%ebp/(%ESP,%EBP/
s/(%esp,%ebx/(%ESP,%EBX/
s/(%esp,%ecx/(%ESP,%ECX/
s/(%esp,%edi/(%ESP,%EDI/
s/(%esp,%edx/(%ESP,%EDX/
s/(%esp,%esi/(%ESP,%ESI/
s/(%esp,%esp/(%ESP,%ESP/
s/(,%eax/(,%EAX/
s/(,%ebx/(,%EBX/
s/(,%ecx/(,%ECX/
s/(,%edx/(,%EDX/
s/(,%esi/(,%ESI/
s/(,%edi/(,%EDI/
s/(,%ebp/(,%EBP/
s/(,%esp/(,%ESP/
s/(%eax)/(%EAX)/
s/(%ecx)/(%ECX)/
s/(%edx)/(%EDX)/
s/(%esp)/(%ESP)/
# 16bitify
s/eax/ax/g
s/ebx/bx/g
s/ecx/cx/g
s/edx/dx/g
s/ebp/bp/g
s/edi/di/g
s/esi/si/g
s/esp/sp/g
# sigh :\
# impossible to avoid rex byte access with naive substitution
# best workaround is avoid uint8_t* and try using uint16_t* more
#s/dil/bl/g
#s/sil/bh/g
#s/spl/bl/g
#s/bpl/bh/g
# nope
s/cltq//

23
build/realify.sh 100755
View File

@ -0,0 +1,23 @@
#!/bin/sh
#
# SYNOPSIS
#
# gcc -g0 -Os -wrapper build/realify.sh -ffixed-r{8,9,1{0,1,2,4,5}}
#
# OVERVIEW
#
# Reconfigures x86_64 compiler to emit 16-bit PC boot code.
if [ "${1##*/}" = as ]; then
for x; do
if [ "${x##*.}" = s ]; then
{
printf "\t.code16gcc"
sed -f build/realify.sed "$x"
} >"$x".tmp
mv -f "$x".tmp "$x"
fi
done
fi
exec "$@"

View File

@ -72,6 +72,7 @@ o/$(MODE)/%.c11.o: %.c11.c; @ACTION=OBJECTIFY.c11 build/compile $(OBJECTIFY.c11.
o/$(MODE)/%.c2x.o: %.c2x.c; @ACTION=OBJECTIFY.c2x build/compile $(OBJECTIFY.c2x.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.c2x.o: %.c2x.c; @ACTION=OBJECTIFY.c2x build/compile $(OBJECTIFY.c2x.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.initabi.o: %.initabi.c; @ACTION=OBJECTIFY.init build/compile $(OBJECTIFY.initabi.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.initabi.o: %.initabi.c; @ACTION=OBJECTIFY.init build/compile $(OBJECTIFY.initabi.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.ncabi.o: %.ncabi.c; @ACTION=OBJECTIFY.nc build/compile $(OBJECTIFY.ncabi.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.ncabi.o: %.ncabi.c; @ACTION=OBJECTIFY.nc build/compile $(OBJECTIFY.ncabi.c) $(OUTPUT_OPTION) $<
o/tiny/%.real.o: %.real.c; @ACTION=OBJECTIFY.real build/compile $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.runs: o/$(MODE)/%; @ACTION=CHECK.runs TARGET=$< build/runcom $< $(TESTARGS) && touch $@ o/$(MODE)/%.runs: o/$(MODE)/%; @ACTION=CHECK.runs TARGET=$< build/runcom $< $(TESTARGS) && touch $@
o/$(MODE)/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^) o/$(MODE)/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
o/$(MODE)/%.zip.o: %; @build/zipobj $(OUTPUT_OPTION) $< o/$(MODE)/%.zip.o: %; @build/zipobj $(OUTPUT_OPTION) $<

View File

@ -243,21 +243,19 @@ fatal:
int editorReadKey(int64_t fd) { int editorReadKey(int64_t fd) {
int nread; int nread;
char c, seq[3]; char c, seq[3];
while ((nread = read(fd, &c, 1)) == 0) { if ((nread = read(fd, &c, 1)) == -1) exit(1);
}
if (nread == -1) exit(1);
while (1) { while (1) {
switch (c) { switch (c) {
case CTRL('J'): /* newline */ case CTRL('J'): /* newline */
return CTRL('M'); return CTRL('M');
case CTRL('['): /* escape sequence */ case CTRL('V'):
return PAGE_DOWN;
case '\e': /* escape sequence */
/* If this is just an ESC, we'll timeout here. */ /* If this is just an ESC, we'll timeout here. */
if (read(fd, seq, 1) == 0) return CTRL('['); if (read(fd, seq, 1) == 0) return CTRL('[');
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
/* ESC [ sequences. */
if (seq[0] == '[') { if (seq[0] == '[') {
if (read(fd, seq + 1, 1) == 0) return CTRL('[');
if (seq[1] >= '0' && seq[1] <= '9') { if (seq[1] >= '0' && seq[1] <= '9') {
/* Extended escape, read additional byte. */ /* Extended escape, read additional byte. */
if (read(fd, seq + 2, 1) == 0) return CTRL('['); if (read(fd, seq + 2, 1) == 0) return CTRL('[');
@ -296,10 +294,11 @@ int editorReadKey(int64_t fd) {
return END_KEY; return END_KEY;
} }
} }
} } else if (seq[0] == 'v') {
return PAGE_UP;
/* ESC O sequences. */ } else if (seq[0] == 'O') {
else if (seq[0] == 'O') { if (read(fd, seq + 1, 1) == 0) return CTRL('[');
/* ESC O sequences. */
switch (seq[1]) { switch (seq[1]) {
case 'H': case 'H':
return HOME_KEY; return HOME_KEY;
@ -586,8 +585,9 @@ void editorUpdateRow(erow *row) {
/* Create a version of the row we can directly print on the screen, /* Create a version of the row we can directly print on the screen,
* respecting tabs, substituting non printable characters with '?'. */ * respecting tabs, substituting non printable characters with '?'. */
free(row->render); free(row->render);
for (j = 0; j < row->size; j++) for (j = 0; j < row->size; j++) {
if (row->chars[j] == CTRL('I')) tabs++; if (row->chars[j] == CTRL('I')) tabs++;
}
row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1); row->render = malloc(row->size + tabs * 8 + nonprint * 9 + 1);
idx = 0; idx = 0;
@ -1200,9 +1200,10 @@ void editorMoveCursor(int key) {
void editorProcessKeypress(int64_t fd) { void editorProcessKeypress(int64_t fd) {
/* When the file is modified, requires Ctrl-q to be pressed N times /* When the file is modified, requires Ctrl-q to be pressed N times
* before actually quitting. */ * before actually quitting. */
int c, times;
static int quit_times; static int quit_times;
int c = editorReadKey(fd); c = editorReadKey(fd);
switch (c) { switch (c) {
case CTRL('M'): /* Enter */ case CTRL('M'): /* Enter */
editorInsertNewline(); editorInsertNewline();
@ -1271,6 +1272,13 @@ void editorProcessKeypress(int64_t fd) {
break; break;
} }
case CTRL('L'):
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
times = E.screenrows / 2;
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break;
case PAGE_UP: case PAGE_UP:
case PAGE_DOWN: case PAGE_DOWN:
if (c == PAGE_UP && E.cy != 0) { if (c == PAGE_UP && E.cy != 0) {
@ -1278,10 +1286,10 @@ void editorProcessKeypress(int64_t fd) {
} else if (c == PAGE_DOWN && E.cy != E.screenrows - 1) { } else if (c == PAGE_DOWN && E.cy != E.screenrows - 1) {
E.cy = E.screenrows - 1; E.cy = E.screenrows - 1;
} }
{ times = E.screenrows;
int times = E.screenrows; while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN); times = E.screenrows / 2;
} while (times--) editorMoveCursor(c == PAGE_UP ? ARROW_DOWN : ARROW_UP);
break; break;
case HOME_KEY: case HOME_KEY:
@ -1316,9 +1324,6 @@ void editorProcessKeypress(int64_t fd) {
editorMoveCursor(c); editorMoveCursor(c);
break; break;
case CTRL('L'): /* ctrl+l, clear screen */
/* Just refresht the line as side effect. */
break;
case CTRL('['): case CTRL('['):
/* Nothing to do for ESC in this mode. */ /* Nothing to do for ESC in this mode. */
break; break;

95
examples/lstime.c 100644
View File

@ -0,0 +1,95 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/alg/alg.h"
#include "libc/alg/arraylist2.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/dt.h"
#include "libc/x/x.h"
struct stat st;
struct Files {
size_t i, n;
struct File {
struct timespec mt;
char *path;
} * p;
} g_files;
int CompareFiles(struct File *a, struct File *b) {
if (a->mt.tv_sec > b->mt.tv_sec) return 1;
if (a->mt.tv_sec < b->mt.tv_sec) return -1;
if (a->mt.tv_nsec > b->mt.tv_nsec) return 1;
if (a->mt.tv_nsec < b->mt.tv_nsec) return -1;
return strcmp(a->path, b->path);
}
void WalkPaths(const char *dirpath) {
DIR *d;
char *path;
struct File f;
struct dirent *e;
CHECK((d = opendir(dirpath)));
while ((e = readdir(d))) {
if (strcmp(e->d_name, ".") == 0) continue;
if (strcmp(e->d_name, "..") == 0) continue;
path = xjoinpaths(dirpath, e->d_name);
if (strcmp(e->d_name, "o") == 0) continue;
if (strcmp(e->d_name, ".git") == 0) continue;
if (e->d_type == DT_DIR) {
WalkPaths(gc(path));
} else {
CHECK_NE(-1, lstat(path, &st), "%s", path);
f.mt = st.st_mtim;
f.path = path;
APPEND(&g_files.p, &g_files.i, &g_files.n, &f);
}
}
closedir(d);
}
void SortPaths(void) {
qsort(g_files.p, g_files.i, sizeof(*g_files.p), (void *)CompareFiles);
}
void PrintPaths(void) {
long i;
char *ts;
for (i = 0; i < g_files.i; ++i) {
ts = xiso8601(&g_files.p[i].mt);
printf("%s %s\n", ts, g_files.p[i].path);
free(ts);
}
}
void FreePaths(void) {
long i;
for (i = 0; i < g_files.i; ++i) free(g_files.p[i].path);
g_files.i = 0;
}
void LsTime(void) {
WalkPaths(".");
SortPaths();
PrintPaths();
FreePaths();
}
int main(int argc, char *argv[]) {
LsTime();
return 0;
}

View File

@ -45,9 +45,9 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
#define ROL(w, k) ((w) << (k) | CheckUnsigned(w) >> (sizeof(w) * 8 - (k))) #define ROL(w, k) ((w) << (k) | CheckUnsigned(w) >> (sizeof(w) * 8 - (k)))
#define SAR(w, k) (((w) & ~(~0u >> (k))) | ((w) >> ((k) & (sizeof(w) * 8 - 1)))) #define SAR(w, k) (((w) & ~(~0u >> (k))) | ((w) >> ((k) & (sizeof(w) * 8 - 1))))
#define bitreverse8(X) (kReverseBits[(X)&0xff]) #define bitreverse8(X) (kReverseBits[(uint8_t)(X)])
#define bitreverse16(X) \ #define bitreverse16(X) \
((uint16_t)kReverseBits[(X)&0xff] << 010 | \ ((uint16_t)kReverseBits[(uint8_t)(X)] << 010 | \
kReverseBits[((uint16_t)(X) >> 010) & 0xff]) kReverseBits[((uint16_t)(X) >> 010) & 0xff])
#define READ16LE(S) \ #define READ16LE(S) \

View File

@ -19,4 +19,6 @@
*/ */
#include "libc/macros.h" #include "libc/macros.h"
long(roundup)(long w, long k) { return ROUNDUP(w, k); } long(roundup)(long w, long k) {
return ROUNDUP(w, k);
}

View File

@ -84,7 +84,6 @@ char *get_current_dir_name(void) nodiscard;
char *getcwd(char *, size_t); char *getcwd(char *, size_t);
char *realpath(const char *, char *); char *realpath(const char *, char *);
char *replaceuser(const char *) nodiscard; char *replaceuser(const char *) nodiscard;
char *slurp(const char *, size_t *) nodiscard;
char *ttyname(int); char *ttyname(int);
char *commandv(const char *, char[hasatleast PATH_MAX]); char *commandv(const char *, char[hasatleast PATH_MAX]);
int access(const char *, int) nothrow; int access(const char *, int) nothrow;

View File

@ -24,7 +24,7 @@
textwindows int close$nt(int fd) { textwindows int close$nt(int fd) {
bool32 ok; bool32 ok;
if (isfdindex(fd)) { if (isfdopen(fd)) {
if (g_fds.p[fd].kind == kFdFile) { if (g_fds.p[fd].kind == kFdFile) {
/* /*
* Like Linux, closing a file on Windows doesn't guarantee it's * Like Linux, closing a file on Windows doesn't guarantee it's

View File

@ -34,13 +34,13 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
if (newfd == -1) { if (newfd == -1) {
if ((newfd = createfd()) == -1) return -1; if ((newfd = createfd()) == -1) return -1;
} else if (isfdindex(newfd)) { } else if (isfdindex(newfd)) {
close(newfd); if (g_fds.p[newfd].kind != kFdEmpty) {
} else if (isfdlegal(newfd)) { close(newfd);
}
} else {
do { do {
if (growfds() == -1) return -1; if (growfds() == -1) return -1;
} while (newfd >= g_fds.n); } while (newfd >= g_fds.n);
} else {
return ebadf();
} }
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle, if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
GetCurrentProcess(), &g_fds.p[newfd].handle, 0, GetCurrentProcess(), &g_fds.p[newfd].handle, 0,

View File

@ -24,7 +24,7 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int fcntl$nt(int fd, int cmd, unsigned arg) { textwindows int fcntl$nt(int fd, int cmd, unsigned arg) {
if (!isfdindex(fd)) return ebadf(); if (!isfdkind(fd, kFdFile)) return ebadf();
switch (cmd) { switch (cmd) {
case F_GETFD: case F_GETFD:
return GetHandleInformation(g_fds.p[fd].handle, &arg) ? (arg ^ FD_CLOEXEC) return GetHandleInformation(g_fds.p[fd].handle, &arg) ? (arg ^ FD_CLOEXEC)

View File

@ -33,7 +33,10 @@ uint32_t fprot2nt(int prot, int flags) {
return (HAS(prot, PROT_READ) ? kNtFileMapRead : 0) | return (HAS(prot, PROT_READ) ? kNtFileMapRead : 0) |
(HAS(prot, PROT_WRITE) ? kNtFileMapWrite : 0) | (HAS(prot, PROT_WRITE) ? kNtFileMapWrite : 0) |
(HAS(prot, PROT_EXEC) ? kNtFileMapExecute : 0) | (HAS(prot, PROT_EXEC) ? kNtFileMapExecute : 0) |
(HAS(flags, MAP_PRIVATE) ? kNtFileMapCopy : 0) |
(HAS(flags, kNtSecLargePages) ? kNtFileMapLargePages : 0) | (HAS(flags, kNtSecLargePages) ? kNtFileMapLargePages : 0) |
(HAS(flags, kNtSecReserve) ? kNtFileMapReserve : 0); (HAS(flags, kNtSecReserve) ? kNtFileMapReserve : 0) |
((HAS(flags, MAP_PRIVATE) && HAS(prot, PROT_READ) &&
HAS(prot, PROT_WRITE))
? kNtFileMapCopy
: 0);
} }

View File

@ -31,7 +31,6 @@
* @see libc/sysv/consts.sh * @see libc/sysv/consts.sh
*/ */
int getrlimit(int resource, struct rlimit *rlim) { int getrlimit(int resource, struct rlimit *rlim) {
/* TODO(jart): Windows */
if (resource == -1) return einval(); if (resource == -1) return einval();
return getrlimit$sysv(resource, rlim); return getrlimit$sysv(resource, rlim);
} }

View File

@ -28,7 +28,7 @@ int growfds(void) {
struct Fd *p; struct Fd *p;
if (weaken(realloc)) { if (weaken(realloc)) {
if ((p = weaken(realloc)(g_fds.p != g_fds.__init_p ? g_fds.p : NULL, if ((p = weaken(realloc)(g_fds.p != g_fds.__init_p ? g_fds.p : NULL,
(n = ((i = g_fds.n) * 2)) * sizeof(*p)))) { (n = (i = g_fds.n) << 1) * sizeof(*p)))) {
do { do {
p[i++].kind = kFdEmpty; p[i++].kind = kFdEmpty;
} while (i < n); } while (i < n);

View File

@ -46,8 +46,7 @@ LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
LIBC_STR \ LIBC_STR \
LIBC_STUBS \ LIBC_STUBS \
LIBC_SYSV \ LIBC_SYSV \
LIBC_SYSV_CALLS \ LIBC_SYSV_CALLS
LIBC_TIME
LIBC_CALLS_HEFTY_A_DEPS := \ LIBC_CALLS_HEFTY_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)))) $(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))

View File

@ -1,22 +1,3 @@
/*-*- 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_CALLS_INTERNAL_H_ #ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ #define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#ifndef __STRICT_ANSI__ #ifndef __STRICT_ANSI__
@ -54,15 +35,8 @@ struct IoctlPtmGet {
char workername[16]; char workername[16];
}; };
/**
* List of open handles on Windows NT.
*
* The array is indexed by the sysv-style file descriptor numbers that
* we assign. It's needed to make file descriptors only require 32bits
* and helps us abstract peculiarities like close() vs. closesocket().
*/
struct Fds { struct Fds {
size_t f; // length size_t f; // arbitrary free slot start search index
size_t n; // capacity size_t n; // capacity
struct Fd { struct Fd {
int64_t handle; int64_t handle;
@ -82,34 +56,27 @@ struct Fds {
extern const struct Fd kEmptyFd; extern const struct Fd kEmptyFd;
hidden extern int g_sighandrvas[NSIG]; extern int g_sighandrvas[NSIG] hidden;
hidden extern struct Fds g_fds; extern struct Fds g_fds hidden;
hidden extern struct NtSystemInfo g_ntsysteminfo; extern struct NtSystemInfo g_ntsysteminfo hidden;
hidden extern struct NtStartupInfo g_ntstartupinfo; extern struct NtStartupInfo g_ntstartupinfo hidden;
hidden extern const struct NtSecurityAttributes kNtIsInheritable; extern const struct NtSecurityAttributes kNtIsInheritable hidden;
forceinline bool isfdlegal(int fd) {
if (!IsTrustworthy()) {
return (0 <= fd && fd <= INT_MAX);
} else {
return fd;
}
}
forceinline bool isfdindex(int fd) {
if (!IsTrustworthy()) {
return (0 <= fd && fd < g_fds.n);
} else {
return fd;
}
}
ssize_t createfd(void) hidden; ssize_t createfd(void) hidden;
int growfds(void) hidden; int growfds(void) hidden;
void removefd(int) hidden; void removefd(int) hidden;
enum FdKind fdkind(int) hidden nosideeffect; enum FdKind fdkind(int) hidden nosideeffect;
bool isfdopen(int) hidden nosideeffect;
bool isfdkind(int, enum FdKind) hidden nosideeffect; bool isfdkind(int, enum FdKind) hidden nosideeffect;
forceinline bool isfdindex(int fd) {
if (!IsTrustworthy()) {
return (0 <= fd && fd < g_fds.n);
} else {
return true;
}
}
forceinline size_t clampio(size_t size) { forceinline size_t clampio(size_t size) {
if (!IsTrustworthy()) { if (!IsTrustworthy()) {
return MIN(size, 0x7ffff000); return MIN(size, 0x7ffff000);

View File

@ -29,8 +29,8 @@ int ioctl$default(int fd, uint64_t request, void *memory) {
int64_t handle; int64_t handle;
if (!IsWindows()) { if (!IsWindows()) {
return ioctl$sysv(fd, request, memory); return ioctl$sysv(fd, request, memory);
} else if (isfdindex(fd)) { } else if (isfdopen(fd)) {
if (isfdkind(fd, kFdSocket)) { if (g_fds.p[fd].kind == kFdSocket) {
handle = g_fds.p[fd].handle; handle = g_fds.p[fd].handle;
if ((rc = weaken(__ioctlsocket$nt)(handle, request, memory)) != -1) { if ((rc = weaken(__ioctlsocket$nt)(handle, request, memory)) != -1) {
return rc; return rc;

View File

@ -20,9 +20,5 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
bool isfdkind(int fd, enum FdKind kind) { bool isfdkind(int fd, enum FdKind kind) {
if (isfdindex(fd)) { return isfdindex(fd) && g_fds.p[fd].kind == kind;
return g_fds.p[fd].kind == kind;
} else {
return false;
}
} }

View File

@ -0,0 +1,24 @@
/*-*- 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"
bool isfdopen(int fd) {
return isfdindex(fd) && g_fds.p[fd].kind != kFdEmpty;
}

View File

@ -39,5 +39,4 @@ kTmpPath:
ezlea GetTempPathA$flunk,ax ezlea GetTempPathA$flunk,ax
call __getntsyspath call __getntsyspath
.init.end 300,_init_kTmpPath .init.end 300,_init_kTmpPath
.source __FILE__ .source __FILE__

View File

@ -22,6 +22,7 @@
#include "libc/calls/ntmagicpaths.h" #include "libc/calls/ntmagicpaths.h"
#include "libc/nexgen32e/tinystrcmp.h" #include "libc/nexgen32e/tinystrcmp.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/filetype.h" #include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/fsctl.h" #include "libc/nt/enum/fsctl.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
@ -38,7 +39,10 @@ static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
char16_t file16[PATH_MAX]; char16_t file16[PATH_MAX];
if (mkntpath2(file, flags, file16) == -1) return -1; if (mkntpath2(file, flags, file16) == -1) return -1;
if ((handle = CreateFile( if ((handle = CreateFile(
file16, (flags & 0xf000000f), file16,
(flags & 0xf000000f) | (/* this is needed if we mmap(rwx+cow)
nt is choosy about open() access */
kNtGenericExecute | kNtFileGenericWrite),
(flags & O_EXCL) (flags & O_EXCL)
? kNtFileShareExclusive ? kNtFileShareExclusive
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,

View File

@ -37,7 +37,7 @@ privileged uint32_t prot2nt(int prot, int flags) {
: HAS(prot, PROT_READ | PROT_WRITE) : HAS(prot, PROT_READ | PROT_WRITE)
? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS)) ? (HAS(flags, MAP_SHARED) || HAS(flags, MAP_ANONYMOUS))
? kNtPageReadwrite ? kNtPageReadwrite
: kNtPageWritecopy : kNtPageReadwrite /* kNtPageWritecopy */
: HAS(prot, PROT_READ | PROT_EXEC) : HAS(prot, PROT_READ | PROT_EXEC)
? kNtPageExecuteRead ? kNtPageExecuteRead
: HAS(prot, PROT_EXEC) : HAS(prot, PROT_EXEC)

View File

@ -17,12 +17,12 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/bits/safemacros.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/macros.h"
void removefd(int fd) { void removefd(int fd) {
if (isfdindex(fd)) { if (isfdopen(fd)) {
g_fds.p[fd].kind = kFdEmpty; g_fds.p[fd].kind = kFdEmpty;
g_fds.f = min(g_fds.f, fd); g_fds.f = MIN(g_fds.f, fd);
} }
} }

View File

@ -50,9 +50,6 @@ textwindows int utimensat$nt(int dirfd, const char *path,
} else { } else {
return einval(); return einval();
} }
} else if (isfdindex(dirfd)) {
fh = g_fds.p[dirfd].handle;
closeme = false;
} else { } else {
return ebadf(); return ebadf();
} }

View File

@ -61,6 +61,11 @@ o/$(MODE)/libc/conv/filetimetotimeval.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-O3 -O3
o/$(MODE)/libc/conv/itoa64radix10.greg.o \
o/$(MODE)/libc/conv/itoa128radix10.greg.o: \
OVERRIDE_CFLAGS += \
-fwrapv
$(LIBC_CONV_A_OBJS): \ $(LIBC_CONV_A_OBJS): \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
$(NO_MAGIC) $(NO_MAGIC)

View File

@ -16,17 +16,10 @@ COSMOPOLITAN_C_START_
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns) - uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) - int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns)
SLOWEST + GENERAL
- int64toarray(0x31337, a, 10) l: 218 (64ns) m: 262 (77ns)
- uint64toarray(0x31337, a, 10) l: 565 (166ns) m: 260 (76ns)
*/ */
size_t int64toarray_radix10(int64_t, char *); size_t int64toarray_radix10(int64_t, char[hasatleast 21]);
size_t uint64toarray_radix10(uint64_t, char *); size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
size_t int64toarray(int64_t, char *, int);
size_t uint64toarray(uint64_t, char *, int);
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]); size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t); size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);

View File

@ -48,15 +48,7 @@ noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
* @return bytes written w/o nul * @return bytes written w/o nul
*/ */
size_t int128toarray_radix10(int128_t i, char *a) { size_t int128toarray_radix10(int128_t i, char *a) {
if (i < 0) { if (i >= 0) return uint128toarray_radix10(i, a);
if (i != INT128_MIN) { *a++ = '-';
*a++ = '-'; return 1 + uint128toarray_radix10(-i, a);
return 1 + uint128toarray_radix10(-i, a);
} else {
memcpy(a, "-170141183460469231731687303715884105728", 41);
return 40;
}
} else {
return uint128toarray_radix10(i, a);
}
} }

View File

@ -45,15 +45,7 @@ noinline size_t uint64toarray_radix10(uint64_t i, char *a) {
* @return bytes written w/o nul * @return bytes written w/o nul
*/ */
size_t int64toarray_radix10(int64_t i, char *a) { size_t int64toarray_radix10(int64_t i, char *a) {
if (i < 0) { if (i >= 0) return uint64toarray_radix10(i, a);
if (i != INT64_MIN) { *a++ = '-';
*a++ = '-'; return 1 + uint64toarray_radix10(-i, a);
return 1 + uint64toarray_radix10(-i, a);
} else {
memcpy(a, "-9223372036854775808", 21);
return 20;
}
} else {
return uint64toarray_radix10(i, a);
}
} }

View File

@ -66,7 +66,7 @@
#endif #endif
#define BIGPAGESIZE 0x200000 #define BIGPAGESIZE 0x200000
#define STACKSIZE 0x20000 #define STACKSIZE 0x80000 /* todo: zlib's fault? */
#define FRAMESIZE 0x10000 /* 8086 */ #define FRAMESIZE 0x10000 /* 8086 */
#define PAGESIZE 0x1000 /* i386+ */ #define PAGESIZE 0x1000 /* i386+ */
#define BUFSIZ 0x1000 /* best stdio default */ #define BUFSIZ 0x1000 /* best stdio default */

View File

@ -31,6 +31,16 @@
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
/**
* Prints stack frames with symbols.
*
* PrintBacktraceUsingSymbols(stdout, NULL, getsymboltable());
*
* @param f is output stream
* @param bp is rbp which can be NULL to detect automatically
* @param st is open symbol table for current executable
* @return -1 w/ errno if error happened
*/
int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp, int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
struct SymbolTable *st) { struct SymbolTable *st) {
size_t gi; size_t gi;
@ -41,6 +51,7 @@ int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
const struct Symbol *symbol; const struct Symbol *symbol;
const struct StackFrame *frame; const struct StackFrame *frame;
if (!st) return -1; if (!st) return -1;
if (!bp) bp = __builtin_frame_address(0);
garbage = weaken(g_garbage); garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) { for (frame = bp; frame; frame = frame->next) {

View File

@ -33,27 +33,6 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/fileno.h"
static struct CanColor {
bool once;
bool result;
struct OldNtConsole {
unsigned codepage;
unsigned mode;
int64_t handle;
} oldin, oldout;
} g_cancolor;
static textwindows void restorecmdexe(void) {
if (g_cancolor.oldin.handle) {
SetConsoleCP(g_cancolor.oldin.codepage);
SetConsoleMode(g_cancolor.oldin.handle, g_cancolor.oldin.mode);
}
if (g_cancolor.oldout.handle) {
SetConsoleOutputCP(g_cancolor.oldout.codepage);
SetConsoleMode(g_cancolor.oldout.handle, g_cancolor.oldout.mode);
}
}
/** /**
* Returns true if ANSI terminal colors are appropriate. * Returns true if ANSI terminal colors are appropriate.
* *
@ -75,47 +54,20 @@ static textwindows void restorecmdexe(void) {
* It's that easy fam. * It's that easy fam.
*/ */
bool cancolor(void) { bool cancolor(void) {
int64_t handle; static bool once;
static bool result;
const char *term; const char *term;
if (g_cancolor.once) return g_cancolor.result; if (!once) {
g_cancolor.once = true; if (!result) {
if (IsWindows()) { if ((term = getenv("TERM"))) {
if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui && /* anything but emacs basically */
NtGetVersion() >= kNtVersionWindows10) { result = strcmp(term, "dumb") != 0;
atexit(restorecmdexe); } else {
if (GetFileType((handle = g_fds.p[STDIN_FILENO].handle)) == /* TODO(jart): Why does Mac bash login shell exec nuke TERM? */
kNtFileTypeChar) { result = IsXnu();
g_cancolor.result = true;
g_cancolor.oldin.handle = handle;
g_cancolor.oldin.codepage = GetConsoleCP();
SetConsoleCP(kNtCpUtf8);
GetConsoleMode(handle, &g_cancolor.oldin.mode);
SetConsoleMode(handle, g_cancolor.oldin.mode | kNtEnableProcessedInput |
kNtEnableVirtualTerminalInput);
}
if (GetFileType((handle = g_fds.p[STDOUT_FILENO].handle)) ==
kNtFileTypeChar ||
GetFileType((handle = g_fds.p[STDERR_FILENO].handle)) ==
kNtFileTypeChar) {
g_cancolor.result = true;
g_cancolor.oldout.handle = handle;
g_cancolor.oldout.codepage = GetConsoleOutputCP();
SetConsoleOutputCP(kNtCpUtf8);
GetConsoleMode(handle, &g_cancolor.oldout.mode);
SetConsoleMode(handle, g_cancolor.oldout.mode |
kNtEnableProcessedOutput |
kNtEnableVirtualTerminalProcessing);
} }
} }
once = true;
} }
if (!g_cancolor.result) { return result;
if ((term = getenv("TERM"))) {
/* anything but emacs basically */
g_cancolor.result = strcmp(term, "dumb") != 0;
} else {
/* TODO(jart): Why does Mac bash login shell exec nuke TERM? */
g_cancolor.result = IsXnu();
}
}
return g_cancolor.result;
} }

View File

@ -40,7 +40,7 @@ cescapec:
ret ret
.LHT: mov $'t,%ah .LHT: mov $'t,%ah
ret ret
.LLF: or $'n<<010|'\\<<020|'\n<<030,%eax .LLF: mov $'n,%ah
ret ret
.LVT: mov $'v,%ah .LVT: mov $'v,%ah
ret ret

View File

@ -100,10 +100,15 @@ MemCpy: .leafprologue
mov %ecx,(%rdi) mov %ecx,(%rdi)
mov %ebx,-4(%rdi,%rdx) mov %ebx,-4(%rdi,%rdx)
jmp 1b jmp 1b
.L3: mov 2(%rsi),%cl .L3: push %rbx
mov %cl,2(%rdi) mov (%rsi),%cx
.L2: mov 1(%rsi),%cl mov -2(%rsi,%rdx),%bx
mov %cl,1(%rdi) mov %cx,(%rdi)
mov %bx,-2(%rdi,%rdx)
jmp 1b
.L2: mov (%rsi),%cx
mov %cx,(%rdi)
jmp .L0
.L1: mov (%rsi),%cl .L1: mov (%rsi),%cl
mov %cl,(%rdi) mov %cl,(%rdi)
jmp .L0 jmp .L0

View File

@ -48,20 +48,20 @@
* @mode long,legacy,real * @mode long,legacy,real
*/ */
#define VIDYA_ROWS 25 #define VIDYA_ROWS 25
#define VIDYA_COLUMNS 80 #define VIDYA_COLUMNS 80
#define VIDYA_SIZE (VIDYA_ROWS * VIDYA_COLUMNS * 2) #define VIDYA_SIZE (VIDYA_ROWS * VIDYA_COLUMNS * 2)
#define VIDYA_MODE_MDA 7 #define VIDYA_MODE_MDA 7
#define VIDYA_MODE_CGA 3 #define VIDYA_MODE_CGA 3
#define VIDYA_ADDR_MDA 0xb0000 #define VIDYA_ADDR_MDA 0xb0000
#define VIDYA_ADDR_CGA 0xb8000 #define VIDYA_ADDR_CGA 0xb8000
#define VIDYA_ATTR_NORMAL 0x07 /* cozy default for both mda and cga */ #define VIDYA_ATTR_NORMAL 0x07 /* cozy default for both mda and cga */
#define VIDYA_REWIND ~0x7fff /* derived from mode addr min. lzcnt */ #define VIDYA_REWIND ~0x7fff /* derived from mode addr min. lzcnt */
#define VIDYA_SERVICE 0x10 #define VIDYA_SERVICE 0x10
#define VIDYA_SET_MODE 0 #define VIDYA_SET_MODE 0x0003
#define VIDYA_SET_CURSOR 0x0100 #define VIDYA_SET_CURSOR 0x0100
#define VIDYA_SET_CURSOR_NONE 0x2000 #define VIDYA_SET_CURSOR_NONE 0x2000
#define VIDYA_SET_BLINKING 0x1003 #define VIDYA_SET_BLINKING 0x1003
#define VIDYA_SET_BLINKING_NONE 0x0000 #define VIDYA_SET_BLINKING_NONE 0x0000
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)

View File

@ -5478,7 +5478,7 @@ imp 'RtlSetDaclSecurityDescriptor' RtlSetDaclSecurityDescriptor ntdll 138
imp 'RtlSetDynamicTimeZoneInformation' RtlSetDynamicTimeZoneInformation ntdll 1386 imp 'RtlSetDynamicTimeZoneInformation' RtlSetDynamicTimeZoneInformation ntdll 1386
imp 'RtlSetEnvironmentStrings' RtlSetEnvironmentStrings ntdll 1387 imp 'RtlSetEnvironmentStrings' RtlSetEnvironmentStrings ntdll 1387
imp 'RtlSetEnvironmentVar' RtlSetEnvironmentVar ntdll 1388 imp 'RtlSetEnvironmentVar' RtlSetEnvironmentVar ntdll 1388
imp 'RtlSetEnvironmentVariable' RtlSetEnvironmentVariable ntdll 1389 imp 'RtlSetEnvironmentVariable' RtlSetEnvironmentVariable ntdll 1389
imp 'RtlSetExtendedFeaturesMask' RtlSetExtendedFeaturesMask ntdll 1390 imp 'RtlSetExtendedFeaturesMask' RtlSetExtendedFeaturesMask ntdll 1390
imp 'RtlSetGroupSecurityDescriptor' RtlSetGroupSecurityDescriptor ntdll 1391 imp 'RtlSetGroupSecurityDescriptor' RtlSetGroupSecurityDescriptor ntdll 1391
imp 'RtlSetHeapInformation' RtlSetHeapInformation ntdll 1392 imp 'RtlSetHeapInformation' RtlSetHeapInformation ntdll 1392

View File

@ -1,11 +1,20 @@
#define GetConsoleMode(...) __imp_GetConsoleMode(__VA_ARGS__) #define GetConsoleMode(...) __imp_GetConsoleMode(__VA_ARGS__)
#define SetConsoleCP(...) __imp_SetConsoleCP(__VA_ARGS__)
#define SetConsoleCtrlHandler(...) __imp_SetConsoleCtrlHandler(__VA_ARGS__)
#define SetConsoleMode(...) __imp_SetConsoleMode(__VA_ARGS__)
#define SetConsoleOutputCP(...) __imp_SetConsoleOutputCP(__VA_ARGS__)
extern typeof(GetConsoleMode) *const __imp_GetConsoleMode __msabi; extern typeof(GetConsoleMode) *const __imp_GetConsoleMode __msabi;
#define SetConsoleCP(...) __imp_SetConsoleCP(__VA_ARGS__)
extern typeof(SetConsoleCP) *const __imp_SetConsoleCP __msabi; extern typeof(SetConsoleCP) *const __imp_SetConsoleCP __msabi;
#define GetConsoleCP(...) __imp_GetConsoleCP(__VA_ARGS__)
extern typeof(GetConsoleCP) *const __imp_GetConsoleCP __msabi;
#define SetConsoleCtrlHandler(...) __imp_SetConsoleCtrlHandler(__VA_ARGS__)
extern typeof(SetConsoleCtrlHandler) *const __imp_SetConsoleCtrlHandler __msabi; extern typeof(SetConsoleCtrlHandler) *const __imp_SetConsoleCtrlHandler __msabi;
#define SetConsoleMode(...) __imp_SetConsoleMode(__VA_ARGS__)
extern typeof(SetConsoleMode) *const __imp_SetConsoleMode __msabi; extern typeof(SetConsoleMode) *const __imp_SetConsoleMode __msabi;
#define SetConsoleOutputCP(...) __imp_SetConsoleOutputCP(__VA_ARGS__)
extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP __msabi; extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP __msabi;
#define GetConsoleOutputCP(...) __imp_GetConsoleOutputCP(__VA_ARGS__)
extern typeof(GetConsoleOutputCP) *const __imp_GetConsoleOutputCP __msabi;

View File

@ -1,5 +1,8 @@
#define CopyFile(...) __imp_CopyFileW(__VA_ARGS__) #define CopyFile(...) __imp_CopyFileW(__VA_ARGS__)
#define FlushFileBuffers(...) __imp_FlushFileBuffers(__VA_ARGS__)
extern typeof(CopyFile) *const __imp_CopyFileW __msabi; extern typeof(CopyFile) *const __imp_CopyFileW __msabi;
#define FlushFileBuffers(...) __imp_FlushFileBuffers(__VA_ARGS__)
extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers __msabi; extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers __msabi;
#define GetFileType(...) __imp_GetFileType(__VA_ARGS__)
extern typeof(GetFileType) *const __imp_GetFileType __msabi;

View File

@ -18,6 +18,7 @@
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/macros.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/directmap.h" #include "libc/runtime/directmap.h"
@ -25,14 +26,21 @@
static textwindows struct DirectMap DirectMapNt(void *addr, size_t size, static textwindows struct DirectMap DirectMapNt(void *addr, size_t size,
unsigned prot, unsigned flags, unsigned prot, unsigned flags,
int fd, int64_t off) { int fd, int64_t off) {
int64_t handle;
struct DirectMap res; struct DirectMap res;
if ((res.maphandle = CreateFileMappingNuma( uint32_t protect, access;
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue, if (fd != -1) {
&kNtIsInheritable, prot2nt(prot, flags), size >> 32, size, NULL, handle = g_fds.p[fd].handle;
kNtNumaNoPreferredNode))) { } else {
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, fprot2nt(prot, flags), handle = kNtInvalidHandleValue;
off >> 32, off, size, addr, }
kNtNumaNoPreferredNode))) { protect = prot2nt(prot, flags);
access = fprot2nt(prot, flags);
if ((res.maphandle =
CreateFileMappingNuma(handle, &kNtIsInheritable, protect, size >> 32,
size, NULL, kNtNumaNoPreferredNode))) {
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, access, off >> 32, off,
size, addr, kNtNumaNoPreferredNode))) {
CloseHandle(res.maphandle); CloseHandle(res.maphandle);
res.maphandle = kNtInvalidHandleValue; res.maphandle = kNtInvalidHandleValue;
res.addr = (void *)(intptr_t)winerr(); res.addr = (void *)(intptr_t)winerr();

View File

@ -20,6 +20,8 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/notice.inc" #include "libc/notice.inc"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/map.h"
#include "libc/dce.h" #include "libc/dce.h"
.text.startup .text.startup
.source __FILE__ .source __FILE__
@ -40,12 +42,15 @@ _executive:
mov %rdx,%r14 mov %rdx,%r14
mov %rcx,%r15 mov %rcx,%r15
call _spawn call _spawn
mov %r12,%rdi call _getstack
mov %r13,%rsi mov %rax,%rdi
mov %r14,%rdx
mov %r15,%rcx
.weak main .weak main
call main mov $main,%esi
mov %r12,%rdx
mov %r13,%rcx
mov %r14,%r8
mov %r15,%r9
call _setstack
mov %eax,%edi mov %eax,%edi
call exit call exit
9: .endfn _executive,weak,hidden 9: .endfn _executive,weak,hidden

View File

@ -34,9 +34,9 @@ int mapfileread(const char *filename, struct MappedFile *mf) {
mf->addr = MAP_FAILED; mf->addr = MAP_FAILED;
if ((mf->fd = open(filename, O_RDONLY)) != -1 && if ((mf->fd = open(filename, O_RDONLY)) != -1 &&
(mf->size = getfiledescriptorsize(mf->fd)) < INT_MAX && (mf->size = getfiledescriptorsize(mf->fd)) < INT_MAX &&
(mf->addr = mf->size (mf->addr = mf->size ? mmap(NULL, mf->size, PROT_READ,
? mmap(NULL, mf->size, PROT_READ, MAP_SHARED, mf->fd, 0) MAP_PRIVATE | MAP_POPULATE, mf->fd, 0)
: NULL) != MAP_FAILED) { : NULL) != MAP_FAILED) {
return 0; return 0;
} else { } else {
unmapfile(mf); unmapfile(mf);
@ -50,7 +50,7 @@ int mapfileread(const char *filename, struct MappedFile *mf) {
int unmapfile(struct MappedFile *mf) { int unmapfile(struct MappedFile *mf) {
int rc; int rc;
rc = 0; rc = 0;
if (mf->addr != MAP_FAILED) { if (mf->addr && mf->addr != MAP_FAILED) {
rc |= munmap(mf->addr, mf->size); rc |= munmap(mf->addr, mf->size);
mf->addr = MAP_FAILED; mf->addr = MAP_FAILED;
} }

View File

@ -0,0 +1,36 @@
/*-*- 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/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
/**
* Allocates deterministic stack for process.
* @see _executive()
*/
void *_getstack(void) {
char *p;
p = mmap((char *)0x700000000000 - STACKSIZE, STACKSIZE,
PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1,
0);
if (p == MAP_FAILED) abort();
return p + STACKSIZE;
}

View File

@ -12,8 +12,8 @@ struct MemoryIntervals {
struct MemoryInterval { struct MemoryInterval {
int x; int x;
int y; int y;
} p[32]; } p[64];
long h[32]; long h[64];
}; };
extern struct MemoryIntervals _mmi; extern struct MemoryIntervals _mmi;

View File

@ -44,6 +44,10 @@ struct MemoryIntervals _mmi;
/** /**
* Beseeches system for page-table entries. * Beseeches system for page-table entries.
* *
* char *p = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
* MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
* munmap(p, 65536);
*
* @param addr optionally requests a particular virtual base address, * @param addr optionally requests a particular virtual base address,
* which needs to be 64kb aligned if passed (for NT compatibility) * which needs to be 64kb aligned if passed (for NT compatibility)
* @param size must be >0 and needn't be a multiple of FRAMESIZE * @param size must be >0 and needn't be a multiple of FRAMESIZE
@ -82,8 +86,6 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
} }
addr = (void *)(intptr_t)((int64_t)x << 16); addr = (void *)(intptr_t)((int64_t)x << 16);
} }
assert((flags & MAP_FIXED) ||
(!isheap(addr) && !isheap((char *)addr + size - 1)));
dm = DirectMap(addr, size, prot, flags | MAP_FIXED, fd, off); dm = DirectMap(addr, size, prot, flags | MAP_FIXED, fd, off);
if (dm.addr == MAP_FAILED || dm.addr != addr) { if (dm.addr == MAP_FAILED || dm.addr != addr) {
return MAP_FAILED; return MAP_FAILED;

View File

@ -25,16 +25,14 @@
textwindows int msync$nt(void *addr, size_t size, int flags) { textwindows int msync$nt(void *addr, size_t size, int flags) {
int x, y, l, r, i; int x, y, l, r, i;
if (!FlushViewOfFile(addr, size)) return winerr(); x = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;
x = (intptr_t)addr >> 16; y = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16;
y = x + (ROUNDUP(size, 65536) >> 16) - 1; for (i = FindMemoryInterval(&_mmi, x); i < _mmi.i; ++i) {
l = FindMemoryInterval(&_mmi, x); if ((x >= _mmi.p[i].x && x <= _mmi.p[i].y) ||
r = FindMemoryInterval(&_mmi, y); (y >= _mmi.p[i].x && y <= _mmi.p[i].y)) {
if (l && x <= _mmi.p[l - 1].y) --l; FlushFileBuffers(_mmi.h[i]);
if (r && y <= _mmi.p[r - 1].y) --r; } else {
if (l < _mmi.i) { break;
for (i = l; i <= r; --i) {
FlushFileBuffers(_mmi.h[i - 1]);
} }
} }
return 0; return 0;

View File

@ -44,6 +44,7 @@ void exit(int) noreturn;
void quick_exit(int) noreturn; void quick_exit(int) noreturn;
void _exit(int) libcesque noreturn; void _exit(int) libcesque noreturn;
void _Exit(int) libcesque noreturn; void _Exit(int) libcesque noreturn;
long _setstack(void *, void *, ...);
void abort(void) noreturn noinstrument; void abort(void) noreturn noinstrument;
void panic(void) noreturn noinstrument privileged; void panic(void) noreturn noinstrument privileged;
void triplf(void) noreturn noinstrument privileged; void triplf(void) noreturn noinstrument privileged;

View File

@ -69,6 +69,8 @@ o/$(MODE)/libc/runtime/winmain.greg.o: \
DEFAULT_CPPFLAGS += \ DEFAULT_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED -DSTACK_FRAME_UNLIMITED
o/$(MODE)/libc/runtime/main-gcc.asm: OVERRIDE_CFLAGS += -ffixed-r12 -ffixed-r13 -ffixed-r14 -ffixed-r15
LIBC_RUNTIME_LIBS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x))) LIBC_RUNTIME_LIBS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)))
LIBC_RUNTIME_SRCS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_SRCS)) LIBC_RUNTIME_SRCS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_SRCS))
LIBC_RUNTIME_HDRS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_HDRS)) LIBC_RUNTIME_HDRS = $(foreach x,$(LIBC_RUNTIME_ARTIFACTS),$($(x)_HDRS))

View File

@ -17,30 +17,30 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/dce.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/nr.h"
#include "libc/macros.h" #include "libc/macros.h"
.text.startup
.source __FILE__
/ Merges page table entries for pages with identical content. / Switches stack.
/ /
/ This is a hint. It can help trim physical memory for things / @param rdi is new rsp, passed as malloc(size) + size
/ like extremely sparse data. / @param rsi is function to call in new stack space
/ / @param rdx,rcx,r8,r9 get passed as args to rsi
/ @param rdi is base address / @return happens on original stack
/ @param rsi is byte length _setstack:
mergepages: push %rbp
.leafprologue mov %rsp,%rbp
.profilable push %rbx
mov $-PAGESIZE,%rax mov %rsp,%rbx
and %rax,%rdi mov %rdi,%rsp
and %rax,%rsi push 16(%rbx)
mov __NR_madvise,%eax push 8(%rbx)
mov MADV_MERGEABLE,%edx mov %rsi,%rax
test %edx,%edx mov %rdx,%rdi
jz 1f mov %rcx,%rsi
syscall mov %r8,%rdx
1: .leafepilogue mov %r9,%rcx
.endfn mergepages,globl call *%rax
mov %rbx,%rsp
pop %rbx
pop %rbp
ret
.endfn _setstack,globl

View File

@ -19,15 +19,32 @@
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/pushpop.h" #include "libc/bits/pushpop.h"
#include "libc/bits/weaken.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/nt/console.h" #include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/loadlibrarysearch.h" #include "libc/nt/enum/loadlibrarysearch.h"
#include "libc/nt/files.h"
#include "libc/nt/pedef.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/getdosenviron.h" #include "libc/runtime/getdosenviron.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/missioncritical.h" #include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
static void LoadFasterAndPreventHijacking(void) { static struct CmdExe {
bool result;
struct OldNtConsole {
unsigned codepage;
unsigned mode;
int64_t handle;
} oldin, oldout;
} g_cmdexe;
static textwindows void MitigateDriveByDownloads(void) {
unsigned wrote; unsigned wrote;
if (!SetDefaultDllDirectories(kNtLoadLibrarySearchSearchSystem32)) { if (!SetDefaultDllDirectories(kNtLoadLibrarySearchSearchSystem32)) {
WriteFile(GetStdHandle(kNtStdErrorHandle), "nodll\n", 6, &wrote, NULL); WriteFile(GetStdHandle(kNtStdErrorHandle), "nodll\n", 6, &wrote, NULL);
@ -35,6 +52,78 @@ static void LoadFasterAndPreventHijacking(void) {
} }
} }
static textwindows void RestoreCmdExe(void) {
if (g_cmdexe.oldin.handle) {
SetConsoleCP(g_cmdexe.oldin.codepage);
SetConsoleMode(g_cmdexe.oldin.handle, g_cmdexe.oldin.mode);
}
if (g_cmdexe.oldout.handle) {
SetConsoleOutputCP(g_cmdexe.oldout.codepage);
SetConsoleMode(g_cmdexe.oldout.handle, g_cmdexe.oldout.mode);
}
}
static textwindows void SetTrueColor(void) {
SetEnvironmentVariable(u"TERM", u"xterm-truecolor");
}
static textwindows void NormalizeCmdExe(void) {
int64_t handle, hstdin, hstdout, hstderr;
if ((int)weakaddr("v_ntsubsystem") == kNtImageSubsystemWindowsCui &&
NtGetVersion() >= kNtVersionWindows10) {
atexit(RestoreCmdExe);
hstdin = GetStdHandle(pushpop(kNtStdInputHandle));
hstdout = GetStdHandle(pushpop(kNtStdOutputHandle));
hstderr = GetStdHandle(pushpop(kNtStdErrorHandle));
if (GetFileType((handle = hstdin)) == kNtFileTypeChar) {
SetTrueColor();
g_cmdexe.oldin.handle = handle;
g_cmdexe.oldin.codepage = GetConsoleCP();
SetConsoleCP(kNtCpUtf8);
GetConsoleMode(handle, &g_cmdexe.oldin.mode);
SetConsoleMode(handle, g_cmdexe.oldin.mode | kNtEnableProcessedInput |
kNtEnableVirtualTerminalInput);
}
if (GetFileType((handle = hstdout)) == kNtFileTypeChar ||
GetFileType((handle = hstderr)) == kNtFileTypeChar) {
SetTrueColor();
g_cmdexe.oldout.handle = handle;
g_cmdexe.oldout.codepage = GetConsoleOutputCP();
SetConsoleOutputCP(kNtCpUtf8);
GetConsoleMode(handle, &g_cmdexe.oldout.mode);
SetConsoleMode(handle, g_cmdexe.oldout.mode | kNtEnableProcessedOutput |
kNtEnableVirtualTerminalProcessing);
}
}
}
/**
* Main function on Windows NT.
*
* The Cosmopolitan Runtime provides the following services, which aim
* to bring Windows NT behavior closer in harmony with System Five:
*
* 1. We configure CMD.EXE for UTF-8 and enable ANSI colors on Win10.
*
* 2. Command line arguments are passed as a blob of UTF-16 text. We
* chop them up into an char *argv[] UTF-8 data structure, in
* accordance with the DOS conventions for argument quoting.
*
* 3. Environment variables are passed to us as a sorted UTF-16 double
* NUL terminated list. We translate this to char ** using UTF-8.
*
* 4. NT likes to choose a stack address that's beneath the program
* image. We want to be able to assume that stack addresses are
* located at higher addresses than heap and program memory. So the
* _executive() function will switch stacks appropriately.
*
* 5. Windows users are afraid of "drive-by downloads" where someone
* might accidentally an evil DLL to their Downloads folder which
* then overrides the behavior of a legitimate EXE being run from
* the downloads folder. Since we don't even use dynamic linking,
* we've cargo culted some API calls, that may harden against it.
*
*/
textwindows int WinMain(void *hInstance, void *hPrevInstance, textwindows int WinMain(void *hInstance, void *hPrevInstance,
const char *lpCmdLine, int nCmdShow) { const char *lpCmdLine, int nCmdShow) {
int i, count; int i, count;
@ -42,7 +131,8 @@ textwindows int WinMain(void *hInstance, void *hPrevInstance,
char *argarray[512], *envarray[512]; char *argarray[512], *envarray[512];
char argblock[ARG_MAX], envblock[ENV_MAX]; char argblock[ARG_MAX], envblock[ENV_MAX];
long auxarray[][2] = {{pushpop(0L), pushpop(0L)}}; long auxarray[][2] = {{pushpop(0L), pushpop(0L)}};
LoadFasterAndPreventHijacking(); MitigateDriveByDownloads();
NormalizeCmdExe();
*(/*unconst*/ int *)&hostos = WINDOWS; *(/*unconst*/ int *)&hostos = WINDOWS;
cmd16 = GetCommandLine(); cmd16 = GetCommandLine();
env16 = GetEnvironmentStrings(); env16 = GetEnvironmentStrings();

View File

@ -23,7 +23,5 @@
* Returns number of bytes available in stream buffer. * Returns number of bytes available in stream buffer.
*/ */
unsigned favail(FILE *f) { unsigned favail(FILE *f) {
if (f->beg == f->end) return f->size; return ((f->end - f->beg - 1) & (f->size - 1)) + 1;
if (f->end > f->beg) return f->end - f->beg;
return (f->size - f->beg) + f->end;
} }

View File

@ -17,8 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/calls/calls.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/macros.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/** /**
* Writes string to stream. * Writes string to stream.
@ -32,15 +35,14 @@
* @return strlen(s) or -1 w/ errno on error * @return strlen(s) or -1 w/ errno on error
*/ */
int fputs(const char *s, FILE *f) { int fputs(const char *s, FILE *f) {
unsigned char *p = (unsigned char *)s; int i, n, m;
int res = 0; n = strlen(s);
while (*p) { for (i = 0; i < n; ++i) {
if (fputc(*p++, f) == -1) { if (fputc(s[i], f) == -1) {
if (ferror(f) == EINTR) continue; if (ferror(f) == EINTR) continue;
if (feof(f)) errno = f->state = EPIPE; if (feof(f)) errno = f->state = EPIPE;
return -1; return -1;
} }
++res;
} }
return ++res; return n;
} }

View File

@ -28,7 +28,6 @@ LIBC_STDIO_A_DIRECTDEPS = \
LIBC_ALG \ LIBC_ALG \
LIBC_BITS \ LIBC_BITS \
LIBC_CALLS \ LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_CONV \ LIBC_CONV \
LIBC_ESCAPE \ LIBC_ESCAPE \
LIBC_FMT \ LIBC_FMT \

View File

@ -26,6 +26,13 @@
* @see getline * @see getline
*/ */
char *(chomp)(char *line) { char *(chomp)(char *line) {
if (line) line[strcspn(line, "\r\n")] = '\0'; size_t i;
for (i = strlen(line); i--;) {
if (line[i] == '\r' || line[i] == '\n') {
line[i] = '\0';
} else {
break;
}
}
return line; return line;
} }

View File

@ -26,6 +26,6 @@
* @see getline * @see getline
*/ */
char16_t *chomp16(char16_t *line) { char16_t *chomp16(char16_t *line) {
if (line) line[strcspn(line, u"\r\n")] = '\0'; if (line) line[strcspn16(line, u"\r\n")] = '\0';
return line; return line;
} }

View File

@ -283,24 +283,6 @@ extern int (*const hook$wcsncmp)(const wchar_t *, const wchar_t *, size_t);
#if __STDC_VERSION__ + 0 >= 201112 #if __STDC_VERSION__ + 0 >= 201112
#define strstr(haystack, needle) \
_Generic(*(haystack), wchar_t \
: wcsstr, char16_t \
: strstr16, default \
: strstr)(haystack, needle)
#define strrchr(s, c) \
_Generic(*(s), wchar_t \
: wcsrchr, char16_t \
: strrchr16, default \
: strrchr)(s, c)
#define strchrnul(s, c) \
_Generic(*(s), wchar_t \
: wcschrnul, char16_t \
: strchrnul16, default \
: strchrnul)(s, c)
#define strnlen(s, n) \ #define strnlen(s, n) \
_Generic(*(s), wchar_t \ _Generic(*(s), wchar_t \
: wcsnlen, char16_t \ : wcsnlen, char16_t \

View File

@ -23,6 +23,9 @@
/** /**
* Returns prefix length, consisting of chars not in reject. * Returns prefix length, consisting of chars not in reject.
* a.k.a. Return index of first byte that's in charset. * a.k.a. Return index of first byte that's in charset.
*
* @param reject is nul-terminated character set
* @see strspn(), strtok_r()
* @asyncsignalsafe * @asyncsignalsafe
*/ */
size_t(strcspn)(const char *s, const char *reject) { size_t(strcspn)(const char *s, const char *reject) {

View File

@ -35,13 +35,13 @@
char *(strstr)(const char *haystack, const char *needle) { char *(strstr)(const char *haystack, const char *needle) {
if (needle[0]) { if (needle[0]) {
if (needle[1]) { if (needle[1]) {
if (!((intptr_t)needle & 0xf) && X86_HAVE(SSE4_2) && !IsTiny()) { if (!((intptr_t)needle & 0xf) && X86_HAVE(SSE4_2)) {
return strstr$sse42(haystack, needle); return strstr$sse42(haystack, needle);
} else { } else {
size_t needlelen; size_t needlelen;
alignas(16) char needle2[64]; alignas(16) char needle2[64];
needlelen = strlen(needle); needlelen = strlen(needle);
if (needlelen < 64 && X86_HAVE(SSE4_2) && !IsTiny()) { if (needlelen < 64 && X86_HAVE(SSE4_2)) {
memcpy(needle2, needle, (needlelen + 1) * sizeof(char)); memcpy(needle2, needle, (needlelen + 1) * sizeof(char));
return strstr$sse42(haystack, needle2); return strstr$sse42(haystack, needle2);
} else { } else {

View File

@ -26,6 +26,6 @@
* @see getline * @see getline
*/ */
wchar_t *wchomp(wchar_t *line) { wchar_t *wchomp(wchar_t *line) {
if (line) line[strcspn(line, L"\r\n")] = '\0'; if (line) line[wcscspn(line, L"\r\n")] = '\0';
return line; return line;
} }

View File

@ -247,7 +247,7 @@ syscon mmap MAP_HUGE_MASK 63 0 0 0 0
syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0
syscon mmap MAP_LOCKED 0x2000 0 0 0 0 syscon mmap MAP_LOCKED 0x2000 0 0 0 0
syscon mmap MAP_NONBLOCK 0x010000 0 0 0 0 syscon mmap MAP_NONBLOCK 0x010000 0 0 0 0
syscon mmap MAP_POPULATE 0x8000 0 0 0 0 syscon mmap MAP_POPULATE 0x8000 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
syscon mmap MAP_TYPE 15 0 0 0 0 # what is it syscon mmap MAP_TYPE 15 0 0 0 0 # what is it
syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 # ignored syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 # ignored
syscon compat MAP_DENYWRITE 0x0800 0 0 0 0 syscon compat MAP_DENYWRITE 0x0800 0 0 0 0
@ -301,8 +301,8 @@ syscon mprot PROT_NONE 0 0 0 0 0 # unix consensus (nt needs special
syscon mprot PROT_READ 1 1 1 1 1 # unix consensus 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_WRITE 2 2 2 2 2 # unix consensus
syscon mprot PROT_EXEC 4 4 4 4 4 # unix consensus syscon mprot PROT_EXEC 4 4 4 4 4 # unix consensus
syscon mprot PROT_GROWSDOWN 0x01000000 0 0 0 0x01000000 # bsd 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 syscon mprot PROT_GROWSUP 0x02000000 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap()
syscon mremap MREMAP_MAYMOVE 1 1 1 1 1 # faked non-linux (b/c linux only) syscon mremap MREMAP_MAYMOVE 1 1 1 1 1 # faked non-linux (b/c linux only)
syscon mremap MREMAP_FIXED 2 2 2 2 2 # faked non-linux (b/c linux only) syscon mremap MREMAP_FIXED 2 2 2 2 2 # faked non-linux (b/c linux only)
@ -320,6 +320,28 @@ syscon access X_OK 1 1 1 1 0xa0000000 # unix consensus and kNtGener
syscon access W_OK 2 2 2 2 0x40000000 # unix consensus and kNtGenericWrite syscon access W_OK 2 2 2 2 0x40000000 # unix consensus and kNtGenericWrite
syscon access R_OK 4 4 4 4 0x80000000 # unix consensus and kNtGenericRead syscon access R_OK 4 4 4 4 0x80000000 # unix consensus and kNtGenericRead
# flock() flags
#
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
syscon lock LOCK_SH 1 1 1 1 0 # shared [unix consensus]
syscon lock LOCK_EX 2 2 2 2 2 # exclusive [consensus!]
syscon lock LOCK_NB 4 4 4 4 1 # non-blocking [unix consensus]
syscon lock LOCK_UN 8 8 8 8 8 # unlock [unix consensus & faked NT]
# waitpid() / wait4() options
#
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
syscon waitpid WNOHANG 1 1 1 1 0 # unix consensus
syscon waitpid WUNTRACED 2 2 2 2 0 # unix consensus
syscon waitpid WCONTINUED 8 0x10 4 8 0
# waitid() options
#
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
syscon waitid WEXITED 4 4 0x10 0 0
syscon waitid WSTOPPED 2 8 2 0 0
syscon waitid WNOWAIT 0x01000000 0x20 8 0 0
# stat::st_mode constants # stat::st_mode constants
# #
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
@ -1049,7 +1071,6 @@ syscon af AF_VSOCK 40 0 0 0 0
syscon af AF_KCM 41 0 0 0 0 syscon af AF_KCM 41 0 0 0 0
syscon af AF_MAX 42 40 42 36 35 syscon af AF_MAX 42 40 42 36 35
syscon pf PF_UNIX 1 1 1 1 1 # consensus syscon pf PF_UNIX 1 1 1 1 1 # consensus
syscon pf PF_UNSPEC 0 0 0 0 0 # consensus syscon pf PF_UNSPEC 0 0 0 0 0 # consensus
syscon pf PF_APPLETALK 5 0x10 0x10 0x10 0x10 # bsd consensus syscon pf PF_APPLETALK 5 0x10 0x10 0x10 0x10 # bsd consensus
@ -1862,6 +1883,7 @@ syscon misc LC_MONETARY_MASK 0x10 0 4 8 0
syscon misc LC_MESSAGES_MASK 0x20 0 0x20 0x40 0 syscon misc LC_MESSAGES_MASK 0x20 0 0x20 0x40 0
syscon misc LC_ALL_MASK 0x1fbf 0 63 126 0 syscon misc LC_ALL_MASK 0x1fbf 0 63 126 0
syscon lock LOCK_UNLOCK_CACHE 54 0 0 0 0 # wut
syscon ptrace PTRACE_GETREGSET 0x4204 0 0 0 0 syscon ptrace PTRACE_GETREGSET 0x4204 0 0 0 0
syscon ptrace PTRACE_GETSIGMASK 0x420a 0 0 0 0 syscon ptrace PTRACE_GETSIGMASK 0x420a 0 0 0 0
@ -1894,12 +1916,6 @@ syscon misc IP6F_MORE_FRAG 0x0100 0x0100 0x0100 0x0100 0x0100 # con
syscon misc IP6F_OFF_MASK 0xf8ff 0xf8ff 0xf8ff 0xf8ff 0xf8ff # consensus syscon misc IP6F_OFF_MASK 0xf8ff 0xf8ff 0xf8ff 0xf8ff 0xf8ff # consensus
syscon misc IP6F_RESERVED_MASK 0x0600 0x0600 0x0600 0x0600 0x0600 # consensus syscon misc IP6F_RESERVED_MASK 0x0600 0x0600 0x0600 0x0600 0x0600 # consensus
syscon lock LOCK_SH 1 1 1 1 0 # unix consensus
syscon lock LOCK_EX 2 2 2 2 2 # consensus!
syscon lock LOCK_NB 4 4 4 4 1 # unix consensus
syscon lock LOCK_UN 8 8 8 8 8 # unix consensus & faked NT
syscon lock LOCK_UNLOCK_CACHE 54 0 0 0 0
syscon misc NO_SENSE 0 0 0 0 0 # consensus syscon misc NO_SENSE 0 0 0 0 0 # consensus
syscon misc NO_ADDRESS 4 4 4 4 0x2afc # unix consensus syscon misc NO_ADDRESS 4 4 4 4 0x2afc # unix consensus
syscon misc NO_DATA 4 4 4 4 0x2afc # unix consensus syscon misc NO_DATA 4 4 4 4 0x2afc # unix consensus
@ -2025,9 +2041,9 @@ syscon misc RTLD_NOLOAD 4 0x10 0x2000 0 0
syscon misc RTLD_DI_LINKMAP 0 0 2 0 0 syscon misc RTLD_DI_LINKMAP 0 0 2 0 0
syscon misc RTLD_LOCAL 0 4 0 0 0 syscon misc RTLD_LOCAL 0 4 0 0 0
syscon misc RUSAGE_SELF 0 0 0 0 0 # unix consensus & faked nt syscon rusage RUSAGE_SELF 0 0 0 0 0 # unix consensus & faked nt
syscon misc RUSAGE_CHILDREN -1 -1 -1 -1 99 # unix consensus & unavailable on nt syscon rusage RUSAGE_CHILDREN -1 -1 -1 -1 99 # unix consensus & unavailable on nt
syscon misc RUSAGE_THREAD 1 99 1 1 1 # faked nt & unavailable on xnu syscon rusage RUSAGE_THREAD 1 99 1 1 1 # faked nt & unavailable on xnu
syscon misc FSETLOCKING_QUERY 0 0 0 0 0 # consensus syscon misc FSETLOCKING_QUERY 0 0 0 0 0 # consensus
syscon misc FSETLOCKING_BYCALLER 2 0 0 0 0 syscon misc FSETLOCKING_BYCALLER 2 0 0 0 0
@ -2315,10 +2331,8 @@ syscon misc TUEXEC 0x40 0x40 0x40 0x40 0 # unix consensus
syscon misc TUREAD 0x0100 0x0100 0x0100 0x0100 0 # unix consensus syscon misc TUREAD 0x0100 0x0100 0x0100 0x0100 0 # unix consensus
syscon misc TUWRITE 0x80 0x80 0x80 0x80 0 # unix consensus syscon misc TUWRITE 0x80 0x80 0x80 0x80 0 # unix consensus
syscon misc TVERSLEN 2 2 2 2 0 # unix consensus syscon misc TVERSLEN 2 2 2 2 0 # unix consensus
syscon misc WNOHANG 1 1 1 1 0 # unix consensus
syscon misc WORD_BIT 0x20 0x20 0x20 0x20 0 # unix consensus syscon misc WORD_BIT 0x20 0x20 0x20 0x20 0 # unix consensus
syscon misc WRQ 2 2 2 2 0 # unix consensus syscon misc WRQ 2 2 2 2 0 # unix consensus
syscon misc WUNTRACED 2 2 2 2 0 # unix consensus
syscon misc SIGEV_THREAD 2 3 2 0 0 syscon misc SIGEV_THREAD 2 3 2 0 0
syscon misc SIGEV_SIGNAL 0 1 1 0 0 syscon misc SIGEV_SIGNAL 0 1 1 0 0
syscon misc SIGEV_NONE 1 0 0 0 0 syscon misc SIGEV_NONE 1 0 0 0 0
@ -2757,10 +2771,6 @@ syscon misc TSS_DTOR_ITERATIONS 0 0 4 0 0
syscon misc TTY_NAME_MAX 0x20 0 0 260 0 syscon misc TTY_NAME_MAX 0x20 0 0 260 0
syscon misc UIO_MAXIOV 0x0400 0 0 0x0400 0 syscon misc UIO_MAXIOV 0x0400 0 0 0x0400 0
syscon misc USER_PROCESS 7 7 4 0 0 syscon misc USER_PROCESS 7 7 4 0 0
syscon misc WCONTINUED 8 0x10 4 8 0
syscon misc WEXITED 4 4 0x10 0 0
syscon misc WNOWAIT 0x01000000 0x20 8 0 0
syscon misc WSTOPPED 2 8 2 0 0
syscon misc YESEXPR 0x050000 52 52 47 0 syscon misc YESEXPR 0x050000 52 52 47 0
syscon misc YESSTR 0x050002 54 54 46 0 syscon misc YESSTR 0x050002 54 54 46 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon mprot PROT_GROWSDOWN 0x01000000 0 0 0 0x01000000 .syscon mprot PROT_GROWSDOWN 0x01000000 0 0 0 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc RUSAGE_CHILDREN -1 -1 -1 -1 99 .syscon rusage RUSAGE_CHILDREN -1 -1 -1 -1 99

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc RUSAGE_SELF 0 0 0 0 0 .syscon rusage RUSAGE_SELF 0 0 0 0 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc RUSAGE_THREAD 1 99 1 1 1 .syscon rusage RUSAGE_THREAD 1 99 1 1 1

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc WCONTINUED 8 0x10 4 8 0 .syscon waitpid WCONTINUED 8 0x10 4 8 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc WEXITED 4 4 0x10 0 0 .syscon waitid WEXITED 4 4 0x10 0 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc WNOHANG 1 1 1 1 0 .syscon waitpid WNOHANG 1 1 1 1 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc WNOWAIT 0x01000000 0x20 8 0 0 .syscon waitid WNOWAIT 0x01000000 0x20 8 0 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc WSTOPPED 2 8 2 0 0 .syscon waitid WSTOPPED 2 8 2 0 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .include "libc/sysv/consts/syscon.inc"
.syscon misc WUNTRACED 2 2 2 2 0 .syscon waitpid WUNTRACED 2 2 2 2 0

View File

@ -27,10 +27,10 @@ hidden extern const long MAP_TYPE;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#define MAP_FILE LITERALLY(0) #define MAP_FILE 0
#define MAP_SHARED LITERALLY(1) #define MAP_SHARED 1
#define MAP_PRIVATE LITERALLY(2) #define MAP_PRIVATE 2
#define MAP_FIXED LITERALLY(16) #define MAP_FIXED 16
#define MAP_32BIT SYMBOLIC(MAP_32BIT) #define MAP_32BIT SYMBOLIC(MAP_32BIT)
#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS) #define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS)

View File

@ -2,14 +2,16 @@
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_W_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_W_H_
#include "libc/runtime/symbolic.h" #include "libc/runtime/symbolic.h"
#define WNOHANG SYMBOLIC(WNOHANG) #define WNOHANG SYMBOLIC(WNOHANG)
#define WUNTRACED SYMBOLIC(WUNTRACED) #define WUNTRACED SYMBOLIC(WUNTRACED)
#define WCONTINUED SYMBOLIC(WCONTINUED)
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
hidden extern const long WNOHANG; hidden extern const long WNOHANG;
hidden extern const long WUNTRACED; hidden extern const long WUNTRACED;
hidden extern const long WCONTINUED;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View File

@ -35,6 +35,7 @@ STATIC_YOINK("ntoa");
*/ */
static char *xiso8601$impl(struct timespec *opt_ts, int sswidth) { static char *xiso8601$impl(struct timespec *opt_ts, int sswidth) {
char *p;
struct tm tm; struct tm tm;
struct timespec ts; struct timespec ts;
int64_t sec, subsec; int64_t sec, subsec;
@ -60,7 +61,8 @@ static char *xiso8601$impl(struct timespec *opt_ts, int sswidth) {
localtime_r(&sec, &tm); localtime_r(&sec, &tm);
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm); strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);
strftime(zonebuf, sizeof(zonebuf), "%z", &tm); strftime(zonebuf, sizeof(zonebuf), "%z", &tm);
return (xasprintf)("%s.%0*ld%s", timebuf, sswidth, subsec, zonebuf); (asprintf)(&p, "%s.%0*ld%s", timebuf, sswidth, subsec, zonebuf);
return p;
} }
/** /**

View File

@ -28,6 +28,6 @@
/ @note the greatest of all libm functions / @note the greatest of all libm functions
tinymath_atan2: tinymath_atan2:
ezlea tinymath_atan2l,ax ezlea tinymath_atan2l,ax
jmp _f2ld2 jmp _d2ld2
.endfn tinymath_atan2,globl .endfn tinymath_atan2,globl
.alias tinymath_atan2,atan2 .alias tinymath_atan2,atan2

View File

@ -43,31 +43,6 @@ kCombiningChars:
add $1208,%rsi add $1208,%rsi
.init.end 400,_init_kCombiningChars .init.end 400,_init_kCombiningChars
/ The data below is sparse, as evidenced by:
/ o/tool/viz/bing.com <o/libc/str/CombiningChars.bin |
/ o/tool/viz/fold.com
/ Thus ask the kernel to shrink its physical memory requirements
/ which might sadly need mmap intermediate step on linux to work
/ how one would have hoped.
.text.startup
kCombiningCharsInit:
push %rbp
mov %rsp,%rbp
.profilable
ezlea kCombiningChars,di
mov $114752,%esi
call mergepages
pop %rbp
ret
.endfn kCombiningCharsInit
.previous
.init_array
.align 8
kCombiningCharsCtor:
.quad kCombiningCharsInit
.endobj kCombiningCharsCtor
.previous
/ o/tool/build/lz4toasm.com \ / o/tool/build/lz4toasm.com \
/ -o o/libc/str/CombiningChars.s \ / -o o/libc/str/CombiningChars.s \
/ -s kCombiningChars \ / -s kCombiningChars \

View File

@ -44,7 +44,7 @@ void *unbingbuf(void *buf, size_t size, const char16_t *glyphs, int fill) {
char *p, *pe; char *p, *pe;
for (p = buf, pe = p + size; p < pe && *glyphs; ++p, ++glyphs) { for (p = buf, pe = p + size; p < pe && *glyphs; ++p, ++glyphs) {
*p = (b = unbing(*glyphs)) & 0xff; *p = (b = unbing(*glyphs)) & 0xff;
DCHECK_NE(-1, b, "%`'hc ∉ IBMCP437\n", *glyphs); /* DCHECK_NE(-1, b, "%`'hc ∉ IBMCP437\n", *glyphs); */
} }
if (fill != -1) memset(p, fill, pe - p); if (fill != -1) memset(p, fill, pe - p);
return buf; return buf;

View File

@ -49,6 +49,7 @@ int xwrite(int, const void *, uint64_t);
cosmopolitan § eXtended apis » memory cosmopolitan § eXtended apis » memory
*/ */
void xdie(void) noreturn;
char *xdtoa(double) _XMAL; char *xdtoa(double) _XMAL;
char *xasprintf(const char *, ...) printfesque(1) paramsnonnull((1)) _XMAL; char *xasprintf(const char *, ...) printfesque(1) paramsnonnull((1)) _XMAL;
char *xvasprintf(const char *, va_list) _XPNN _XMAL; char *xvasprintf(const char *, va_list) _XPNN _XMAL;
@ -63,6 +64,7 @@ char *xstrdup(const char *) _XPNN _XMAL;
char *xstrndup(const char *, size_t) _XPNN _XMAL; char *xstrndup(const char *, size_t) _XPNN _XMAL;
char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL; char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL;
char *xstrmul(const char *, size_t) paramsnonnull((1)) _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 *xinet_ntop(int, const void *) _XPNN _XMAL;
char *xaescapec(const char *) _XPNN _XMAL; char *xaescapec(const char *) _XPNN _XMAL;
char *xaescapesh(const char *) _XPNN _XMAL; char *xaescapesh(const char *) _XPNN _XMAL;
@ -82,7 +84,8 @@ char *xiso8601ts(struct timespec *) mallocesque;
cosmopolitan § eXtended apis » input / output cosmopolitan § eXtended apis » input / output
*/ */
char *xslurp(const char *) _XPNN _XMALPG nodiscard; char *xslurp(const char *, size_t *) paramsnonnull((1)) _XMALPG nodiscard;
int xbarf(const char *, const void *, size_t);
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § eXtended apis » safety cosmopolitan § eXtended apis » safety

View File

@ -37,7 +37,6 @@ LIBC_X_A_DIRECTDEPS = \
LIBC_CALLS \ LIBC_CALLS \
LIBC_ESCAPE \ LIBC_ESCAPE \
LIBC_FMT \ LIBC_FMT \
LIBC_LOG \
LIBC_MEM \ LIBC_MEM \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_RUNTIME \ LIBC_RUNTIME \
@ -45,7 +44,6 @@ LIBC_X_A_DIRECTDEPS = \
LIBC_STR \ LIBC_STR \
LIBC_STUBS \ LIBC_STUBS \
LIBC_SYSV \ LIBC_SYSV \
LIBC_TIME \
THIRD_PARTY_DTOA THIRD_PARTY_DTOA
LIBC_X_A_DEPS := \ LIBC_X_A_DEPS := \

View File

@ -32,7 +32,7 @@ char *xaescape(const char *unescaped,
unsigned length)) { unsigned length)) {
char *escaped = NULL; char *escaped = NULL;
if (aescape(&escaped, 32, unescaped, strlen(unescaped), impl) == -1) { if (aescape(&escaped, 32, unescaped, strlen(unescaped), impl) == -1) {
die(); xdie();
} }
return escaped; return escaped;
} }

65
libc/x/xbarf.c 100644
View File

@ -0,0 +1,65 @@
/*-*- 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/calls.h"
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
/**
* Writes data to file.
*
* @param size can be -1 to strlen(data)
* @return if failed, -1 w/ errno
* @note this is uninterruptible
*/
int xbarf(const char *path, const void *data, size_t size) {
char *p;
ssize_t rc;
int fd, res;
size_t i, wrote;
res = 0;
p = data;
if (size == -1) size = strlen(p);
if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) != -1) {
if (ftruncate(fd, size) != -1) {
if (size > 2 * 1024 * 1024) {
fadvise(fd, 0, size, MADV_SEQUENTIAL);
}
for (i = 0; i < size; i += wrote) {
TryAgain:
if ((rc = pwrite(fd, p + i, size - i, i)) != -1) {
wrote = rc;
} else if (errno == EINTR) {
goto TryAgain;
} else {
res = -1;
break;
}
}
} else {
res = -1;
}
close(fd);
} else {
res = -1;
}
return res;
}

View File

@ -26,6 +26,6 @@
*/ */
void *xcalloc(size_t count, size_t size) { void *xcalloc(size_t count, size_t size) {
void *res = calloc(count, size); void *res = calloc(count, size);
if (!res) die(); if (!res) xdie();
return res; return res;
} }

28
libc/x/xdie.c 100644
View File

@ -0,0 +1,28 @@
/*-*- 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/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/x/x.h"
void xdie(void) {
if (weaken(die)) die();
abort();
}

View File

@ -0,0 +1,37 @@
/*-*- 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/safemacros.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
/**
* Joins paths.
*/
char *xjoinpaths(const char *path, const char *other) {
if (!*other) {
return xstrdup(path);
} else if (startswith(other, "/") || strcmp(path, ".") == 0) {
return xstrdup(other);
} else if (endswith(other, "/")) {
return xstrcat(path, other);
} else {
return xstrcat(path, '/', other);
}
}

View File

@ -26,6 +26,6 @@
*/ */
void *xmalloc(size_t bytes) { void *xmalloc(size_t bytes) {
void *res = malloc(bytes); void *res = malloc(bytes);
if (!res) die(); if (!res) xdie();
return res; return res;
} }

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