Browse Source

Add fixes performance and static web server

main
Justine Tunney 1 year ago
parent
commit
c45e46f871
  1. 8
      build/compile
  2. 7
      build/definitions.mk
  3. 19
      build/realify.sed
  4. 2
      build/rules.mk
  5. 1
      examples/examples.mk
  6. 2
      examples/printargs.c
  7. 30
      libc/alg/memmem.c
  8. 3
      libc/calls/atfork.c
  9. 2
      libc/calls/clock_gettime.c
  10. 6
      libc/calls/fstat-nt.c
  11. 4
      libc/calls/getpid.c
  12. 4
      libc/calls/getrusage-nt.c
  13. 2
      libc/calls/gettimeofday-nt.c
  14. 2
      libc/calls/open.c
  15. 2
      libc/calls/sigaction.c
  16. 2
      libc/calls/utimensat-nt.c
  17. 4
      libc/calls/wait4-nt.c
  18. 15
      libc/conv/conv.h
  19. 1
      libc/conv/conv.mk
  20. 43
      libc/conv/dosdatetimetounix.c
  21. 6
      libc/conv/filetimetotimespec.c
  22. 10
      libc/conv/filetimetotimeval.c
  23. 25
      libc/conv/kmonthyearday.c
  24. 2
      libc/conv/timespectofiletime.c
  25. 2
      libc/conv/timetofiletime.c
  26. 2
      libc/conv/timevaltofiletime.c
  27. 1
      libc/dos.h
  28. 128
      libc/fmt/fcvt.c
  29. 2
      libc/fmt/fmt.h
  30. 2
      libc/fmt/palandftoa.c
  31. 6
      libc/fmt/palandntoa.c
  32. 24
      libc/fmt/palandprintf.c
  33. 8
      libc/fmt/palandprintf.h
  34. 2
      libc/fmt/spacepad.c
  35. 190
      libc/fmt/stoa.c
  36. 18
      libc/fmt/vsnprintf.c
  37. 2
      libc/integral/normalize.inc
  38. 2
      libc/linux/linux.mk
  39. 2
      libc/log/asan.c
  40. 26
      libc/log/checkfail.c
  41. 2
      libc/log/log.h
  42. 5
      libc/log/log.mk
  43. 24
      libc/log/vflogf.c
  44. 6
      libc/nt/winsock.h
  45. 3
      libc/runtime/executive.S
  46. 6
      libc/runtime/getstack.c
  47. 3
      libc/runtime/isheap.c
  48. 22
      libc/sock/inet_ntop.c
  49. 1
      libc/stdio/fwritebuf.c
  50. 10
      libc/str/getutf16.ncabi.c
  51. 4
      libc/str/str.h
  52. 5
      libc/str/strclen16.c
  53. 9
      libc/str/thompike.h
  54. 12
      libc/str/utf16.h
  55. 10
      libc/time/localtime.c
  56. 1
      libc/time/time.h
  57. 4
      libc/time/times.c
  58. 18
      libc/zip.h
  59. 2
      libc/zipos/close.c
  60. 18
      libc/zipos/find.c
  61. 10
      libc/zipos/open.c
  62. 67
      net/http/formathttpdatetime.c
  63. 2
      net/http/gethttpheader.gperf
  64. 2
      net/http/gethttpheader.inc
  65. 8
      net/http/gethttpmethod.gperf
  66. 126
      net/http/gethttpmethod.inc
  67. 48
      net/http/http.h
  68. 81
      net/http/http.mk
  69. 40
      net/http/khttpmethod.c
  70. 57
      net/http/parsehttpdatetime.c
  71. 72
      net/http/parsehttprange.c
  72. 5
      net/http/parsehttprequest.c
  73. 33
      net/http/parsehttpversion.c
  74. 32
      test/libc/conv/dosdatetimetounix_test.c
  75. 3
      test/libc/conv/test.mk
  76. 4
      test/libc/conv/timevaltofiletime_test.c
  77. 32
      test/libc/fmt/fcvt_test.c
  78. 9
      test/libc/fmt/palandprintf_test.c
  79. 20
      test/libc/fmt/sprintf_s.inc
  80. 7
      test/libc/sock/inet_ntop_test.c
  81. 48
      test/net/http/parsehttpdatetime_test.c
  82. 102
      test/net/http/parsehttprange_test.c
  83. 22
      test/tool/build/lib/disinst_test.c
  84. 6
      third_party/zlib/zlib.mk
  85. 1
      tool/build/build.mk
  86. 7
      tool/build/emubin/emubin.mk
  87. 355
      tool/build/emubin/lisp.c
  88. 16
      tool/build/emubin/lisp.lds
  89. 46
      tool/build/emubin/lispstart.S
  90. 93
      tool/build/emulator.c
  91. 3
      tool/build/lib/buffer.c
  92. 80
      tool/build/lib/demangle.c
  93. 2
      tool/build/lib/demangle.h
  94. 2
      tool/build/lib/dis.c
  95. 4
      tool/build/lib/dis.h
  96. 73
      tool/build/lib/disarg.c
  97. 8
      tool/build/lib/diself.c
  98. 7
      tool/build/lib/disinst.c
  99. 2
      tool/build/lib/modrm.h
  100. 7
      tool/build/lib/pty.c

8
build/compile

@ -45,6 +45,7 @@ COUNTERMAND=
# The GNU Compiler Collection passes a lot of CFLAGS to the preprocessor
# (which we call CCFLAGS) but it should pass more; and we do just that.
NOPG=0
FIRST=1
OUTARG=0
INVISIBLE=0
@ -65,13 +66,16 @@ for x; do
-w)
set -- "$@" "$x" -D__W__
;;
-x-no-pg)
NOPG=1
;;
-pg)
if [ $INVISIBLE -eq 0 ]; then
if [ $NOPG -eq 0 ] && [ $INVISIBLE -eq 0 ]; then
set -- "$@" "$x" -D__PG__ # @see libc/macros.h
fi
;;
-mfentry)
if [ $INVISIBLE -eq 0 ]; then
if [ $NOPG -eq 0 ] && [ $INVISIBLE -eq 0 ]; then
set -- "$@" "$x" -D__MFENTRY__
fi
;;

7
build/definitions.mk

@ -63,6 +63,7 @@ FC = gfortran #/opt/cross9f/bin/x86_64-linux-musl-gfortran
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
AR = o/third_party/gcc/bin/x86_64-linux-musl-ar
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
@ -319,6 +320,7 @@ OBJECTIFY.c2x.c = $(CC) $(OBJECTIFY.c.flags) -std=c2x -Wextra -Werror -pedantic-
OBJECTIFY.real.c = \
$(GCC) \
-x-no-pg \
$(OBJECTIFY.c.flags) \
-wrapper build/realify.sh \
-D__REAL_MODE__ \
@ -330,7 +332,12 @@ OBJECTIFY.real.c = \
-ffixed-r13 \
-ffixed-r14 \
-ffixed-r15 \
-mno-red-zone \
-fcall-used-rbx \
-fno-jump-tables \
-fno-shrink-wrap \
-fno-schedule-insns2 \
-flive-range-shrinkage \
-fno-omit-frame-pointer \
-momit-leaf-frame-pointer \
-mpreferred-stack-boundary=3 \

19
build/realify.sed

@ -15,17 +15,6 @@
# remove comments
s/[ \t][ \t]*#.*//
# preserve hardcoded stack offsets
# bloats code size 13% compared to recomputing stack solution
s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/
s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/
s/ret\(q\|\)/retw\t$6/
s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/
s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
# 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/
@ -34,6 +23,14 @@ s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
#s/pushq\t\(.*\)/sub $6,%sp\n\tpush \1/
#s/popq\t\(.*\)/pop \1\n\tadd $6,%sp/
# preserve hardcoded stack offsets
# bloats code size 13%
s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/
s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/
s/ret\(q\|\)/retw\t$6/
s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/
s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
s/, /,/g
# 32-bitify

2
build/rules.mk

@ -72,7 +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)/%.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/tiny/%.real.o: %.real.c; @ACTION=OBJECTIFY.real build/compile $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.real.o: %.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)/%.pkg:; @build/package $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
o/$(MODE)/%.zip.o: %; @build/zipobj $(OUTPUT_OPTION) $<

1
examples/examples.mk

@ -49,6 +49,7 @@ EXAMPLES_DIRECTDEPS = \
LIBC_CONV \
LIBC_FMT \
LIBC_LOG \
LIBC_LOG_ASAN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNELBASE \

2
examples/printargs.c

@ -55,7 +55,7 @@ int main(int argc, char *argv[], char **envp) {
unsigned long val;
char fmt[64], **env;
printf("\nArguments:\n");
for (i = 0; i < argc; ++i) {
for (i = 0; i < g_argc; ++i) {
printf(" ☼ %s\n", argv[i]);
}
printf("\nEnvironment:\n");

30
libc/alg/memmem.c

@ -71,27 +71,25 @@ static size_t KnuthMorrisPratt(m, T, W, n, S)
* @param needlelen is its character count
* @return pointer to first result or NULL if not found
*/
void *(memmem)(const void *haystack_, size_t haystacklen, const void *needle_,
void *(memmem)(const void *haystackp, size_t haystacklen, const void *needlep,
size_t needlelen) {
long *T;
size_t i;
const char *haystack, *needle, *h;
haystack = haystack_;
needle = needle_;
needle = needlep;
haystack = haystackp;
if (needlelen > haystacklen) return NULL;
if (!needlelen) return (/*unconst*/ void *)haystack;
if (!needlelen) return haystack;
h = memchr(haystack, *needle, haystacklen);
if (!h || needlelen == 1) return (/*unconst*/ void *)h;
if (!h || needlelen == 1) return h;
haystacklen -= h - haystack;
long stacktmp[16];
void *freeme = NULL;
long *T = (needlelen + 1 < ARRAYLEN(stacktmp))
? &stacktmp[0]
: (freeme = malloc((needlelen + 1) * sizeof(long)));
KnuthMorrisPrattInit(needlelen, T, needle);
size_t i = KnuthMorrisPratt(needlelen, T, needle, haystacklen, h);
free(freeme);
if (i < haystacklen) {
return (/*unconst*/ char *)h + i * sizeof(char);
if (needlelen < haystacklen && memcmp(h, needle, needlelen) == 0) {
return h;
} else {
return NULL;
T = malloc((needlelen + 1) * sizeof(long));
KnuthMorrisPrattInit(needlelen, T, needle);
i = KnuthMorrisPratt(needlelen, T, needle, haystacklen, h);
free(T);
return i < haystacklen ? h + i * sizeof(char) : NULL;
}
}

3
libc/calls/atfork.c

@ -17,10 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/internal.h"
#include "libc/macros.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"

2
libc/calls/clock_gettime.c

@ -77,7 +77,7 @@ int clock_gettime(int clockid, struct timespec *out_ts) {
} else {
struct NtFileTime ft;
GetSystemTimeAsFileTime(&ft);
*out_ts = filetimetotimespec(ft);
*out_ts = FileTimeToTimeSpec(ft);
return 0;
}
}

6
libc/calls/fstat-nt.c

@ -49,9 +49,9 @@ textwindows int fstat$nt(int64_t handle, struct stat *st) {
: (((filetype == kNtFileTypeDisk) ? S_IFBLK : 0) |
((filetype == kNtFileTypeChar) ? S_IFCHR : 0) |
((filetype == kNtFileTypePipe) ? S_IFIFO : 0))));
st->st_atim = filetimetotimespec(wst.ftLastAccessFileTime);
st->st_mtim = filetimetotimespec(wst.ftLastWriteFileTime);
st->st_ctim = filetimetotimespec(wst.ftCreationFileTime);
st->st_atim = FileTimeToTimeSpec(wst.ftLastAccessFileTime);
st->st_mtim = FileTimeToTimeSpec(wst.ftLastWriteFileTime);
st->st_ctim = FileTimeToTimeSpec(wst.ftCreationFileTime);
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
st->st_blksize = PAGESIZE;
st->st_dev = wst.dwVolumeSerialNumber;

4
libc/calls/getpid.c

@ -28,7 +28,6 @@
static int g_pid;
static void __updatepid(void) {
atfork(__updatepid, NULL);
g_pid = __getpid();
}
@ -47,8 +46,9 @@ int __getpid(void) {
int getpid(void) {
static bool once;
if (!once) {
once = true;
__updatepid();
atfork(__updatepid, NULL);
once = true;
}
return g_pid;
}

4
libc/calls/getrusage-nt.c

@ -36,8 +36,8 @@ textwindows int getrusage$nt(int who, struct rusage *usage) {
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
filetimetotimeval(&usage->ru_utime, UserFileTime);
filetimetotimeval(&usage->ru_stime, KernelFileTime);
FileTimeToTimeVal(&usage->ru_utime, UserFileTime);
FileTimeToTimeVal(&usage->ru_stime, KernelFileTime);
return 0;
} else {
return winerr();

2
libc/calls/gettimeofday-nt.c

@ -29,7 +29,7 @@
int gettimeofday$nt(struct timeval *tv, struct timezone *tz) {
struct NtFileTime ft;
GetSystemTimeAsFileTime(&ft);
filetimetotimeval(tv, ft);
FileTimeToTimeVal(tv, ft);
if (tz) memset(tz, 0, sizeof(*tz));
return 0;
}

2
libc/calls/open.c

@ -35,7 +35,7 @@
* @param mode is an octal user/group/other permission signifier, that's
* ignored if O_CREAT or O_TMPFILE weren't passed
* @return number needing close(), or -1 w/ errno
* @asyncsignalsafe
* @note don't call open() from signal handlers
*/
nodiscard int open(const char *file, int flags, ...) {
va_list va;

2
libc/calls/sigaction.c

@ -155,7 +155,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
ap->sa_restorer = &__restore_rt;
}
}
if (rva >= 0) {
if (rva >= kSigactionMinRva) {
ap->sa_sigaction = (sigaction_f)__sigenter;
}
}

2
libc/calls/utimensat-nt.c

@ -63,7 +63,7 @@ textwindows int utimensat$nt(int dirfd, const char *path,
} else if (ts[i].tv_nsec == UTIME_OMIT) {
ftp[i] = NULL;
} else {
ft[i] = timespectofiletime(ts[i]);
ft[i] = TimeSpecToFileTime(ts[i]);
ftp[i] = &ft[i];
}
}

4
libc/calls/wait4-nt.c

@ -50,8 +50,8 @@ textwindows int wait4$nt(int pid, int *opt_out_wstatus, int options,
memset(opt_out_rusage, 0, sizeof(*opt_out_rusage));
GetProcessTimes(GetCurrentProcess(), &createfiletime, &exitfiletime,
&kernelfiletime, &userfiletime);
filetimetotimeval(&opt_out_rusage->ru_utime, userfiletime);
filetimetotimeval(&opt_out_rusage->ru_stime, kernelfiletime);
FileTimeToTimeVal(&opt_out_rusage->ru_utime, userfiletime);
FileTimeToTimeVal(&opt_out_rusage->ru_stime, kernelfiletime);
}
return pid;
} else if (options & WNOHANG) {

15
libc/conv/conv.h

@ -15,8 +15,8 @@
* of the UNIX operation system signalled the end of modernity. Windows
* timestamps are living proof.
*/
#define MODERNITYSECONDS 11644473600
#define HECTONANOSECONDS 10000000
#define MODERNITYSECONDS 11644473600ull
#define HECTONANOSECONDS 10000000ull
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -46,12 +46,13 @@ long strtol(const char *, char **, int)
cosmopolitan § conversion » time
*/
struct timespec filetimetotimespec(struct NtFileTime);
struct NtFileTime timespectofiletime(struct timespec);
struct NtFileTime timetofiletime(int64_t) nothrow pureconst;
int64_t DosDateTimeToUnix(unsigned, unsigned);
struct timespec FileTimeToTimeSpec(struct NtFileTime);
struct NtFileTime TimeSpecToFileTime(struct timespec);
struct NtFileTime TimeToFileTime(int64_t) nothrow pureconst;
int64_t filetimetotime(struct NtFileTime) nothrow pureconst;
void filetimetotimeval(struct timeval *, struct NtFileTime) nothrow;
struct NtFileTime timevaltofiletime(const struct timeval *) nosideeffect;
void FileTimeToTimeVal(struct timeval *, struct NtFileTime) nothrow;
struct NtFileTime TimeValToFileTime(const struct timeval *) nosideeffect;
long convertmicros(const struct timeval *, long) paramsnonnull() nosideeffect;
/*───────────────────────────────────────────────────────────────────────────│─╗

1
libc/conv/conv.mk

@ -52,6 +52,7 @@ $(LIBC_CONV_A).pkg: \
$(LIBC_CONV_A_OBJS) \
$(foreach x,$(LIBC_CONV_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/conv/dosdatetimetounix.o \
o/$(MODE)/libc/conv/itoa64radix10.greg.o \
o/$(MODE)/libc/conv/timetofiletime.o \
o/$(MODE)/libc/conv/filetimetotime.o \

43
libc/conv/dosdatetimetounix.c

@ -0,0 +1,43 @@
/*-*- 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/conv/conv.h"
#include "libc/macros.h"
#include "libc/time/time.h"
/**
* Converts MS-DOS timestamp to UNIX.
*
* @note type signature supports dates greater than 2100
* @see PKZIP, FAT
*/
int64_t DosDateTimeToUnix(unsigned date, unsigned time) {
unsigned weekday, year, month, day, hour, minute, second, yday, leap;
year = ((date & 0xfffffe00) >> 9) + 1980 - 1900;
month = MAX(1, MIN(12, (date & 0x01e0) >> 5));
day = (date & 0x001f) ? (date & 0x001f) - 1 : 0;
hour = (time & 0x0000f800) >> 11;
minute = (time & 0x000007e0) >> 5;
second = (time & 0x0000001f) << 1;
leap = year % 4 == 0 && (year % 100 || year % 400 == 0);
yday = day + kMonthYearDay[leap][month - 1];
return second + minute * 60 + hour * 3600 + yday * 86400 +
(year - 70) * 31536000ull + ((year - 69) / 4) * 86400ull -
((year - 1) / 100) * 86400ull + ((year + 299) / 400) * 86400ull;
}

6
libc/conv/filetimetotimespec.c

@ -24,11 +24,11 @@
/**
* Converts Windows COBOL timestamp to UNIX epoch in nanoseconds.
*/
struct timespec filetimetotimespec(struct NtFileTime ft) {
struct timespec FileTimeToTimeSpec(struct NtFileTime ft) {
uint64_t x;
x = ft.dwHighDateTime;
x <<= 32;
x |= ft.dwLowDateTime;
x -= MODERNITYSECONDS;
return (struct timespec){x / HECTONANOSECONDS, x % HECTONANOSECONDS * 100};
return (struct timespec){x / HECTONANOSECONDS - MODERNITYSECONDS,
x % HECTONANOSECONDS * 100};
}

10
libc/conv/filetimetotimeval.c

@ -22,9 +22,11 @@
#include "libc/conv/conv.h"
#include "libc/nt/struct/filetime.h"
void filetimetotimeval(struct timeval *tv, struct NtFileTime ft) {
uint64_t t = (uint64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime;
uint64_t x = t - MODERNITYSECONDS * HECTONANOSECONDS;
tv->tv_sec = x / HECTONANOSECONDS;
void FileTimeToTimeVal(struct timeval *tv, struct NtFileTime ft) {
uint64_t x;
x = ft.dwHighDateTime;
x <<= 32;
x |= ft.dwLowDateTime;
tv->tv_sec = x / HECTONANOSECONDS - MODERNITYSECONDS;
tv->tv_usec = x % HECTONANOSECONDS / 10;
}

25
libc/conv/kmonthyearday.c

@ -0,0 +1,25 @@
/*-*- 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/time/time.h"
const unsigned short kMonthYearDay[2][12] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};

2
libc/conv/timespectofiletime.c

@ -25,7 +25,7 @@
/**
* Converts UNIX nanosecond timestamp to Windows COBOL timestamp.
*/
struct NtFileTime timespectofiletime(struct timespec ts) {
struct NtFileTime TimeSpecToFileTime(struct timespec ts) {
uint64_t x;
x = MODERNITYSECONDS;
x += ts.tv_sec * HECTONANOSECONDS;

2
libc/conv/timetofiletime.c

@ -20,7 +20,7 @@
#include "libc/conv/conv.h"
#include "libc/nt/struct/filetime.h"
struct NtFileTime timetofiletime(int64_t t) {
struct NtFileTime TimeToFileTime(int64_t t) {
uint64_t t2 = (t + MODERNITYSECONDS) * HECTONANOSECONDS;
return (struct NtFileTime){(uint32_t)t2, (uint32_t)(t2 >> 32)};
}

2
libc/conv/timevaltofiletime.c

@ -22,7 +22,7 @@
#include "libc/nt/struct/filetime.h"
#include "libc/time/time.h"
struct NtFileTime timevaltofiletime(const struct timeval *tv) {
struct NtFileTime TimeValToFileTime(const struct timeval *tv) {
uint64_t t2 = tv->tv_sec * HECTONANOSECONDS + tv->tv_usec * 10 +
MODERNITYSECONDS * HECTONANOSECONDS;
return (struct NtFileTime){(uint32_t)t2, (uint32_t)(t2 >> 32)};

1
libc/dos.h

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_DOS_H_
#define COSMOPOLITAN_LIBC_DOS_H_
#include "libc/macros.h"
/**
* @fileoverview MS-DOS Data Structures.

128
libc/fmt/fcvt.c

@ -0,0 +1,128 @@
/*-*- 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 2009 Ian Piumarta
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the 'Software'), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to
do so, provided that the above copyright notice(s) and this permission
notice appear in all copies of the Software. Inclusion of the above
copyright notice(s) and this permission notice in supporting documentation
would be appreciated but is not required.
THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
*/
#include "libc/assert.h"
#include "libc/fmt/fmt.h"
#include "libc/macros.h"
#include "libc/math.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
asm(".ident\t\"\\n\\n\
ecvt, fcvt (MIT License)\\n\
Copyright 2009 Ian Piumarta\"");
/**
* @fileoverview Replacements for the functions ecvt() and fcvt()
*
* These functions were recently deprecated in POSIX. The interface and
* behaviour is identical to the functions that they replace and faster.
*
* For details on the use of these functions, see your ecvt(3) manual
* page. If you don't have one handy, there might still be one available
* here: http://opengroup.org/onlinepubs/007908799/xsh/ecvt.html
*
* @see https://www.piumarta.com/software/fcvt/
*/
static char *Fcvt(double value, int ndigit, int *decpt, int *sign, int fflag) {
static char buf[128];
double i;
uint64_t l, mant;
int exp2, exp10, ptr;
memcpy(&l, &value, 8);
exp2 = (0x7ff & (l >> 52)) - 1023;
mant = l & 0x000fffffffffffffULL;
if ((*sign = l >> 63)) value = -value;
if (exp2 == 0x400) {
*decpt = 0;
return mant ? "nan" : "inf";
}
exp10 = (value == 0) ? !fflag : (int)ceil(log10(value));
if (exp10 < -307) exp10 = -307; /* otherwise overflow in pow() */
value *= pow(10.0, -exp10);
if (value) {
while (value < 0.1) {
value *= 10;
--exp10;
}
while (value >= 1.0) {
value /= 10;
++exp10;
}
}
assert(value == 0 || (0.1 <= value && value < 1.0));
if (fflag) {
if (ndigit + exp10 < 0) {
*decpt = -ndigit;
return "";
}
ndigit += exp10;
}
*decpt = exp10;
if (ARRAYLEN(buf) < ndigit + 2) abort();
ptr = 1;
#if 0 /* slow and safe (and dreadfully boring) */
while (ptr <= ndigit) {
i;
value = modf(value * 10, &i);
buf[ptr++] = '0' + (int)i;
}
if (value >= 0.5) {
while (--ptr && ++buf[ptr] > '9') {
buf[ptr] = '0';
}
}
#else /* faster */
memcpy(&l, &value, 8);
exp2 = (0x7ff & (l >> 52)) - 1023;
assert(value == 0 || (-4 <= exp2 && exp2 <= -1));
mant = l & 0x000fffffffffffffULL;
if (exp2 == -1023) {
++exp2;
} else {
mant |= 0x0010000000000000ULL;
}
mant <<= (exp2 + 4); /* 56-bit denormalised signifier */
while (ptr <= ndigit) {
mant &= 0x00ffffffffffffffULL; /* mod 1.0 */
mant = (mant << 1) + (mant << 3);
buf[ptr++] = '0' + (mant >> 56);
}
if (mant & 0x0080000000000000ULL) /* 1/2 << 56 */
while (--ptr && ++buf[ptr] > '9') buf[ptr] = '0';
#endif
if (ptr) {
buf[ndigit + 1] = 0;
return buf + 1;
}
if (fflag) {
++ndigit;
++*decpt;
}
buf[0] = '1';
buf[ndigit] = 0;
return buf;
}
char *ecvt(double value, int ndigit, int *decpt, int *sign) {
return Fcvt(value, ndigit, decpt, sign, 0);
}
char *fcvt(double value, int ndigit, int *decpt, int *sign) {
return Fcvt(value, ndigit, decpt, sign, 1);
}

2
libc/fmt/fmt.h

@ -29,6 +29,8 @@ char *strerror(int) returnsnonnull nothrow nocallback;
int strerror_r(int, char *, size_t) nothrow nocallback;
int palandprintf(void *, void *, const char *, va_list) hidden;
char *itoa(int, char *, int) compatfn;
char *fcvt(double, int, int *, int *);
char *ecvt(double, int, int *, int *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § string formatting » optimizations

2
libc/fmt/palandftoa.c

@ -40,7 +40,7 @@
* @see xdtoa() for higher precision at the cost of bloat
* @see palandprintf() which is intended caller
*/
int ftoa(int out(int, void *), void *arg, long double value, int prec,
int ftoa(int out(long, void *), void *arg, long double value, int prec,
unsigned long width, unsigned long flags) {
long whole, frac;
long double tmp, diff;

6
libc/fmt/palandntoa.c

@ -31,7 +31,7 @@
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
static int ntoaformat(int out(int, void *), void *arg, char *buf, unsigned len,
static int ntoaformat(int out(long, void *), void *arg, char *buf, unsigned len,
bool negative, unsigned log2base, unsigned prec,
unsigned width, unsigned char flags) {
unsigned i, idx;
@ -103,7 +103,7 @@ static int ntoaformat(int out(int, void *), void *arg, char *buf, unsigned len,
return 0;
}
int ntoa2(int out(int, void *), void *arg, uintmax_t value, bool neg,
int ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
unsigned log2base, unsigned prec, unsigned width, unsigned flags,
const char *alphabet) {
uintmax_t remainder;
@ -135,7 +135,7 @@ int ntoa2(int out(int, void *), void *arg, uintmax_t value, bool neg,
return ntoaformat(out, arg, buf, len, neg, log2base, prec, width, flags);
}
int ntoa(int out(int, void *), void *arg, va_list va, unsigned char signbit,
int ntoa(int out(long, void *), void *arg, va_list va, unsigned char signbit,
unsigned long log2base, unsigned long prec, unsigned long width,
unsigned char flags, const char *lang) {
bool neg;

24
libc/fmt/palandprintf.c

@ -75,7 +75,7 @@ static int ppatoi(const char **str) {
* - `%Lf` long double
* - `%p` pointer (48-bit hexadecimal)
*
* Length Modifiers
* Size Modifiers
*
* - `%hhd` char (8-bit)
* - `%hd` short (16-bit)
@ -89,7 +89,11 @@ static int ppatoi(const char **str) {
* - `%08d` fixed columns w/ zero leftpadding
* - `%8d` fixed columns w/ space leftpadding
* - `%*s` variable column string (thompson-pike)
* - `%.*s` variable column data (ignore nul terminator)
*
* Precision Modifiers
*
* - `%.8s` supplied character length (ignore nul terminator)
* - `%.*s` supplied character length argument (ignore nul terminator)
*
* Formatting Modifiers
*
@ -112,9 +116,9 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
long double ldbl;
wchar_t charbuf[3];
const char *alphabet;
int (*out)(int, void *);
int (*out)(long, void *);
unsigned char signbit, log2base;
int w, rc, flags, width, lasterr, precision;
int w, flags, width, lasterr, precision;
lasterr = errno;
out = fn ? fn : (int (*)(int, void *))missingno;
@ -255,7 +259,8 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
case 'u': {
flags &= ~FLAGS_HASH; /* no hash for dec format */
DoNumber:
if (weaken(ntoa)(out, arg, va, signbit, log2base, precision, width,
if (!weaken(ntoa) ||
weaken(ntoa)(out, arg, va, signbit, log2base, precision, width,
flags, alphabet) == -1) {
return -1;
}
@ -269,7 +274,8 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
} else {
ldbl = va_arg(va, double);
}
if (weaken(ftoa)(out, arg, ldbl, precision, width, flags) == -1) {
if (!weaken(ftoa) ||
weaken(ftoa)(out, arg, ldbl, precision, width, flags) == -1) {
return -1;
}
break;
@ -297,8 +303,10 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
case 's':
p = va_arg(va, void *);
showstr:
rc = weaken(stoa)(out, arg, p, flags, precision, width, signbit, qchar);
if (rc == -1) return -1;
if (!weaken(stoa) || weaken(stoa)(out, arg, p, flags, precision, width,
signbit, qchar) == -1) {
return -1;
}
break;
case '%':

8
libc/fmt/palandprintf.h

@ -7,12 +7,12 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int spacepad(int(int, void *), void *, unsigned long) hidden;
int ftoa(int(int, void *), void *, long double, int, unsigned long,
int spacepad(int(long, void *), void *, unsigned long) hidden;
int ftoa(int(long, void *), void *, long double, int, unsigned long,
unsigned long) hidden;
int stoa(int(int, void *), void *, void *, unsigned long, unsigned long,
int stoa(int(long, void *), void *, void *, unsigned long, unsigned long,
unsigned long, unsigned char, unsigned char) hidden;
int ntoa(int(int, void *), void *, va_list, unsigned char, unsigned long,
int ntoa(int(long, void *), void *, va_list, unsigned char, unsigned long,
unsigned long, unsigned long, unsigned char, const char *) hidden;
COSMOPOLITAN_C_END_

2
libc/fmt/spacepad.c

@ -19,7 +19,7 @@
*/
#include "libc/fmt/palandprintf.h"
int spacepad(int out(int, void *), void *arg, unsigned long n) {
int spacepad(int out(long, void *), void *arg, unsigned long n) {
int i, rc;
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
return rc;

190
libc/fmt/stoa.c

@ -17,47 +17,54 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/bits/weaken.h"
#include "libc/escape/escape.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/paland.inc"
#include "libc/fmt/palandprintf.h"
#include "libc/nexgen32e/tinystrlen.h"
#include "libc/str/internal.h"
#include "libc/str/str.h"
#include "libc/str/tpdecode.h"
#include "libc/str/tpencode.h"
#include "libc/str/thompike.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/unicode/unicode.h"
forceinline unsigned long tpiencode(wint_t wc) {
char buf[8];
memset(buf, 0, sizeof(buf));
tpencode(buf, sizeof(buf), wc, false);
return read64le(buf);
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
static int StoaEmitByte(int f(long, void *), void *a, wint_t c) {
return f(c, a);
}
forceinline int emitwc(int out(int, void *), void *arg, unsigned flags,
wint_t wc) {
unsigned long pending;
if (flags & FLAGS_QUOTE) {
if (wc > 127) {
pending = tpiencode(wc);
} else {
pending = cescapec(wc);
static int StoaEmitWordEncodedString(int f(long, void *), void *a, uint64_t w) {
do {
if (f(w & 0xff, a) == -1) {
return -1;
}
} while ((w >>= 8));
return 0;
}
static int StoaEmitUnicode(int f(long, void *), void *a, wint_t c) {
if (0 <= c && c <= 127) {
return f(c, a);
} else {
pending = tpiencode(wc);
return StoaEmitWordEncodedString(f, a, tpenc(c));
}
do {
if (out(pending & 0xff, arg) == -1) return -1;
} while ((pending >>= 8));
return 0;
}
forceinline int emitquote(int out(int, void *), void *arg, unsigned flags,
char ch, unsigned char signbit) {
static int StoaEmitQuoted(int f(long, void *), void *a, wint_t c) {
if (0 <= c && c <= 127) {
return StoaEmitWordEncodedString(f, a, cescapec(c));
} else {
return StoaEmitWordEncodedString(f, a, tpenc(c));
}
}
static int StoaEmitVisualized(int f(long, void *), void *a, wint_t c) {
return StoaEmitUnicode(f, a, (*weaken(kCp437))[c]);
}
static int StoaEmitQuote(int out(long, void *), void *arg, unsigned flags,
char ch, unsigned char signbit) {
if (flags & FLAGS_REPR) {
if (signbit == 63) {
if (out('L', arg) == -1) return -1;
@ -78,13 +85,15 @@ forceinline int emitquote(int out(int, void *), void *arg, unsigned flags,
*
* @see palandprintf()
*/
int stoa(int out(int, void *), void *arg, void *data, unsigned long flags,
int stoa(int out(long, void *), void *arg, void *data, unsigned long flags,
unsigned long precision, unsigned long width, unsigned char signbit,
unsigned char qchar) {
char *p;
wint_t wc;
unsigned w, c;
bool ignorenul;
unsigned n;
emit_f emit;
bool justdobytes;
unsigned w, c, pad;
p = data;
if (!p) {
@ -93,89 +102,102 @@ int stoa(int out(int, void *), void *arg, void *data, unsigned long flags,
flags |= FLAGS_NOQUOTE;
signbit = 0;
} else {
if (emitquote(out, arg, flags, qchar, signbit) == -1) return -1;
if (StoaEmitQuote(out, arg, flags, qchar, signbit) == -1) return -1;
}
if (!(flags & FLAGS_PRECISION)) {
if (signbit == 63) {
precision = tinywcsnlen((const wchar_t *)p, -1);
} else if (signbit == 15) {
precision = tinystrnlen16((const char16_t *)p, -1);
} else {
precision = strlen(p);
}
}
w = precision ? precision : -1;
pad = 0;
if (width) {
w = precision;
if (signbit == 63) {
if (weaken(wcsnwidth)) {
w = weaken(wcsnwidth)((const wchar_t *)p, w);
} else {
w = tinywcsnlen((const wchar_t *)p, w);
w = weaken(wcsnwidth)((const wchar_t *)p, precision);
}
} else if (signbit == 15) {
if (weaken(strnwidth16)) {
w = weaken(strnwidth16)((const char16_t *)p, w);
} else {
w = tinystrnlen16((const char16_t *)p, w);
w = weaken(strnwidth16)((const char16_t *)p, precision);
}
} else if (weaken(strnwidth)) {
w = weaken(strnwidth)(p, w);
} else {
w = strnlen(p, w);
w = weaken(strnwidth)(p, precision);
}
if (w < width) {
pad = width - w;
}
}
if (flags & FLAGS_PRECISION) {
w = MIN(w, precision);
if (pad && !(flags & FLAGS_LEFT)) {
if (spacepad(out, arg, pad) == -1) return -1;
}
if (w < width && !(flags & FLAGS_LEFT)) {
if (spacepad(out, arg, width - w) == -1) return -1;
justdobytes = false;
if (signbit == 15 || signbit == 63) {
if (flags & FLAGS_QUOTE) {
emit = StoaEmitQuoted;
} else {
emit = StoaEmitUnicode;
}
} else if ((flags & FLAGS_HASH) && weaken(kCp437)) {
justdobytes = true;
emit = StoaEmitVisualized;
} else if (flags & FLAGS_QUOTE) {
emit = StoaEmitQuoted;
} else {
justdobytes = true;
emit = StoaEmitByte;
}
ignorenul = (flags & FLAGS_PRECISION) && (flags & (FLAGS_HASH | FLAGS_QUOTE));
for (; !(flags & FLAGS_PRECISION) || precision; --precision) {
if (signbit == 15) {
if ((wc = *(const char16_t *)p) || ignorenul) {
if ((1 <= wc && wc <= 0xD7FF)) {
if (justdobytes) {
while (precision--) {
wc = *p++ & 0xff;
if (emit(out, arg, wc) == -1) return -1;
}
} else {
while (precision--) {
if (signbit == 15) {
wc = *(const char16_t *)p;
if (IsUcs2(wc)) {
p += sizeof(char16_t);
} else if ((wc & UTF16_MASK) == UTF16_CONT) {
} else if (IsUtf16Cont(wc)) {
p += sizeof(char16_t);
continue;
} else if (!precision) {
break;
} else {
char16_t buf[4] = {wc};
if (!(flags & FLAGS_PRECISION) || precision > 1) {
buf[1] = ((const char16_t *)p)[1];
}
p += max(1, getutf16((const char16_t *)p, &wc)) * sizeof(char16_t);
--precision;
wc = MergeUtf16(wc, *(const char16_t *)p);
}
} else if (signbit == 63) {
wc = *(const wint_t *)p;
p += sizeof(wint_t);
if (!wc) break;
} else {
break;
}
} else if (signbit == 63) {
wc = *(const wint_t *)p;
p += sizeof(wint_t);
if (!wc) break;
} else if (flags & FLAGS_HASH) {
c = *p & 0xff;
if (!c && !ignorenul) break;
wc = (*weaken(kCp437))[c];
p++;
} else {
if ((wc = *p & 0xff) || ignorenul) {
if (1 <= wc && wc <= 0x7f) {
++p;
} else if (iscont(wc & 0xff)) {
++p;
continue;
} else {
char buf[8];
memset(buf, 0, sizeof(buf));
memcpy(buf, p,
!(flags & FLAGS_PRECISION) ? 7 : MIN(7, precision - 1));
p += max(1, tpdecode(p, &wc));
wc = *p++ & 0xff;
if (!isascii(wc)) {
if (ThomPikeCont(wc)) continue;
n = ThomPikeLen(wc) - 1;
wc = ThomPikeByte(wc);
if (n > precision) break;
precision -= n;
while (n--) {
wc = ThomPikeMerge(wc, *p++);
}
}
} else {
break;
}
if (emit(out, arg, wc) == -1) return -1;
}
if (emitwc(out, arg, flags, wc) == -1) return -1;
}
if (w <= width && (flags & FLAGS_LEFT)) {
if (spacepad(out, arg, width - w) == -1) return -1;
if (pad && (flags & FLAGS_LEFT)) {
if (spacepad(out, arg, pad) == -1) return -1;
}
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {

18
libc/fmt/vsnprintf.c

@ -25,17 +25,13 @@
struct SprintfStr {
char *p;
size_t i, n;
size_t i;
size_t n;
};
static int vsnprintfputchar(unsigned char c, struct SprintfStr *str) {
if (str->i < str->n) {
if (str->p) str->p[str->i] = c;
str->i++;
} else {
if (!IsTrustworthy() && str->i >= INT_MAX) abort();
str->i++;
}
if (str->i < str->n) str->p[str->i] = c;
str->i++;
return 0;
}
@ -48,15 +44,11 @@ static int vsnprintfputchar(unsigned char c, struct SprintfStr *str) {
* @return number of bytes written, excluding the NUL terminator; or,
* if the output buffer wasn't passed, or was too short, then the
* number of characters that *would* have been written is returned
* @throw EOVERFLOW when a formatted field exceeds its limit, which can
* be checked by setting errno to 0 before calling
* @see palandprintf() and printf() for detailed documentation
*/
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
struct SprintfStr str = {buf, 0, size};
palandprintf(vsnprintfputchar, &str, fmt, va);
if (str.p && str.n) {
str.p[min(str.i, str.n - 1)] = '\0';
}
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
return str.i;
}

2
libc/integral/normalize.inc

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

2
libc/linux/linux.mk

@ -3,7 +3,7 @@
PKGS += LIBC_LINUX
LIBC_LINUX_HDRS = $(filter %.h,$(LIBC_FILES))
LIBC_LINUX_HDRS = $(filter %.h,$(LIBC_LINUX_FILES))
LIBC_LINUX_FILES := $(wildcard libc/linux/*)
LIBC_LINUX_CHECKS = $(LIBC_LINUX_HDRS:%=o/$(MODE)/%.ok)

2
libc/log/asan.c

@ -41,6 +41,8 @@
#include "libc/sysv/consts/prot.h"
#include "third_party/dlmalloc/dlmalloc.h"
STATIC_YOINK("_init_asan");
/**
* @fileoverview Cosmopolitan Address Sanitizer Runtime.
*

26
libc/log/checkfail.c

@ -31,6 +31,10 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
STATIC_YOINK("ftoa");
/**
* Handles failure of CHECK_xx() macros.
*/
@ -47,30 +51,30 @@ relegated void __check_fail(const char *suffix, const char *opstr,
if (!memccpy(sufbuf, suffix, '\0', sizeof(sufbuf))) strcpy(sufbuf, "?");
strtoupper(sufbuf);
fprintf(stderr,
"check failed\n"
"\tCHECK_%s(%s, %s);\n"
"\t\t → %#lx (%s)\n"
"\t\t%s %#lx (%s)\n",
sufbuf, wantstr, gotstr, want, wantstr, opstr, got, gotstr);
(fprintf)(stderr,
"check failed\n"
"\tCHECK_%s(%s, %s);\n"
"\t\t → %#lx (%s)\n"
"\t\t%s %#lx (%s)\n",
sufbuf, wantstr, gotstr, want, wantstr, opstr, got, gotstr);
if (!isempty(fmt)) {
fputc('\t', stderr);
va_start(va, fmt);
vfprintf(stderr, fmt, va);
(vfprintf)(stderr, fmt, va);
va_end(va);
fputc('\n', stderr);
}
fprintf(stderr, "\t%s\n\t%s%s%s%s\n", strerror(lasterr), SUBTLE,
getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET);
(fprintf)(stderr, "\t%s\n\t%s%s%s%s\n", strerror(lasterr), SUBTLE,
getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET);
for (i = 1; i < g_argc; ++i) {
fprintf(stderr, "\t\t%s%s\n", g_argv[i], i < g_argc - 1 ? " \\" : "");
(fprintf)(stderr, "\t\t%s%s\n", g_argv[i], i < g_argc - 1 ? " \\" : "");
}
if (!IsTiny() && lasterr == ENOMEM) {
fprintf(stderr, "\n");
(fprintf)(stderr, "\n");
fflush(stderr);
PrintMemoryIntervals(fileno(stderr), &_mmi);
}

2
libc/log/log.h

@ -15,7 +15,7 @@
* Log level for compile-time DCE.
*/
#ifndef LOGGABLELEVEL
#ifndef NDEBUG
#ifndef TINY
#define LOGGABLELEVEL kLogDebug
/* #elif IsTiny() */
/* #define LOGGABLELEVEL kLogInfo */

5
libc/log/log.mk

@ -65,6 +65,11 @@ $(LIBC_LOG_A_OBJS): \
$(NO_MAGIC) \
-fwrapv
ifeq (,$(MODE))
LIBC_LOG_ASAN = o/$(MODE)/libc/log/asan.o
endif
LIBC_LOG_ASAN_A = o/$(MODE)/libc/log/log.a
LIBC_LOG_LIBS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)))
LIBC_LOG_SRCS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_SRCS))
LIBC_LOG_HDRS = $(foreach x,$(LIBC_LOG_ARTIFACTS),$($(x)_HDRS))

24
libc/log/vflogf.c

@ -37,6 +37,10 @@
#define kNontrivialSize (8 * 1000 * 1000)
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
STATIC_YOINK("ftoa");
static int loglevel2char(unsigned level) {
switch (level) {
case kLogInfo:
@ -47,6 +51,8 @@ static int loglevel2char(unsigned level) {
return 'W';
case kLogFatal:
return 'F';
case kLogVerbose:
return 'V';
default:
return '?';
}
@ -80,8 +86,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
long double t2;
const char *prog;
int64_t secs, nsec, dots;
char zonebuf[8], *zonebufp;