From 13437dd19b52072a7ff09e3cdfb84b17989181ae Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 26 Dec 2020 02:09:07 -0800 Subject: [PATCH] Auto-generate some documentation --- Makefile | 5 + ape/config.h | 21 +- ape/relocations.h | 4 +- libc/alg/memmem.c | 14 +- libc/bits/abs.c | 3 + libc/bits/bitreverse16.c | 3 + libc/bits/bitreverse32.c | 3 + libc/bits/bitreverse64.c | 3 + libc/bits/bitreverse8.c | 3 + libc/bits/emptytonull.c | 9 +- libc/bits/firstnonnull.c | 3 + libc/bits/gray.c | 5 + libc/bits/hamming.c | 1 + libc/bits/hilbert.c | 6 +- libc/bits/isempty.c | 7 +- libc/bits/morton.c | 2 + libc/bits/nulltoempty.c | 9 +- libc/bits/popcnt.c | 3 + libc/bits/pushpop.h | 6 +- libc/bits/rounddown.c | 7 +- libc/bits/roundup.c | 3 + libc/bits/roundup2log.c | 2 +- libc/bits/roundup2pow.c | 2 +- libc/bits/ungray.c | 5 + libc/bits/unmorton.c | 1 + libc/calls/fchmod.c | 12 +- libc/calls/fcntl.c | 2 +- libc/calls/hefty/dirstream.c | 14 +- libc/calls/hefty/spawnve.c | 25 +- libc/calls/isatty.c | 2 +- libc/calls/kntprioritycombos.c | 55 ++- libc/calls/readansi.c | 16 +- libc/calls/setitimer.c | 31 +- libc/calls/sigaction.c | 8 +- libc/calls/sigprocmask.c | 6 +- libc/dce.h | 2 +- libc/elf/struct/rela.h | 2 +- libc/fmt/bing.c | 34 +- libc/integral/c.inc | 237 ------------- libc/integral/lp64.inc | 2 +- libc/integral/normalize.inc | 9 - libc/math.h | 5 - libc/mem/vasprintf.c | 2 +- libc/nexgen32e/ffs.S | 2 +- libc/nexgen32e/ffs.h | 24 +- libc/nexgen32e/ffsl.S | 2 +- libc/nexgen32e/kcpuids.h | 7 - libc/nt/thunk/msabi.h | 8 +- libc/rand/rand32.c | 2 +- libc/runtime/mmap.c | 6 +- libc/runtime/winmain.greg.c | 36 +- libc/stdio/g_stderr.c | 4 + libc/stdio/g_stdin.c | 4 + libc/stdio/g_stdout.c | 4 + libc/str/isalnum.c | 3 + libc/str/isalpha.c | 3 + libc/str/isascii.c | 3 + libc/str/isblank.c | 3 + libc/str/iscntrl.c | 3 + libc/str/isdigit.c | 3 + libc/str/islower.c | 3 + libc/str/isspace.c | 3 + libc/str/isupper.c | 3 + libc/str/iswcntrl.c | 3 + libc/str/isxdigit.c | 3 + libc/str/memccpy.c | 10 +- libc/str/stpncpy.c | 1 + libc/str/strncpy.c | 1 + libc/testlib/testrunner.c | 2 +- libc/time/strftime.c | 14 +- libc/unicode/strnwidth.c | 2 + libc/x/unbingbuf.c | 8 +- libc/x/unbingstr.c | 2 +- libc/x/xjoinpaths.c | 12 +- libc/x/xsigaction.c | 4 +- test/libc/nexgen32e/ffs_test.c | 45 +++ test/tool/build/lib/javadown_test.c | 230 +++++++++++++ third_party/chibicc/README.cosmo | 6 + third_party/chibicc/as.c | 184 ++++++---- third_party/chibicc/chibicc.c | 49 ++- third_party/chibicc/chibicc.h | 56 +++- third_party/chibicc/chibicc.mk | 1 + third_party/chibicc/codegen.c | 36 +- third_party/chibicc/dox1.c | 248 ++++++++++++++ third_party/chibicc/dox2.c | 392 ++++++++++++++++++++++ third_party/chibicc/parse.c | 107 +++++- third_party/chibicc/preprocess.c | 44 ++- third_party/chibicc/test/attribute_test.c | 3 +- third_party/chibicc/test/vla_test.c | 6 + third_party/chibicc/tokenize.c | 47 ++- third_party/dlmalloc/mallinfo.c | 35 +- third_party/musl/glob.c | 14 +- third_party/regex/regcomp.c | 8 +- third_party/zlib/zlib.h | 80 ++--- tool/build/lib/javadown.c | 276 +++++++++++++++ tool/build/lib/javadown.h | 24 ++ tool/emacs/javadown.el | 21 ++ 97 files changed, 2033 insertions(+), 661 deletions(-) create mode 100644 test/libc/nexgen32e/ffs_test.c create mode 100644 test/tool/build/lib/javadown_test.c create mode 100644 third_party/chibicc/dox1.c create mode 100644 third_party/chibicc/dox2.c create mode 100644 tool/build/lib/javadown.c create mode 100644 tool/build/lib/javadown.h diff --git a/Makefile b/Makefile index 35495a60..19c6794f 100644 --- a/Makefile +++ b/Makefile @@ -303,6 +303,7 @@ COSMOPOLITAN_HEADERS = \ THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MUSL \ + THIRD_PARTY_ZLIB \ THIRD_PARTY_REGEX o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_OBJS))) @@ -312,6 +313,10 @@ o/cosmopolitan.h: \ $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) @ACTION=ROLLUP TARGET=$@ build/do $^ >$@ +o/cosmopolitan.html: \ + o//third_party/chibicc/chibicc.com.dbg + o//third_party/chibicc/chibicc.com.dbg -J -fno-common -include libc/integral/normalize.inc -o $@ $(filter %.c,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) + # UNSPECIFIED PREREQUISITES TUTORIAL # # A build rule must exist for all files that make needs to consider in diff --git a/ape/config.h b/ape/config.h index b988bdec..440a6528 100644 --- a/ape/config.h +++ b/ape/config.h @@ -3,11 +3,7 @@ #include "ape/relocations.h" #include "libc/macros.h" -/** - * @fileverview αcτµαlly pδrταblε εxεcµταblε configuration. - */ - -/** +/* * Post-Initialization Read-Only Code Size Threshold. * * An executable needs to have at least this much code, before the @@ -22,9 +18,6 @@ #endif #endif -/** - * PC Standard I/O Configuration. - */ #ifndef METAL_STDIN #define METAL_STDIN COM1 #endif @@ -35,11 +28,6 @@ #define METAL_STDERR COM1 #endif -/** - * PC Display Configuration (MDA/CGA) - * @see www.lammertbies.nl/comm/info/serial-uart.html - * @see ape/lib/vidya.internal.h - */ #ifndef VIDYA_MODE #define VIDYA_MODE VIDYA_MODE_CGA #endif @@ -66,10 +54,6 @@ #define X87_DEFAULT X87_NORMAL #endif -/** - * Serial Line Configuration (8250 UART 16550) - * @see ape/lib/uart.h - */ #ifndef UART_BAUD_RATE #define UART_BAUD_RATE 9600 /* bits per second ∈ [50,115200] */ #endif @@ -93,9 +77,6 @@ #define UART_CONF_LCR 0b01000011 #endif -/** - * eXtreme Low Memory. - */ #define XLM(VAR) (XLM_BASE_REAL + XLM_##VAR) #define XLMV(VAR) (__xlm + XLM_##VAR) #define XLM_BASE_REAL 0x1000 diff --git a/ape/relocations.h b/ape/relocations.h index 6dc3ad38..1500d2b6 100644 --- a/ape/relocations.h +++ b/ape/relocations.h @@ -19,23 +19,23 @@ #define IMAGE_BASE_PHYSICAL 0x100000 #endif +#ifndef REAL_SCRATCH_AREA /** * Location of anything goes memory for real mode. * * The MBR won't load program content beyond this address, so we have * room for buffers, page tables, etc. before we reach the stack frame. */ -#ifndef REAL_SCRATCH_AREA #define REAL_SCRATCH_AREA 0x40000 #endif +#ifndef REAL_STACK_FRAME /** * Location of real mode 64kb stack frame. * * This address was chosen because memory beyond 0x80000 can't be * accessed safely without consulting e820. */ -#ifndef REAL_STACK_FRAME #define REAL_STACK_FRAME 0x70000 #endif diff --git a/libc/alg/memmem.c b/libc/alg/memmem.c index 666a5faf..196cc863 100644 --- a/libc/alg/memmem.c +++ b/libc/alg/memmem.c @@ -21,12 +21,8 @@ #include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/str/str.h" -/* clang-format off */ -static void KnuthMorrisPrattInit(m, T, W) - ssize_t m, T[m + 1]; - const char W[m]; -{ +static void KnuthMorrisPrattInit(ssize_t m, ssize_t *T, const char *W) { ssize_t i = 2; ssize_t j = 0; T[0] = -1; @@ -43,10 +39,8 @@ static void KnuthMorrisPrattInit(m, T, W) T[m] = 0; } -static size_t KnuthMorrisPratt(m, T, W, n, S) - const long n, m, T[m + 1]; - const char W[m], S[n]; -{ +static size_t KnuthMorrisPratt(long m, const long *T, const char *W, long n, + const char *S) { long i = 0, j = 0; while (i + j < n) { if (W[i] == S[i + j]) { @@ -60,8 +54,6 @@ static size_t KnuthMorrisPratt(m, T, W, n, S) return j; } -/* clang-format on */ - /** * Searches for fixed-length substring in memory region. * diff --git a/libc/bits/abs.c b/libc/bits/abs.c index b3735735..655af5c2 100644 --- a/libc/bits/abs.c +++ b/libc/bits/abs.c @@ -20,6 +20,9 @@ #include "libc/fmt/conv.h" #include "libc/macros.h" +/** + * Returns absolute value of x. + */ int(abs)(int x) { return ABS(x); } diff --git a/libc/bits/bitreverse16.c b/libc/bits/bitreverse16.c index b6b44167..69123510 100644 --- a/libc/bits/bitreverse16.c +++ b/libc/bits/bitreverse16.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Reverses bits in 16-bit word. + */ uint16_t(bitreverse16)(uint16_t x) { return kReverseBits[x & 0x00FF] << 8 | kReverseBits[(x & 0xFF00) >> 8]; } diff --git a/libc/bits/bitreverse32.c b/libc/bits/bitreverse32.c index 9ccc86d1..acae9021 100644 --- a/libc/bits/bitreverse32.c +++ b/libc/bits/bitreverse32.c @@ -20,6 +20,9 @@ #include "libc/bits/bits.h" #include "libc/bits/bswap.h" +/** + * Reverses bits in 32-bit word. + */ uint32_t(bitreverse32)(uint32_t x) { x = bswap_32(x); x = ((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1); diff --git a/libc/bits/bitreverse64.c b/libc/bits/bitreverse64.c index 8e9310eb..06e2156b 100644 --- a/libc/bits/bitreverse64.c +++ b/libc/bits/bitreverse64.c @@ -20,6 +20,9 @@ #include "libc/bits/bits.h" #include "libc/bits/bswap.h" +/** + * Reverses bits in 64-bit word. + */ uint64_t bitreverse64(uint64_t x) { x = bswap_64(x); x = ((x & 0xaaaaaaaaaaaaaaaa) >> 1) | ((x & 0x5555555555555555) << 1); diff --git a/libc/bits/bitreverse8.c b/libc/bits/bitreverse8.c index fdf3d9ca..813790cb 100644 --- a/libc/bits/bitreverse8.c +++ b/libc/bits/bitreverse8.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Reverses bits in 8-bit word. + */ uint8_t(bitreverse8)(uint8_t x) { return kReverseBits[x]; } diff --git a/libc/bits/emptytonull.c b/libc/bits/emptytonull.c index 059f16e6..0c70c0ba 100644 --- a/libc/bits/emptytonull.c +++ b/libc/bits/emptytonull.c @@ -17,5 +17,12 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/safemacros.internal.h" -const char *emptytonull(const char *s) { return s && !*s ? 0 : s; } +/** + * Returns string where empty string is made null. + * @see nulltoempty() + */ +const char *(emptytonull)(const char *s) { + return s && !*s ? 0 : s; +} diff --git a/libc/bits/firstnonnull.c b/libc/bits/firstnonnull.c index 3bcd6727..5160bb89 100644 --- a/libc/bits/firstnonnull.c +++ b/libc/bits/firstnonnull.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/runtime.h" +/** + * Returns a or b or aborts if both are null. + */ const char *(firstnonnull)(const char *a, const char *b) { if (a) return a; if (b) return b; diff --git a/libc/bits/gray.c b/libc/bits/gray.c index f941c23b..d2530c73 100644 --- a/libc/bits/gray.c +++ b/libc/bits/gray.c @@ -19,6 +19,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Returns gray code for x. + * @see https://en.wikipedia.org/wiki/Gray_code + * @see ungray() + */ uint32_t gray(uint32_t x) { return x ^ (x >> 1); } diff --git a/libc/bits/hamming.c b/libc/bits/hamming.c index 0e9807d6..71595b38 100644 --- a/libc/bits/hamming.c +++ b/libc/bits/hamming.c @@ -21,6 +21,7 @@ /** * Counts number of different bits. + * @see https://en.wikipedia.org/wiki/Hamming_code */ unsigned long hamming(unsigned long x, unsigned long y) { return popcnt(x ^ y); diff --git a/libc/bits/hilbert.c b/libc/bits/hilbert.c index b2ed8d7c..2b8b2afa 100644 --- a/libc/bits/hilbert.c +++ b/libc/bits/hilbert.c @@ -36,7 +36,8 @@ static axdx_t RotateQuadrant(long n, long y, long x, long ry, long rx) { /** * Generates Hilbert space-filling curve. * - * @see morton() + * @see https://en.wikipedia.org/wiki/Hilbert_curve + * @see unhilbert() */ long hilbert(long n, long y, long x) { axdx_t m; @@ -56,7 +57,8 @@ long hilbert(long n, long y, long x) { /** * Decodes Hilbert space-filling curve. * - * @see unmorton() + * @see https://en.wikipedia.org/wiki/Hilbert_curve + * @see hilbert() */ axdx_t unhilbert(long n, long i) { axdx_t m; diff --git a/libc/bits/isempty.c b/libc/bits/isempty.c index 22734db0..ed7dc6be 100644 --- a/libc/bits/isempty.c +++ b/libc/bits/isempty.c @@ -18,4 +18,9 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -bool isempty(const char *s) { return !s || !*s; } +/** + * Returns true if s is empty string or null. + */ +bool isempty(const char *s) { + return !s || !*s; +} diff --git a/libc/bits/morton.c b/libc/bits/morton.c index 680bf437..78ac08b4 100644 --- a/libc/bits/morton.c +++ b/libc/bits/morton.c @@ -21,6 +21,8 @@ /** * Interleaves bits. + * @see https://en.wikipedia.org/wiki/Z-order_curve + * @see unmorton() */ unsigned long(morton)(unsigned long y, unsigned long x) { x = (x | x << 020) & 0x0000FFFF0000FFFF; diff --git a/libc/bits/nulltoempty.c b/libc/bits/nulltoempty.c index 524ba5e9..df5087db 100644 --- a/libc/bits/nulltoempty.c +++ b/libc/bits/nulltoempty.c @@ -17,5 +17,12 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/safemacros.internal.h" -const char *nulltoempty(const char *s) { return s ? s : ""; } +/** + * Returns 𝑠 converting null to empty string. + * @see emptytonull() + */ +const char *(nulltoempty)(const char *s) { + return s ? s : ""; +} diff --git a/libc/bits/popcnt.c b/libc/bits/popcnt.c index 02619b97..2c522bd2 100644 --- a/libc/bits/popcnt.c +++ b/libc/bits/popcnt.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/popcnt.h" +/** + * Returns number of bits set in integer. + */ uint64_t(popcnt)(uint64_t x) { x = x - ((x >> 1) & 0x5555555555555555); x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333); diff --git a/libc/bits/pushpop.h b/libc/bits/pushpop.h index 57c223fa..44dfd4ca 100644 --- a/libc/bits/pushpop.h +++ b/libc/bits/pushpop.h @@ -3,13 +3,13 @@ #include "libc/macros.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) +#if !defined(__GNUC__) || defined(__STRICT_ANSI__) +#define pushpop(x) (x) +#else /** * PushPop * An elegant weapon for a more civilized age. */ -#if !defined(__GNUC__) || defined(__STRICT_ANSI__) -#define pushpop(x) (x) -#else #define pushpop(x) \ ({ \ typeof(x) Popped; \ diff --git a/libc/bits/rounddown.c b/libc/bits/rounddown.c index 44b01586..d9b23c3f 100644 --- a/libc/bits/rounddown.c +++ b/libc/bits/rounddown.c @@ -19,4 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -long(rounddown)(long w, long k) { return ROUNDDOWN(w, k); } +/** + * Rounds down 𝑤 to next two power 𝑘. + */ +long(rounddown)(long w, long k) { + return ROUNDDOWN(w, k); +} diff --git a/libc/bits/roundup.c b/libc/bits/roundup.c index dc822845..b27d18a7 100644 --- a/libc/bits/roundup.c +++ b/libc/bits/roundup.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" +/** + * Rounds up 𝑤 to next two power 𝑘. + */ long(roundup)(long w, long k) { return ROUNDUP(w, k); } diff --git a/libc/bits/roundup2log.c b/libc/bits/roundup2log.c index 843e3501..d93e7c69 100644 --- a/libc/bits/roundup2log.c +++ b/libc/bits/roundup2log.c @@ -22,7 +22,7 @@ /** * Returns 𝑥 rounded up to next two power and log'd. - * @see roundup2pow + * @see roundup2pow() */ unsigned long roundup2log(unsigned long x) { return x > 1 ? (bsrl(x - 1) + 1) : x ? 1 : 0; diff --git a/libc/bits/roundup2pow.c b/libc/bits/roundup2pow.c index d4ae7baf..483e173e 100644 --- a/libc/bits/roundup2pow.c +++ b/libc/bits/roundup2pow.c @@ -24,7 +24,7 @@ * Returns 𝑥 rounded up to next two power. * * @define (𝑥>0→2^⌈log₂x⌉, x=0→0, 𝑇→⊥) - * @see rounddown2pow)() + * @see rounddown2pow() */ unsigned long roundup2pow(unsigned long x) { return x > 1 ? 1ul << (bsrl(x - 1) + 1) : x ? 1 : 0; diff --git a/libc/bits/ungray.c b/libc/bits/ungray.c index d37dc86f..ee7ec8e8 100644 --- a/libc/bits/ungray.c +++ b/libc/bits/ungray.c @@ -19,6 +19,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +/** + * Decodes gray code. + * @see https://en.wikipedia.org/wiki/Gray_code + * @see gray() + */ uint32_t ungray(uint32_t x) { x ^= x >> 16; x ^= x >> 8; diff --git a/libc/bits/unmorton.c b/libc/bits/unmorton.c index e54d2d98..103f01d7 100644 --- a/libc/bits/unmorton.c +++ b/libc/bits/unmorton.c @@ -35,6 +35,7 @@ static unsigned long GetOddBits(unsigned long x) { * @param 𝑖 is interleaved index * @return deinterleaved coordinate {ax := 𝑦, dx := 𝑥} * @see en.wikipedia.org/wiki/Z-order_curve + * @see morton() */ axdx_t(unmorton)(unsigned long i) { return (axdx_t){GetOddBits(i >> 1), GetOddBits(i)}; diff --git a/libc/calls/fchmod.c b/libc/calls/fchmod.c index 83988fe7..58f23ff8 100644 --- a/libc/calls/fchmod.c +++ b/libc/calls/fchmod.c @@ -25,15 +25,15 @@ /** * Changes file permissions via open()'d file descriptor, e.g.: * - * CHECK_NE(-1, chmod("foo/bar.txt", 0644)); - * CHECK_NE(-1, chmod("o/default/program.com", 0755)); - * CHECK_NE(-1, chmod("privatefolder/", 0700)); + * CHECK_NE(-1, chmod("foo/bar.txt", 0644)); + * CHECK_NE(-1, chmod("o/default/program.com", 0755)); + * CHECK_NE(-1, chmod("privatefolder/", 0700)); * * The esoteric bits generally available on System V are: * - * CHECK_NE(-1, chmod("/opt/", 01000)); // sticky bit - * CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit - * CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit + * CHECK_NE(-1, chmod("/opt/", 01000)); // sticky bit + * CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit + * CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit * * This works on Windows NT if you ignore the error ;-) * diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index f5fec2a8..9e42702a 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -24,7 +24,7 @@ /** * Does things with file descriptor, via re-imagined hourglass api, e.g. * - * CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC)); + * CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC)); * * @param cmd can be F_{GET,SET}{FD,FL}, etc. * @param arg can be FD_CLOEXEC, etc. depending diff --git a/libc/calls/hefty/dirstream.c b/libc/calls/hefty/dirstream.c index 1b085706..8218ff5b 100644 --- a/libc/calls/hefty/dirstream.c +++ b/libc/calls/hefty/dirstream.c @@ -118,13 +118,13 @@ static textwindows noinline struct dirent *readdir$nt(DIR *dir) { /** * Opens directory, e.g. * - * DIR *d; - * struct dirent *e; - * CHECK((d = opendir(path))); - * while ((e = readdir(d))) { - * printf("%s/%s\n", path, e->d_name); - * } - * LOGIFNEG1(closedir(d)); + * DIR *d; + * struct dirent *e; + * CHECK((d = opendir(path))); + * while ((e = readdir(d))) { + * printf("%s/%s\n", path, e->d_name); + * } + * LOGIFNEG1(closedir(d)); * * @returns newly allocated DIR object, or NULL w/ errno * @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM diff --git a/libc/calls/hefty/spawnve.c b/libc/calls/hefty/spawnve.c index 31dff906..eabe6d28 100644 --- a/libc/calls/hefty/spawnve.c +++ b/libc/calls/hefty/spawnve.c @@ -27,18 +27,18 @@ /** * Launches program, e.g. * - * char buf[2]; - * int ws, pid, fds[3] = {-1, -1, STDERR_FILENO}; - * CHECK_NE(-1, (pid = spawnve(0, fds, commandv("ssh"), - * (char *const[]){"ssh", hostname, "cat", NULL}, - * environ))); - * CHECK_EQ(+2, write(fds[0], "hi", 2)); - * CHECK_NE(-1, close(fds[0])); - * CHECK_EQ(+2, read(fds[1], buf, 2))); - * CHECK_NE(-1, close(fds[1])); - * CHECK_EQ(+0, memcmp(buf, "hi", 2))); - * CHECK_NE(-1, waitpid(pid, &ws, 0)); - * CHECK_EQ(+0, WEXITSTATUS(ws)); + * char buf[2]; + * int ws, pid, fds[3] = {-1, -1, STDERR_FILENO}; + * CHECK_NE(-1, (pid = spawnve(0, fds, commandv("ssh"), + * (char *const[]){"ssh", hostname, "cat", 0}, + * environ))); + * CHECK_EQ(+2, write(fds[0], "hi", 2)); + * CHECK_NE(-1, close(fds[0])); + * CHECK_EQ(+2, read(fds[1], buf, 2))); + * CHECK_NE(-1, close(fds[1])); + * CHECK_EQ(+0, memcmp(buf, "hi", 2))); + * CHECK_NE(-1, waitpid(pid, &ws, 0)); + * CHECK_EQ(+0, WEXITSTATUS(ws)); * * @param stdiofds may optionally be passed to customize standard i/o * @param stdiofds[𝑖] may be -1 to receive a pipe() fd @@ -49,6 +49,7 @@ * @param envp[0,n-2] specifies "foo=bar" environment variables * @param envp[n-1] is NULL * @return pid of child, or -1 w/ errno + * @deprecated just use vfork() and execve() */ int spawnve(unsigned flags, int stdiofds[3], const char *program, char *const argv[], char *const envp[]) { diff --git a/libc/calls/isatty.c b/libc/calls/isatty.c index 1002046c..07f94d56 100644 --- a/libc/calls/isatty.c +++ b/libc/calls/isatty.c @@ -27,7 +27,7 @@ * @asyncsignalsafe */ bool32 isatty(int fd) { - char buf[sizeof(uint16_t) * 4] forcealign(2); + _Alignas(short) char buf[sizeof(uint16_t) * 4]; if (!IsWindows()) { return ioctl$sysv(fd, TIOCGWINSZ, &buf) != -1; } else { diff --git a/libc/calls/kntprioritycombos.c b/libc/calls/kntprioritycombos.c index ce88bcd9..13853576 100644 --- a/libc/calls/kntprioritycombos.c +++ b/libc/calls/kntprioritycombos.c @@ -21,38 +21,37 @@ #include "libc/calls/kntprioritycombos.internal.h" #include "libc/limits.h" #include "libc/macros.h" +#include "libc/nexgen32e/ffs.h" #include "libc/nt/enum/processcreationflags.h" #include "libc/nt/enum/threadpriority.h" -#define FFS(x) __builtin_ffs(x) - const struct NtPriorityCombo kNtPriorityCombos[] = { - {-20, FFS(kNtHighPriorityClass), kNtThreadPriorityHighest, 15}, - {-18, FFS(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15}, - {-17, FFS(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15}, - {-15, FFS(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15}, - {-13, FFS(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14}, - {-11, FFS(kNtHighPriorityClass), kNtThreadPriorityNormal, 13}, - {-9, FFS(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12}, - {-7, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11}, - {-5, FFS(kNtHighPriorityClass), kNtThreadPriorityLowest, 11}, - {-3, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10}, - {-1, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9}, - {0, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9}, - {1, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8}, - {2, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8}, - {3, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7}, - {4, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7}, - {5, FFS(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6}, - {6, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6}, - {7, FFS(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5}, - {9, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5}, - {11, FFS(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4}, - {13, FFS(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3}, - {15, FFS(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2}, - {17, FFS(kNtHighPriorityClass), kNtThreadPriorityIdle, 1}, - {18, FFS(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1}, - {19, FFS(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1}, + {-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15}, + {-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15}, + {-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15}, + {-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15}, + {-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14}, + {-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13}, + {-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12}, + {-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11}, + {-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11}, + {-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10}, + {-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9}, + {0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9}, + {1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8}, + {2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8}, + {3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7}, + {4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7}, + {5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6}, + {6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6}, + {7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5}, + {9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5}, + {11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4}, + {13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3}, + {15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2}, + {17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1}, + {18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1}, + {19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1}, }; const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos); diff --git a/libc/calls/readansi.c b/libc/calls/readansi.c index 2f16a63d..92a60975 100644 --- a/libc/calls/readansi.c +++ b/libc/calls/readansi.c @@ -29,11 +29,11 @@ * how long each sequence is, so that each read consumes a single thing * from the underlying file descriptor, e.g. * - * "a" ALFA - * "\316\261" ALPHA - * "\033[A" CURSOR UP - * "\033[38;5;202m" ORANGERED - * "\eOP" PF1 + * "a" ALFA + * "\316\261" ALPHA + * "\033[A" CURSOR UP + * "\033[38;5;202m" ORANGERED + * "\eOP" PF1 * * This routine generalizes to ascii, utf-8, chorded modifier keys, * function keys, color codes, c0/c1 control codes, cursor movement, @@ -48,9 +48,9 @@ * tokenized as a single read. Lastly note, this function has limited * support for UNICODE representations of C0/C1 control codes, e.g. * - * "\000" NUL - * "\300\200" NUL - * "\302\233A" CURSOR UP + * "\000" NUL + * "\300\200" NUL + * "\302\233A" CURSOR UP * * @param buf is guaranteed to receive a NUL terminator if size>0 * @return number of bytes read (helps differentiate "\0" vs. "") diff --git a/libc/calls/setitimer.c b/libc/calls/setitimer.c index 4cf00541..97544bd0 100644 --- a/libc/calls/setitimer.c +++ b/libc/calls/setitimer.c @@ -28,27 +28,28 @@ * * Raise SIGALRM every 1.5s: * - * CHECK_NE(-1, sigaction(SIGALRM, - * &(struct sigaction){.sa_sigaction = missingno}, - * NULL)); - * CHECK_NE(-1, setitimer(ITIMER_REAL, - * &(const struct itimerval){{1, 500000}, {1, 500000}}, - * NULL)); + * CHECK_NE(-1, sigaction(SIGALRM, + * &(struct sigaction){.sa_sigaction = missingno}, + * NULL)); + * CHECK_NE(-1, setitimer(ITIMER_REAL, + * &(const struct itimerval){{1, 500000}, + * {1, 500000}}, + * NULL)); * * Set single-shot 50ms timer callback to interrupt laggy connect(): * - * CHECK_NE(-1, sigaction(SIGALRM, - * &(struct sigaction){.sa_sigaction = missingno, - * .sa_flags = SA_RESETHAND}, - * NULL)); - * CHECK_NE(-1, setitimer(ITIMER_REAL, - * &(const struct itimerval){{0, 0}, {0, 50000}}, - * NULL)); - * if (connect(...) == -1 && errno == EINTR) { ... } + * CHECK_NE(-1, sigaction(SIGALRM, + * &(struct sigaction){.sa_sigaction = missingno, + * .sa_flags = SA_RESETHAND}, + * NULL)); + * CHECK_NE(-1, setitimer(ITIMER_REAL, + * &(const struct itimerval){{0, 0}, {0, 50000}}, + * NULL)); + * if (connect(...) == -1 && errno == EINTR) { ... } * * Disarm timer: * - * CHECK_NE(-1, setitimer(ITIMER_REAL, &(const struct itimerval){0}, NULL)); + * CHECK_NE(-1, setitimer(ITIMER_REAL, &(const struct itimerval){0}, NULL)); * * Be sure to check for EINTR on your i/o calls, for best low latency. * diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 18f92556..b4383ba2 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -112,10 +112,10 @@ static void sigaction$native2cosmo(union metasigaction *sa) { /** * Installs handler for kernel interrupt, e.g.: * - * void GotCtrlC(int sig, siginfo_t *si, ucontext_t *ctx); - * struct sigaction sa = {.sa_sigaction = GotCtrlC, - * .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO}; - * CHECK_NE(-1, sigaction(SIGINT, &sa, NULL)); + * void GotCtrlC(int sig, siginfo_t *si, ucontext_t *ctx); + * struct sigaction sa = {.sa_sigaction = GotCtrlC, + * .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO}; + * CHECK_NE(-1, sigaction(SIGINT, &sa, NULL)); * * @see xsigaction() for a much better api * @asyncsignalsafe diff --git a/libc/calls/sigprocmask.c b/libc/calls/sigprocmask.c index ac32bfe1..fc8d3e4d 100644 --- a/libc/calls/sigprocmask.c +++ b/libc/calls/sigprocmask.c @@ -26,9 +26,9 @@ /** * Changes program signal blocking state, e.g.: * - * sigset_t oldmask; - * sigprocmask(SIG_BLOCK, &kSigsetFull, &oldmask); - * sigprocmask(SIG_SETMASK, &oldmask, NULL); + * sigset_t oldmask; + * sigprocmask(SIG_BLOCK, &kSigsetFull, &oldmask); + * sigprocmask(SIG_SETMASK, &oldmask, NULL); * * @param how can be SIG_BLOCK (U), SIG_UNBLOCK (/), SIG_SETMASK (=) * @param set is the new mask content (optional) diff --git a/libc/dce.h b/libc/dce.h index 0179c04e..24992054 100644 --- a/libc/dce.h +++ b/libc/dce.h @@ -5,6 +5,7 @@ │ cosmopolitan § autotune » dead code elimination │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#ifndef SUPPORT_VECTOR /** * Supported Platforms Tuning Knob (Runtime & Compile-Time) * @@ -17,7 +18,6 @@ * offer marginal improvements in terms of code size and performance, at * the cost of portability. */ -#ifndef SUPPORT_VECTOR #define SUPPORT_VECTOR 0b11111111 #endif #define LINUX 1 diff --git a/libc/elf/struct/rela.h b/libc/elf/struct/rela.h index 51f0f68f..5fcbc8ea 100644 --- a/libc/elf/struct/rela.h +++ b/libc/elf/struct/rela.h @@ -10,7 +10,7 @@ typedef struct Elf64_Rela { * ELF64_R_TYPE(r_info) → R_X86_64_{64,PC32,GOTPCRELX,...} * ELF64_R_INFO(sym, type) → r_info */ - /*u64*/ Elf64_Xword r_info; /** @see ELF64_R_{SYM,SIZE,INFO} */ + /*u64*/ Elf64_Xword r_info; /* ELF64_R_{SYM,SIZE,INFO} */ /*i64*/ Elf64_Sxword r_addend; } Elf64_Rela; diff --git a/libc/fmt/bing.c b/libc/fmt/bing.c index aab1a120..db9ef0ec 100644 --- a/libc/fmt/bing.c +++ b/libc/fmt/bing.c @@ -26,23 +26,23 @@ * * Cosmopolitan displays RADIX-256 numbers using these digits: * - * 0123456789abcdef - * 0 ☺☻♥♦♣♠•◘○◙♂♀♪♫☼ - * 1►◄↕‼¶§▬↨↑↓→←∟↔▲▼ - * 2 !"#$%&'()*+,-./ - * 30123456789:;<=>? - * 4@ABCDEFGHIJKLMNO - * 5PQRSTUVWXYZ[\]^_ - * 6`abcdefghijklmno - * 7pqrstuvwxyz{|}~⌂ - * 8ÇüéâäàåçêëèïîìÄÅ - * 9ÉæÆôöòûùÿÖÜ¢£¥€ƒ - * aáíóúñѪº¿⌐¬½¼¡«» - * b░▒▓│┤╡╢╖╕╣║╗╝╜╛┐ - * c└┴┬├─┼╞╟╚╔╩╦╠═╬╧ - * d╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ - * eαßΓπΣσμτΦΘΩδ∞φε∩ - * f≡±≥≤⌠⌡÷≈°∙·√ⁿ²■λ + * 0123456789abcdef + * 0 ☺☻♥♦♣♠•◘○◙♂♀♪♫☼ + * 1►◄↕‼¶§▬↨↑↓→←∟↔▲▼ + * 2 !"#$%&'()*+,-./ + * 30123456789:;<=>? + * 4@ABCDEFGHIJKLMNO + * 5PQRSTUVWXYZ[\]^_ + * 6`abcdefghijklmno + * 7pqrstuvwxyz{|}~⌂ + * 8ÇüéâäàåçêëèïîìÄÅ + * 9ÉæÆôöòûùÿÖÜ¢£¥€ƒ + * aáíóúñѪº¿⌐¬½¼¡«» + * b░▒▓│┤╡╢╖╕╣║╗╝╜╛┐ + * c└┴┬├─┼╞╟╚╔╩╦╠═╬╧ + * d╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ + * eαßΓπΣσμτΦΘΩδ∞φε∩ + * f≡±≥≤⌠⌡÷≈°∙·√ⁿ²■λ * * IBM designed these glyphs for the PC to map onto the display bytes at * (char *)0xb8000. Because IBM authorized buyers of its PCs to inspect diff --git a/libc/integral/c.inc b/libc/integral/c.inc index f1f51b9b..05357b08 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -18,10 +18,6 @@ #define __far #endif -/** - * Gets type of expression. - * @see autotype() which is a better alternative for certain use cases - */ #if !defined(__GNUC__) && __cplusplus + 0 >= 201103L #define typeof(x) decltype(x) #elif (defined(__STRICT_ANSI__) || !defined(__GNUC__)) && \ @@ -143,35 +139,10 @@ typedef __UINT32_TYPE__ uint32_t; typedef __INT64_TYPE__ int64_t; typedef __UINT64_TYPE__ uint64_t; -/** - * AX:DX register pair. - * - * Every ABI we support permits functions to return two machine words. - * Normally it's best to define a one-off struct. Sometimes we don't - * want the boilerplate. - * - * @see System V Application Binary Interface NexGen32e Architecture - * Processor Supplement, Version 1.0, December 5th, 2018 - * @see agner.org/optimize/calling_conventions.pdf (chapter 6) - * @see LISP primitives CONS[CAR,CDR] w/ IBM 704 naming - * @see int128_t - */ typedef struct { intptr_t ax, dx; } axdx_t; -/* - * GCC, Clang, and System V ABI all incorrectly define intmax_t. - * - * “[intmax_t] designates a signed integer type capable of - * representing any value of any signed integer type.” - * ──Quoth ISO/IEC 9899:201x 7.20.1.5 - * - * This surprising contradiction is most likely due to Linux distro - * practices of using dynamic shared objects which needs to change. - * - * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2303.pdf - */ #ifdef __SIZEOF_INTMAX__ #undef __SIZEOF_INTMAX__ #endif @@ -210,11 +181,6 @@ typedef uint64_t uintmax_t; #define mallocesque reallocesque returnspointerwithnoaliases #define interruptfn nocallersavedregisters forcealignargpointer -/** - * Declares combinator, i.e. never reads/writes global memory. - * Thus enabling LICM, CSE, DCE, etc. optimizations. - * @see nosideeffect - */ #ifndef pureconst #ifndef __STRICT_ANSI__ #define pureconst __attribute__((__const__)) @@ -223,9 +189,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Aligns automatic or static variable. - */ #ifndef forcealign #ifndef __STRICT_ANSI__ #define forcealign(bytes) __attribute__((__aligned__(bytes))) @@ -234,21 +197,12 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Disables alignment. - * @param opt_bytes defaults to __BIGGEST_ALIGNMENT__ - * @see nosideeffect - */ #ifndef __STRICT_ANSI__ #define thatispacked __attribute__((__packed__)) #else #define thatispacked #endif -/** - * Declares prototype as using well-known format string DSL. - * Thereby allowing compiler to identify certain bugs. - */ #ifndef __STRICT_ANSI__ #define printfesque(n) __attribute__((__format__(__gnu_printf__, n, n + 1))) #define scanfesque(n) __attribute__((__format__(__gnu_scanf__, n, n + 1))) @@ -297,11 +251,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype as never mutating global memory. - * Thus enabling CSE, DCE, LICM [clang-only?], etc. optimizations. - * @see pureconst - */ #ifndef nosideeffect #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__pure__) || \ @@ -332,18 +281,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Makes function behave as much like macro as possible, meaning: - * - * 1. always inlined, i.e. even with -fno-inline - * 2. unlinkable, i.e. elf data is not generated - * 3. steppable, i.e. dwarf data is generated - * 4. unprofilable - * 5. unhookable - * - * @note consider static or writing a macro - * @see externinline - */ #ifndef forceinline #ifdef __cplusplus #define forceinline inline @@ -372,19 +309,6 @@ typedef uint64_t uintmax_t; #endif /* __cplusplus */ #endif /* forceinline */ -/** - * Permits untyped or punned memory manipulation w/o asm. - * - * “The fundamental problem is that it is not possible to write real - * programs using the X3J11 definition of C. The committee has created - * an unreal language that no one can or will actually use. While the - * problems of `const' may owe to careless drafting of the - * specification, `noalias' is an altogether mistaken notion, and must - * not survive.” ──Dennis Ritchie in 1988-03-20. - * - * @see asm(), memcpy(), memset(), read32be(), etc. - * @see unsigned char - */ #ifndef mayalias #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__may_alias__) || \ @@ -395,11 +319,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype as returning freeable resource. - * Compilation will fail if caller ignores return value. - * @see gc(), free(), close(), etc. - */ #ifndef nodiscard #if !defined(__STRICT_ANSI__) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \ @@ -410,10 +329,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares variadic function as needing NULL sentinel argument. - * @see execl() for example - */ #ifndef nullterminated #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__sentinel__) || __GNUC__ >= 4) @@ -448,10 +363,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Relocates function to .text.unlikely section of binary. - * @note can be used to minimize page-faults and improve locality - */ #ifndef relegated #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__cold__) || \ @@ -470,11 +381,6 @@ typedef uint64_t uintmax_t; #define warnifused(s) #endif -/** - * Relocates function to .text.hot section of binary. - * @note can be used to minimize page-faults w/ improved locality - * @note most appropriately automated by profile-guided opts - */ #ifndef firstclass #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__hot__) || \ @@ -485,12 +391,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares all or specific parameters as never receiving NULL. - * - * This can be checked at both compile-time (only for constexprs) and - * runtime too (only in MODE=dbg mode) by synthetic Ubsan code. - */ #ifndef paramsnonnull #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__nonnull__) || \ @@ -501,22 +401,12 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares array argument w/ minimum size contract, e.g. - * - * int foo(int bar[hasatleast 2]) { ... } - */ #if __STDC_VERSION__ + 0 >= 199901L #define hasatleast static #else #define hasatleast #endif -/** - * Qualifies char pointer so it's treated like every other type. - * - * int foo(int bar[hasatleast 2]) { ... } - */ #if __STDC_VERSION__ + 0 < 199901L && !defined(restrict) #if !defined(__STRICT_ANSI__) && !defined(__cplusplus) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301 || defined(_MSC_VER)) @@ -527,10 +417,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype that can't mutate caller's static variables. - * @note consider more .c files or declare in function - */ #ifndef nocallback #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__leaf__) || \ @@ -554,11 +440,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to not optimize function definition. - * - * @todo this is dangerous delete? - */ #ifndef nooptimize #ifndef __STRICT_ANSI__ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ @@ -572,13 +453,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to generate as little code as possible for function. - * - * This does the same thing as relegated, but without relocation. - * - * @todo this is dangerous delete? - */ #ifndef optimizesize #ifndef __STRICT_ANSI__ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ @@ -592,15 +466,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to always heavily optimize function. - * - * This keyword provides an alternative to build flag tuning, in cases - * where the compiler is reluctant to vectorize mathematical code that's - * written in standards-compliant C rather than GCC extensions. - * - * @todo this is dangerous delete? - */ #ifndef optimizespeed #if !defined(__STRICT_ANSI__) && \ ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ @@ -611,9 +476,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Declares prototype that behaves similar to setjmp() or vfork(). - */ #ifndef returnstwice #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__returns_twice__) || \ @@ -624,10 +486,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Asks compiler to not emit DWARF assembly for function. - * @see artificial - */ #ifndef nodebuginfo #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__nodebug__) || defined(__llvm__)) @@ -637,10 +495,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Associates debug information with call site. - * @see nodebuginfo - */ #ifndef artificial #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__artificial__) || \ @@ -651,11 +505,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Defines function as specially compiled for newer cpu model. - * @see -ftree-vectorize and consider assembly - * @see libc/dce.h - */ #ifndef microarchitecture #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__target__) || \ @@ -666,10 +515,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Compiles function multiple times for different cpu models. - * @see libc/dce.h - */ #ifndef targetclones #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__target_clones__) || __GNUC__ >= 6) @@ -679,10 +524,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Defines function with prologue that fixes misaligned stack. - * @see nocallersavedregisters and consider assembly - */ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ __has_attribute(__force_align_arg_pointer__) #define forcealignargpointer __attribute__((__force_align_arg_pointer__)) @@ -690,12 +531,6 @@ typedef uint64_t uintmax_t; #define forcealignargpointer "need modern compiler" #endif -/** - * Declares prototype as never returning NULL. - * - * This is checked at compile-time for constexprs. It'll be checked at - * runtime too by synthetic code, only in MODE=dbg mode. - */ #ifndef returnsnonnull #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__returns_nonnull__) || \ @@ -706,13 +541,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Attests return value is aligned. - * - * @param (alignment) - * @param (alignment, misalignment) - * @see attributeallocalign(), returnspointerwithnoaliases, mallocesque - */ #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__assume_aligned__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) @@ -721,10 +549,6 @@ typedef uint64_t uintmax_t; #define returnsaligned(x) #endif -/** - * Declares prototype as behaving similar to malloc(). - * @see attributeallocsize(), attributeallocalign() - */ #ifndef returnspointerwithnoaliases #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__malloc__) || \ @@ -757,20 +581,6 @@ typedef uint64_t uintmax_t; #endif #endif -/** - * Defines variable as having same type as right-hand side. - * - * This enables safe, backwards-compatible, non-explosive macros, e.g.: - * - * #define bar(FOO) \ - * ({ \ - * autotype(FOO) Foo = (FOO); \ - * Foo + Foo * 2; \ - * }) - * - * @param x must be identical to rhs - * @note typeof goes back to gcc 2.x - */ #if __cplusplus + 0 >= 201103L #define autotype(x) auto #elif ((__has_builtin(auto_type) || defined(__llvm__) || \ @@ -781,27 +591,16 @@ typedef uint64_t uintmax_t; #define autotype(x) typeof(x) #endif -/** - * Defines interrupt handler that can call non-interrupt functions. - * @see forcealignargpointer, -mgeneral-regs-only and consider assembly - */ #if __GNUC__ >= 7 || __has_attribute(__no_caller_saved_registers__) #define nocallersavedregisters __attribute__((__no_caller_saved_registers__)) #else #define nocallersavedregisters "need modern compiler" #endif -/** - * Attests that execution of statement is impossible. - */ #ifndef unreachable #define unreachable __builtin_unreachable() #endif -/** - * Statement that does nothing. - * @note can help avoid drama w/ linters, warnings, formatters, etc. - */ #define donothing \ do { \ } while (0) @@ -857,9 +656,6 @@ typedef uint64_t uintmax_t; #define initarray _Section(".init_array") #endif -/** - * Systemic suppressions. - */ #ifndef __STRICT_ANSI__ #if defined(__GNUC__) || defined(__llvm__) #pragma GCC diagnostic ignored "-Wsign-compare" /* lint needs to change */ @@ -908,17 +704,6 @@ typedef uint64_t uintmax_t; #endif /* !GCC && LLVM */ #endif /* ANSI */ -/** - * Elevate warnings of material consequence. - * - * These aren't stylistic in nature; but are perfectly fine to disable, - * assuming we're ok with the compiler simply generating a runtime crash - * instead. Otherwise what usually happens with these is that a weakness - * is introduced, important optimizations can't be performed; or worst - * of all: the code will need patching if ported to a toy or any machine - * designed by an engineer who hadn't understood John von Neumann at the - * time, e.g. 1's complement, big endian, under 32bit word size, etc. - */ #ifndef __W__ #ifndef __STRICT_ANSI__ #if defined(__GNUC__) || defined(__llvm__) @@ -965,10 +750,6 @@ typedef uint64_t uintmax_t; #endif /* ANSI */ #endif /* -w */ -/** - * Sets manual breakpoint. - * @see showcrashreports() for auto gdb attach - */ #define DebugBreak() asm("int3") #define VEIL(CONSTRAINT, EXPRESSION) \ @@ -991,10 +772,6 @@ typedef uint64_t uintmax_t; 0; \ }) -/** - * Pulls another module, by symbol, into linkage. - * @note nop is discarded by ape/ape.lds - */ #define YOINK(SYMBOL) \ do { \ _Static_assert(!__builtin_types_compatible_p(typeof(SYMBOL), char[]), \ @@ -1006,29 +783,15 @@ typedef uint64_t uintmax_t; : "X"(SYMBOL)); \ } while (0) -/** - * Pulls another module into linkage from top-level scope. - * @note nop is discarded by ape/ape.lds - */ #define STATIC_YOINK(SYMBOLSTR) \ asm(".pushsection .yoink\n\tnop\t\"" SYMBOLSTR "\"\n\t.popsection") -/** - * Pulls source file into ZIP portion of binary. - * @see build/rules.mk which defines the wildcard build rule %.zip.o - */ #if !defined(IM_FEELING_NAUGHTY) && !defined(__STRICT_ANSI__) #define STATIC_YOINK_SOURCE(PATH) STATIC_YOINK(PATH) #else #define STATIC_YOINK_SOURCE(PATH) #endif -/** - * Pulls source of object being compiled into zip. - * @note automates most compliance with gpl terms - * @see libc/zipos/zipcentraldir.S - * @see ape/ape.lds - */ #ifdef __BASE_FILE__ STATIC_YOINK_SOURCE(__BASE_FILE__); #endif diff --git a/libc/integral/lp64.inc b/libc/integral/lp64.inc index b60bbda8..387f2eb6 100644 --- a/libc/integral/lp64.inc +++ b/libc/integral/lp64.inc @@ -67,4 +67,4 @@ #define __INT_FAST64_TYPE__ __INT64_TYPE__ #define __UINT_FAST64_TYPE__ __UINT64_TYPE__ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 7df7ba0e..ae09ea41 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -1,12 +1,3 @@ -/** - * @fileoverview Cosmopolitan Preprocessor / Language Normalization. - * - * This is our lowest-level header file. You don't need to include it, - * since we require that compilers be configured to do so automatically, - * and the -include flag is the safest bet. Further note polyfills here - * shouldn't be taken as indicators of intent to support. - */ - #define __COSMOPOLITAN__ 1 #ifndef __COUNTER__ diff --git a/libc/math.h b/libc/math.h index bfaa8259..f17ad172 100644 --- a/libc/math.h +++ b/libc/math.h @@ -289,11 +289,6 @@ void sincosl(long double, long double *, long double *); │ cosmopolitan § mathematics » x87 ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -#if 0 -/** - * Asks FPU to push well-known numbers to its own stack. - */ -#endif #define fldz() __X87_CONST(fldz, 0x0p+0) #define fld1() __X87_CONST(fld1, 0x8p-3) #define fldpi() __X87_CONST(fldpi, M_PI) diff --git a/libc/mem/vasprintf.c b/libc/mem/vasprintf.c index 9f4b2d17..3317e3a4 100644 --- a/libc/mem/vasprintf.c +++ b/libc/mem/vasprintf.c @@ -30,7 +30,7 @@ * @see xasprintf() for a better API */ int(vasprintf)(char **strp, const char *fmt, va_list va) { - /** + /* * This implementation guarantees the smallest possible allocation, * using an optimistic approach w/o changing asymptotic complexity. */ diff --git a/libc/nexgen32e/ffs.S b/libc/nexgen32e/ffs.S index 39be2372..1391f16d 100644 --- a/libc/nexgen32e/ffs.S +++ b/libc/nexgen32e/ffs.S @@ -38,8 +38,8 @@ / @asyncsignalsafe ffs: .leafprologue .profilable - bsf %edi,%eax or $-1,%edx + bsf %edi,%eax cmovz %edx,%eax inc %eax .leafepilogue diff --git a/libc/nexgen32e/ffs.h b/libc/nexgen32e/ffs.h index 6a161763..07d1219b 100644 --- a/libc/nexgen32e/ffs.h +++ b/libc/nexgen32e/ffs.h @@ -3,9 +3,29 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +/* + * BIT SCANNING 101 + * ctz(𝑥) 31^clz(𝑥) clz(𝑥) + * uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥) + * 0x00000000 wut 32 0 wut 32 + * 0x00000001 0 0 1 0 31 + * 0x80000001 0 0 1 31 0 + * 0x80000000 31 31 32 31 0 + * 0x00000010 4 4 5 4 27 + * 0x08000010 4 4 5 27 4 + * 0x08000000 27 27 28 27 4 + * 0xffffffff 0 0 1 31 0 + */ + int ffs(int) pureconst; -int ffsl(long int) pureconst; -int ffsll(long long int) pureconst; +int ffsl(long) pureconst; +int ffsll(long long) pureconst; + +#ifdef __GNUC__ +#define ffs(u) __builtin_ffs(u) +#define ffsl(u) __builtin_ffsl(u) +#define ffsll(u) __builtin_ffsll(u) +#endif COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/nexgen32e/ffsl.S b/libc/nexgen32e/ffsl.S index 44327c06..84a2540e 100644 --- a/libc/nexgen32e/ffsl.S +++ b/libc/nexgen32e/ffsl.S @@ -38,8 +38,8 @@ / @asyncsignalsafe ffsl: .leafprologue .profilable - bsf %rdi,%rax or $-1,%edx + bsf %rdi,%rax cmovz %edx,%eax inc %eax .leafepilogue diff --git a/libc/nexgen32e/kcpuids.h b/libc/nexgen32e/kcpuids.h index f104f06f..1c0f9def 100644 --- a/libc/nexgen32e/kcpuids.h +++ b/libc/nexgen32e/kcpuids.h @@ -29,13 +29,6 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/** - * Globally precomputed x86 CPUID values. - * - * @note Referencing Is Initialization (RII) - * @note Protected with PIRO - * @see X86_HAVE() - */ extern const unsigned kCpuids[KCPUIDS_LEN][4]; COSMOPOLITAN_C_END_ diff --git a/libc/nt/thunk/msabi.h b/libc/nt/thunk/msabi.h index 89793d50..10cfaedf 100644 --- a/libc/nt/thunk/msabi.h +++ b/libc/nt/thunk/msabi.h @@ -2,6 +2,9 @@ #define COSMOPOLITAN_LIBC_NT_THUNK_MSABI_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) +#if !defined(__STRICT_ANSI__) && \ + (__GNUC__ * 100 + __GNUC_MINOR__ >= 408 || \ + (__has_attribute(__ms_abi__) || defined(__llvm__))) /** * Defines function as using Microsoft x64 calling convention. * @@ -9,13 +12,10 @@ * generate code that calls MS ABI functions directly, without needing * to jump through the assembly thunks. */ -#if !defined(__STRICT_ANSI__) && \ - (__GNUC__ * 100 + __GNUC_MINOR__ >= 408 || \ - (__has_attribute(__ms_abi__) || defined(__llvm__))) #define __msabi __attribute__((__ms_abi__)) #endif -/** +/* * Returns true if header should provide MS-ABI overrides. */ #ifndef ShouldUseMsabiAttribute diff --git a/libc/rand/rand32.c b/libc/rand/rand32.c index d8b65c64..c072f575 100644 --- a/libc/rand/rand32.c +++ b/libc/rand/rand32.c @@ -35,7 +35,7 @@ nodebuginfo uint32_t(rand32)(void) { } else { devrand(&res, sizeof(res)); } - hidden extern uint32_t g_rando32; + extern uint32_t g_rando32 hidden; res ^= MarsagliaXorshift32(&g_rando32); } return res; diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 800d4f09..849cf4c8 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -42,9 +42,9 @@ /** * Beseeches system for page-table entries. * - * char *p = mmap(NULL, 65536, PROT_READ | PROT_WRITE, - * MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - * munmap(p, 65536); + * 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, * which needs to be 64kb aligned if passed (for NT compatibility) diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 48cd378b..5b82db32 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -157,29 +157,29 @@ static textwindows wontreturn void WinMainNew(void) { * 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. + * 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. + * 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. + * 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. Allocates new stack at a high address. 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. + * 4. Allocates new stack at a high address. 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. * - * 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. + * 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. * - * 6. Finally, we need fork. Microsoft designed Windows to prevent us - * from having fork() so we pass pipe handles in an environment - * variable literally copy all the memory. + * 6. Finally, we need fork. Microsoft designed Windows to prevent us + * from having fork() so we pass pipe handles in an environment + * variable literally copy all the memory. * * @param hInstance call GetModuleHandle(NULL) from main if you need it */ diff --git a/libc/stdio/g_stderr.c b/libc/stdio/g_stderr.c index d4871277..2beed914 100644 --- a/libc/stdio/g_stderr.c +++ b/libc/stdio/g_stderr.c @@ -22,7 +22,11 @@ STATIC_YOINK("_init_g_stderr"); +/** + * Pointer to standard error stream. + */ FILE *stderr; + hidden FILE g_stderr; hidden unsigned char g_stderr_buf[BUFSIZ] forcealign(PAGESIZE); diff --git a/libc/stdio/g_stdin.c b/libc/stdio/g_stdin.c index 63249d96..a31deef1 100644 --- a/libc/stdio/g_stdin.c +++ b/libc/stdio/g_stdin.c @@ -22,7 +22,11 @@ STATIC_YOINK("_init_g_stdin"); +/** + * Pointer to standard input stream. + */ FILE *stdin; + hidden FILE g_stdin; hidden unsigned char g_stdin_buf[BUFSIZ] forcealign(PAGESIZE); diff --git a/libc/stdio/g_stdout.c b/libc/stdio/g_stdout.c index 2ef26577..2b09eaa4 100644 --- a/libc/stdio/g_stdout.c +++ b/libc/stdio/g_stdout.c @@ -25,7 +25,11 @@ STATIC_YOINK("_init_g_stdout"); +/** + * Pointer to standard output stream. + */ FILE *stdout; + hidden FILE g_stdout; hidden unsigned char g_stdout_buf[BUFSIZ] forcealign(PAGESIZE); diff --git a/libc/str/isalnum.c b/libc/str/isalnum.c index 1b94dc17..3ad2d74b 100644 --- a/libc/str/isalnum.c +++ b/libc/str/isalnum.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is lower, alpha, or digit. + */ int isalnum(int c) { return ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); diff --git a/libc/str/isalpha.c b/libc/str/isalpha.c index 64a6d94a..2af6db7f 100644 --- a/libc/str/isalpha.c +++ b/libc/str/isalpha.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is upper or lower. + */ int isalpha(int c) { return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); } diff --git a/libc/str/isascii.c b/libc/str/isascii.c index 5313b23d..05356136 100644 --- a/libc/str/isascii.c +++ b/libc/str/isascii.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is ascii. + */ int isascii(int c) { return 0x00 <= c && c <= 0x7F; } diff --git a/libc/str/isblank.c b/libc/str/isblank.c index f1f43ec8..3b17bfff 100644 --- a/libc/str/isblank.c +++ b/libc/str/isblank.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is space or tab. + */ int isblank(int c) { return c == ' ' || c == '\t'; } diff --git a/libc/str/iscntrl.c b/libc/str/iscntrl.c index 423965e9..87bd0aa5 100644 --- a/libc/str/iscntrl.c +++ b/libc/str/iscntrl.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is C0 ASCII control code or DEL. + */ int iscntrl(int c) { return (0x00 <= c && c <= 0x1F) || c == 0x7F; } diff --git a/libc/str/isdigit.c b/libc/str/isdigit.c index 208528c0..83bafcad 100644 --- a/libc/str/isdigit.c +++ b/libc/str/isdigit.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is decimal digit. + */ int isdigit(int c) { return '0' <= c && c <= '9'; } diff --git a/libc/str/islower.c b/libc/str/islower.c index 2578519b..c1ac7629 100644 --- a/libc/str/islower.c +++ b/libc/str/islower.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is lowercase alpha ascii character. + */ int islower(int c) { return 'a' <= c && c <= 'z'; } diff --git a/libc/str/isspace.c b/libc/str/isspace.c index e5873bad..dcd64f69 100644 --- a/libc/str/isspace.c +++ b/libc/str/isspace.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns true if c is space, \t, \r, \n, \f, or \v. + */ int isspace(int c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v'; diff --git a/libc/str/isupper.c b/libc/str/isupper.c index a374f695..736eb2be 100644 --- a/libc/str/isupper.c +++ b/libc/str/isupper.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if c is uppercase alpha ascii character. + */ int isupper(int c) { return 'A' <= c && c <= 'Z'; } diff --git a/libc/str/iswcntrl.c b/libc/str/iswcntrl.c index 4b67fae7..3f33ce98 100644 --- a/libc/str/iswcntrl.c +++ b/libc/str/iswcntrl.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns nonzero if wc is C0 or C1 control code. + */ int iswcntrl(wint_t wc) { return (0x00 <= wc && wc <= 0x1F) || (0x7F <= wc && wc <= 0x9F); } diff --git a/libc/str/isxdigit.c b/libc/str/isxdigit.c index 7ef928d7..2b3c8fbb 100644 --- a/libc/str/isxdigit.c +++ b/libc/str/isxdigit.c @@ -19,6 +19,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +/** + * Returns true if c is hexadecimal digit. + */ int isxdigit(int c) { return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); diff --git a/libc/str/memccpy.c b/libc/str/memccpy.c index 5569c4f6..e2b008c1 100644 --- a/libc/str/memccpy.c +++ b/libc/str/memccpy.c @@ -28,17 +28,17 @@ * * For example, strictly: * - * char buf[16]; - * CHECK_NOTNULL(memccpy(buf, s, '\0', sizeof(buf))); + * char buf[16]; + * CHECK_NOTNULL(memccpy(buf, s, '\0', sizeof(buf))); * * Or unstrictly: * - * if (!memccpy(buf, s, '\0', sizeof(buf))) strcpy(buf, "?"); + * if (!memccpy(buf, s, '\0', sizeof(buf))) strcpy(buf, "?"); * * Are usually more sensible than the following: * - * char cstrbuf[16]; - * snprintf(cstrbuf, sizeof(cstrbuf), "%s", CSTR); + * char cstrbuf[16]; + * snprintf(cstrbuf, sizeof(cstrbuf), "%s", CSTR); * * @return 𝑑 + idx(𝑐) + 1, or NULL if 𝑐 ∉ 𝑠₀․․ₙ₋₁ * @note 𝑑 and 𝑠 can't overlap diff --git a/libc/str/stpncpy.c b/libc/str/stpncpy.c index 41f17de0..ef7501d6 100644 --- a/libc/str/stpncpy.c +++ b/libc/str/stpncpy.c @@ -23,6 +23,7 @@ * Prepares static search buffer. * * 1. If SRC is too long, it's truncated and *not* NUL-terminated. + * * 2. If SRC is too short, the remainder is zero-filled. * * Please note this function isn't designed to prevent untrustworthy diff --git a/libc/str/strncpy.c b/libc/str/strncpy.c index 91ee8457..a249aa40 100644 --- a/libc/str/strncpy.c +++ b/libc/str/strncpy.c @@ -23,6 +23,7 @@ * Prepares static search buffer. * * 1. If SRC is too long, it's truncated and *not* NUL-terminated. + * * 2. If SRC is too short, the remainder is zero-filled. * * Please note this function isn't designed to prevent untrustworthy diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index ae40f7a1..7292dd3a 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -46,7 +46,7 @@ wontreturn void testlib_abort(void) { */ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end, testfn_t warmup) { - /** + /* * getpid() calls are inserted to help visually see tests in traces * which can be performed on Linux, FreeBSD, OpenBSD, and XNU: * diff --git a/libc/time/strftime.c b/libc/time/strftime.c index b52083dc..d9f7933d 100644 --- a/libc/time/strftime.c +++ b/libc/time/strftime.c @@ -370,13 +370,13 @@ static char *strftime_timefmt(char *p, const char *pe, const char *format, /** * Converts time to string, e.g. * - * char b[64]; - * int64_t sec; - * struct tm tm; - * time(&sec); - * localtime_r(&sec, &tm); - * strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S%z", &tm); // ISO8601 - * strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123 + * char b[64]; + * int64_t sec; + * struct tm tm; + * time(&sec); + * localtime_r(&sec, &tm); + * strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S%z", &tm); // ISO8601 + * strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123 * * @return bytes copied excluding nul, or 0 on error */ diff --git a/libc/unicode/strnwidth.c b/libc/unicode/strnwidth.c index 46b8b60f..dd28be0f 100644 --- a/libc/unicode/strnwidth.c +++ b/libc/unicode/strnwidth.c @@ -25,7 +25,9 @@ * Returns monospace display width of UTF-8 string. * * - Control codes are discounted + * * - ANSI escape sequences are discounted + * * - East asian glyphs, emoji, etc. count as two * * @param s is NUL-terminated string diff --git a/libc/x/unbingbuf.c b/libc/x/unbingbuf.c index 05bb49c5..9b63f192 100644 --- a/libc/x/unbingbuf.c +++ b/libc/x/unbingbuf.c @@ -27,10 +27,10 @@ /** * Decodes human-readable CP437 glyphs into binary, e.g. * - * char binged[5]; - * char golden[5] = "\0\1\2\3\4"; - * unbingbuf(binged, sizeof(binged), u" ☺☻♥♦", -1); - * CHECK_EQ(0, memcmp(binged, golden, 5)); + * char binged[5]; + * char golden[5] = "\0\1\2\3\4"; + * unbingbuf(binged, sizeof(binged), u" ☺☻♥♦", -1); + * CHECK_EQ(0, memcmp(binged, golden, 5)); * * @param buf is caller owned * @param size is byte length of buf diff --git a/libc/x/unbingstr.c b/libc/x/unbingstr.c index 1ff46cfa..e19d2c62 100644 --- a/libc/x/unbingstr.c +++ b/libc/x/unbingstr.c @@ -24,7 +24,7 @@ /** * Decodes human-readable CP437 glyphs into binary, e.g. * - * CHECK_EQ(0, memcmp(gc(unbingstr(u" ☺☻♥♦")), "\0\1\2\3\4", 5)); + * CHECK_EQ(0, memcmp(gc(unbingstr(u" ☺☻♥♦")), "\0\1\2\3\4", 5)); * * @param buf is caller owned * @param size is byte length of buf diff --git a/libc/x/xjoinpaths.c b/libc/x/xjoinpaths.c index dac89ba1..92cb74cb 100644 --- a/libc/x/xjoinpaths.c +++ b/libc/x/xjoinpaths.c @@ -24,12 +24,12 @@ /** * Joins paths, e.g. * - * "a" + "b" → "a/b" - * "a/" + "b" → "a/b" - * "a" + "b/" → "a/b/" - * "a" + "/b" → "/b" - * "." + "b" → "b" - * "" + "b" → "b" + * "a" + "b" → "a/b" + * "a/" + "b" → "a/b" + * "a" + "b/" → "a/b/" + * "a" + "/b" → "/b" + * "." + "b" → "b" + * "" + "b" → "b" * * @return newly allocated string of resulting path */ diff --git a/libc/x/xsigaction.c b/libc/x/xsigaction.c index d6555f39..eeabbe3e 100644 --- a/libc/x/xsigaction.c +++ b/libc/x/xsigaction.c @@ -26,8 +26,8 @@ /** * Installs handler for kernel interrupt, e.g.: * - * onctrlc(sig) { exit(128+sig); } - * CHECK_NE(-1, xsigaction(SIGINT, onctrlc, SA_RESETHAND, 0, 0)); + * onctrlc(sig) { exit(128+sig); } + * CHECK_NE(-1, xsigaction(SIGINT, onctrlc, SA_RESETHAND, 0, 0)); * * @param sig can be SIGINT, SIGTERM, etc. * @param handler is SIG_DFL, SIG_IGN, or a pointer to a 0≤arity≤3 diff --git a/test/libc/nexgen32e/ffs_test.c b/test/libc/nexgen32e/ffs_test.c new file mode 100644 index 00000000..e3195e62 --- /dev/null +++ b/test/libc/nexgen32e/ffs_test.c @@ -0,0 +1,45 @@ +/*-*- 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/nexgen32e/ffs.h" +#include "libc/nexgen32e/nexgen32e.h" +#include "libc/testlib/testlib.h" + +TEST(ffs, test) { + EXPECT_EQ(__builtin_ffs(0), (ffs)(0)); + EXPECT_EQ(__builtin_ffs(1), (ffs)(1)); + EXPECT_EQ(__builtin_ffs(0x00100000), (ffs)(0x00100000)); + EXPECT_EQ(__builtin_ffs(-1), (ffs)(-1)); +} + +TEST(ffsl, test) { + EXPECT_EQ(__builtin_ffsl(0), (ffsl)(0)); + EXPECT_EQ(__builtin_ffsl(1), (ffsl)(1)); + EXPECT_EQ(__builtin_ffsl(0x00100000), (ffsl)(0x00100000)); + EXPECT_EQ(__builtin_ffsl(0x0010000000000000), (ffsl)(0x0010000000000000)); + EXPECT_EQ(__builtin_ffsl(-1), (ffsl)(-1)); +} + +TEST(ffsll, test) { + EXPECT_EQ(__builtin_ffsll(0), (ffsll)(0)); + EXPECT_EQ(__builtin_ffsll(1), (ffsll)(1)); + EXPECT_EQ(__builtin_ffsll(0x00100000), (ffsll)(0x00100000)); + EXPECT_EQ(__builtin_ffsll(0x0010000000000000), (ffsll)(0x0010000000000000)); + EXPECT_EQ(__builtin_ffsll(-1), (ffsll)(-1)); +} diff --git a/test/tool/build/lib/javadown_test.c b/test/tool/build/lib/javadown_test.c new file mode 100644 index 00000000..db531d5d --- /dev/null +++ b/test/tool/build/lib/javadown_test.c @@ -0,0 +1,230 @@ +/*-*- 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/mem/mem.h" +#include "libc/runtime/gc.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/testlib/testlib.h" +#include "tool/build/lib/javadown.h" + +TEST(ParseJavadown, testOneLiner) { + const char *comment = "/** Parses javadown. */"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ("Parses javadown.", jd->title); + EXPECT_STREQ("", jd->text); + EXPECT_EQ(0, jd->tags.n); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testShortAndTerse) { + const char *comment = "\ +/**\n\ + * Parses javadown.\n\ + * @see love\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ("Parses javadown.", jd->title); + EXPECT_STREQ("", jd->text); + EXPECT_EQ(1, jd->tags.n); + EXPECT_STREQ("see", jd->tags.p[0].tag); + EXPECT_STREQ("love", jd->tags.p[0].text); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testBlankLineOmitted) { + const char *comment = "\ +/**\n\ + * Parses javadown.\n\ + *\n\ + * Description.\n\ + * @see love\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ("Parses javadown.", jd->title); + EXPECT_STREQ("Description.", jd->text); + EXPECT_EQ(1, jd->tags.n); + EXPECT_STREQ("see", jd->tags.p[0].tag); + EXPECT_STREQ("love", jd->tags.p[0].text); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testContentInterpretation) { + const char *comment = "\ +/**\n\ + * Parses javadown \n\ + * and that is the bottom line.\n\ + *\n\ + * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ + * eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim \n\ + * ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ + * aliquip ex ea commodo consequat.\n\ + *\n\ + * Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ + * dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ + * non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ + * laborum\n\ + *\n\ + * @param data should point to text inside the slash star markers\n\ + * lorem ipsum dolla dollaz yo\n\ + * @param size is length of data in bytes\n\ + * @return object that should be passed to FreeJavadown()\n\ + * @asyncsignalsafe\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + const char *description = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n\ +ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +aliquip ex ea commodo consequat.\n\ +\n\ +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +laborum\n"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ(title, jd->title); + EXPECT_STREQ(description, jd->text); + EXPECT_EQ(4, jd->tags.n); + EXPECT_STREQ("param", jd->tags.p[0].tag); + EXPECT_STREQ("data should point to text inside the slash star markers\n" + "lorem ipsum dolla dollaz yo", + jd->tags.p[0].text); + EXPECT_STREQ("param", jd->tags.p[1].tag); + EXPECT_STREQ("size is length of data in bytes", jd->tags.p[1].text); + EXPECT_STREQ("return", jd->tags.p[2].tag); + EXPECT_STREQ("object that should be passed to FreeJavadown()", + jd->tags.p[2].text); + EXPECT_STREQ("asyncsignalsafe", jd->tags.p[3].tag); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testTabFormatting1) { + const char *comment = "\ +/**\n\ +\tParses javadown \n\ +\tand that is the bottom line.\n\ +\n\ +\tLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim \n\ +\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +\taliquip ex ea commodo consequat.\n\ +\n\ +\tDuis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +\tdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +\tnon proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +\tlaborum\n\ +\n\ +\t@param data should point to text inside the slash star markers\n\ +\t\tlorem ipsum dolla dollaz yo\n\ +\t@param size is length of data in bytes\n\ +\t@return object that should be passed to FreeJavadown()\n\ +\t@asyncsignalsafe\n\ + */"; + const char *title = "Parses javadown and that is the bottom line."; + const char *description = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n\ +ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +aliquip ex ea commodo consequat.\n\ +\n\ +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +laborum\n"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ(title, jd->title); + EXPECT_STREQ(description, jd->text); + EXPECT_EQ(4, jd->tags.n); + EXPECT_STREQ("param", jd->tags.p[0].tag); + EXPECT_STREQ("data should point to text inside the slash star markers\n" + "lorem ipsum dolla dollaz yo", + jd->tags.p[0].text); + EXPECT_STREQ("param", jd->tags.p[1].tag); + EXPECT_STREQ("size is length of data in bytes", jd->tags.p[1].text); + EXPECT_STREQ("return", jd->tags.p[2].tag); + EXPECT_STREQ("object that should be passed to FreeJavadown()", + jd->tags.p[2].text); + EXPECT_STREQ("asyncsignalsafe", jd->tags.p[3].tag); + FreeJavadown(jd); +} + +TEST(ParseJavadown, testTabFormatting2) { + const char *comment = "\ +/**\n\ +\tParses javadown \n\ +\tand that is the bottom line.\n\ +\t\n\ +\tLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +\t\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim \n\ +\t\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +\t\taliquip ex ea commodo consequat.\n\ +\t\n\ +\tDuis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +\tdolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +\tnon proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +\tlaborum\n\ +\t\n\ +\t@param data should point to text inside the slash star markers\n\ +\t\tlorem ipsum dolla dollaz yo\n\ +\t@param size is length of data in bytes\n\ +\t@return object that should be passed to FreeJavadown()\n\ +\t@asyncsignalsafe\n\ +*/"; + const char *title = "Parses javadown and that is the bottom line."; + const char *description = "\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n\ +\teiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim\n\ +\tad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n\ +\taliquip ex ea commodo consequat.\n\ +\n\ +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n\ +dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat\n\ +non proident, sunt in culpa qui officia deserunt mollit anim id est\n\ +laborum\n"; + struct Javadown *jd; + jd = ParseJavadown(comment + 3, strlen(comment) - 3 - 2); + EXPECT_FALSE(jd->isfileoverview); + EXPECT_STREQ(title, jd->title); + EXPECT_STREQ(description, jd->text); + EXPECT_EQ(4, jd->tags.n); + EXPECT_STREQ("param", jd->tags.p[0].tag); + EXPECT_STREQ("data should point to text inside the slash star markers\n" + "lorem ipsum dolla dollaz yo", + jd->tags.p[0].text); + EXPECT_STREQ("param", jd->tags.p[1].tag); + EXPECT_STREQ("size is length of data in bytes", jd->tags.p[1].text); + EXPECT_STREQ("return", jd->tags.p[2].tag); + EXPECT_STREQ("object that should be passed to FreeJavadown()", + jd->tags.p[2].text); + EXPECT_STREQ("asyncsignalsafe", jd->tags.p[3].tag); + FreeJavadown(jd); +} diff --git a/third_party/chibicc/README.cosmo b/third_party/chibicc/README.cosmo index 56971eec..bb5ce109 100644 --- a/third_party/chibicc/README.cosmo +++ b/third_party/chibicc/README.cosmo @@ -16,18 +16,22 @@ local enhancements - support __builtin_constant_p, __builtin_likely, etc. - support __builtin_isunordered, __builtin_islessgreater, etc. - support __builtin_ctz, __builtin_bswap, __builtin_popcount, etc. +- support __force_align_arg_pointer__, __no_caller_saved_registers__, etc. - support __constructor__, __section__, __cold__, -ffunction-sections, etc. - support building -x assembler-with-cpp a.k.a. .S files - support profiling w/ -mcount / -mfentry / -mnop-mcount - improve error messages to trace macro expansions - reduce #lines of generated assembly by a third - reduce #bytes of generated binary by a third +- report divide errors in constexprs local bug fixes - allow casted values to be lvalues +- permit remainder operator in constexprs - permit parentheses around string-initializer - fix 64-bit bug in generated code for struct bitfields +- fix struct_designator() so it won't crash on anonymous union members - fix bug where last statement in statement expression couldn't have label - print_tokens (chibicc -E) now works in the case of adjacent string literals - make enums unsigned (like gcc) so we don't suffer the msvc enum bitfield bug @@ -35,6 +39,8 @@ local bug fixes local changes - use tabs in generated output +- parse javadoc-style markdown comments +- don't fold backslash newline in comments - generated code no longer assumes red zone - emit .size directives for function definitions - use fisttp long double conversions if built w/ -msse3 diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index 6a6133d9..4d06bb62 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -177,8 +177,8 @@ struct As { struct Sauces { unsigned long n; struct Sauce { - int path; // strings - int line; // 1-indexed + unsigned path; // strings + unsigned line; // 1-indexed } * p; } sauces; struct Things { @@ -192,14 +192,14 @@ struct As { TT_FORWARD, TT_BACKWARD, } t : 4; - int s : 28; // sauces - int i; // identity,ints,floats,slices + unsigned s : 28; // sauces + unsigned i; // identity,ints,floats,slices } * p; } things; struct Sections { unsigned long n; struct Section { - int name; // strings + unsigned name; // strings int flags; int type; int align; @@ -210,11 +210,11 @@ struct As { unsigned long n; struct Symbol { bool isused; - int name; // slices - int section; // sections - int stb; // STB_* - int stv; // STV_* - int type; // STT_* + unsigned char stb; // STB_* + unsigned char stv; // STV_* + unsigned char type; // STT_* + unsigned name; // slices + unsigned section; // sections long offset; long size; struct ElfWriterSymRef ref; @@ -223,25 +223,25 @@ struct As { struct HashTable { unsigned i, n; struct HashEntry { - int h; - int i; + unsigned h; + unsigned i; } * p; } symbolindex; struct Labels { unsigned long n; struct Label { - int id; - int tok; // things - int symbol; // symbols + unsigned id; + unsigned tok; // things + unsigned symbol; // symbols } * p; } labels; struct Relas { unsigned long n; struct Rela { bool isdead; - int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...} - int expr; // exprs - int section; // sections + int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...} + unsigned expr; // exprs + unsigned section; // sections long offset; long addend; } * p; @@ -251,7 +251,7 @@ struct As { struct Expr { enum ExprKind { EX_INT, // integer - EX_SYM, // slice, forward, backward, then symbol + EX_SYM, // things (then symbols after eval) EX_NEG, // unary - EX_NOT, // unary ! EX_BITNOT, // unary ~ @@ -276,7 +276,7 @@ struct As { EM_DTPOFF, EM_TPOFF, } em; - int tok; + unsigned tok; int lhs; int rhs; long x; @@ -456,7 +456,7 @@ static bool EndsWith(const char *s, const char *suffix) { n = strlen(s); m = strlen(suffix); if (m > n) return false; - return memcmp(s + n - m, suffix, m) == 0; + return !memcmp(s + n - m, suffix, m); } static char *Format(const char *fmt, ...) { @@ -1192,21 +1192,21 @@ static int ParseMul(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '*')) { y = ParseUnary(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x *= a->exprs.p[y].x; } else { x = NewBinary(a, EX_MUL, x, y); } } else if (IsPunct(a, i, '/')) { y = ParseUnary(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x /= a->exprs.p[y].x; } else { x = NewBinary(a, EX_DIV, x, y); } } else if (IsPunct(a, i, '%')) { y = ParseUnary(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x %= a->exprs.p[y].x; } else { x = NewBinary(a, EX_REM, x, y); @@ -1225,14 +1225,14 @@ static int ParseAdd(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '+')) { y = ParseMul(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x += a->exprs.p[y].x; } else { x = NewBinary(a, EX_ADD, x, y); } } else if (IsPunct(a, i, '-')) { y = ParseMul(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x -= a->exprs.p[y].x; } else if (a->exprs.p[y].kind == EX_INT) { a->exprs.p[y].x = -a->exprs.p[y].x; @@ -1254,14 +1254,14 @@ static int ParseShift(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '<' << 8 | '<')) { y = ParseAdd(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x <<= a->exprs.p[y].x & 63; } else { x = NewBinary(a, EX_SHL, x, y); } } else if (IsPunct(a, i, '>' << 8 | '>')) { y = ParseAdd(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x >>= a->exprs.p[y].x & 63; } else { x = NewBinary(a, EX_SHR, x, y); @@ -1280,28 +1280,28 @@ static int ParseRelational(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '<')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x < a->exprs.p[y].x; } else { x = NewBinary(a, EX_LT, x, y); } } else if (IsPunct(a, i, '>')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[y].x < a->exprs.p[x].x; } else { x = NewBinary(a, EX_LT, y, x); } } else if (IsPunct(a, i, '<' << 8 | '=')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x <= a->exprs.p[y].x; } else { x = NewBinary(a, EX_LE, x, y); } } else if (IsPunct(a, i, '>' << 8 | '=')) { y = ParseShift(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[y].x <= a->exprs.p[x].x; } else { x = NewBinary(a, EX_LE, y, x); @@ -1320,14 +1320,14 @@ static int ParseEquality(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '=' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x; } else { x = NewBinary(a, EX_EQ, x, y); } } else if (IsPunct(a, i, '!' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x; } else { x = NewBinary(a, EX_NE, x, y); @@ -1346,7 +1346,7 @@ static int ParseAnd(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '&')) { y = ParseEquality(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x &= a->exprs.p[y].x; } else { x = NewBinary(a, EX_AND, x, y); @@ -1365,7 +1365,7 @@ static int ParseXor(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '^')) { y = ParseAnd(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x ^= a->exprs.p[y].x; } else { x = NewBinary(a, EX_XOR, x, y); @@ -1384,7 +1384,7 @@ static int ParseOr(struct As *a, int *rest, int i) { for (;;) { if (IsPunct(a, i, '|')) { y = ParseXor(a, &i, i + 1); - if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { + if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x |= a->exprs.p[y].x; } else { x = NewBinary(a, EX_OR, x, y); @@ -3745,8 +3745,7 @@ static int ResolveSymbol(struct As *a, int i) { case TT_FORWARD: return FindLabelForward(a, a->ints.p[a->things.p[i].i]); default: - DebugBreak(); - Fail(a, "this corruption"); + Fail(a, "this corruption %d", a->things.p[i].t); } } @@ -3777,15 +3776,6 @@ static void Write32(char b[4], int x) { b[3] = x >> 030; } -static void MarkUndefinedSymbolsGlobal(struct As *a) { - int i; - for (i = 0; i < a->symbols.n; ++i) { - if (!a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) { - a->symbols.p[i].stb = STB_GLOBAL; - } - } -} - static void MarkUsedSymbols(struct As *a, int i) { if (i == -1) return; MarkUsedSymbols(a, a->exprs.p[i].lhs); @@ -3818,6 +3808,16 @@ static void Evaluate(struct As *a) { } } +static void MarkUndefinedSymbolsGlobal(struct As *a) { + int i; + for (i = 0; i < a->symbols.n; ++i) { + if (a->symbols.p[i].isused && !a->symbols.p[i].section && + a->symbols.p[i].stb == STB_LOCAL) { + a->symbols.p[i].stb = STB_GLOBAL; + } + } +} + static bool IsLocal(struct As *a, int name) { if (name < 0) return true; return a->slices.p[name].n >= 2 && !memcmp(a->slices.p[name].p, ".L", 2); @@ -3829,17 +3829,18 @@ static bool IsLiveSymbol(struct As *a, int i) { } static void Objectify(struct As *a, int path) { - int i, j, s; + char *p; + int i, j, s, e; struct ElfWriter *elf; elf = elfwriter_open(a->strings.p[path], 0644); for (i = 0; i < a->symbols.n; ++i) { if (!IsLiveSymbol(a, i)) continue; + p = strndup(a->slices.p[a->symbols.p[i].name].p, + a->slices.p[a->symbols.p[i].name].n); a->symbols.p[i].ref = elfwriter_appendsym( - elf, - strndup(a->slices.p[a->symbols.p[i].name].p, - a->slices.p[a->symbols.p[i].name].n), - ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type), + elf, p, ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type), a->symbols.p[i].stv, a->symbols.p[i].offset, a->symbols.p[i].size); + free(p); } for (i = 0; i < a->sections.n; ++i) { elfwriter_align(elf, a->sections.p[i].align, 0); @@ -3853,24 +3854,24 @@ static void Objectify(struct As *a, int path) { for (j = 0; j < a->relas.n; ++j) { if (a->relas.p[j].isdead) continue; if (a->relas.p[j].section != i) continue; - a->i = a->exprs.p[a->relas.p[j].expr].tok; - switch (a->exprs.p[a->relas.p[j].expr].kind) { + e = a->relas.p[j].expr; + a->i = a->exprs.p[e].tok; + switch (a->exprs.p[e].kind) { case EX_INT: break; case EX_SYM: - elfwriter_appendrela( - elf, a->relas.p[j].offset, - a->symbols.p[a->exprs.p[a->relas.p[j].expr].x].ref, - a->relas.p[j].kind, a->relas.p[j].addend); + elfwriter_appendrela(elf, a->relas.p[j].offset, + a->symbols.p[a->exprs.p[e].x].ref, + a->relas.p[j].kind, a->relas.p[j].addend); break; case EX_ADD: - if (a->exprs.p[a->exprs.p[j].lhs].kind == EX_SYM && - a->exprs.p[a->exprs.p[j].rhs].kind == EX_INT) { + if (a->exprs.p[a->exprs.p[e].lhs].kind == EX_SYM && + a->exprs.p[a->exprs.p[e].rhs].kind == EX_INT) { elfwriter_appendrela( elf, a->relas.p[j].offset, - a->symbols.p[a->exprs.p[a->exprs.p[j].lhs].x].ref, + a->symbols.p[a->exprs.p[a->exprs.p[e].lhs].x].ref, a->relas.p[j].kind, - a->relas.p[j].addend + a->exprs.p[a->exprs.p[j].rhs].x); + a->relas.p[j].addend + a->exprs.p[a->exprs.p[e].rhs].x); } else { Fail(a, "bad addend"); } @@ -3887,6 +3888,58 @@ static void Objectify(struct As *a, int path) { elfwriter_close(elf); } +static void CheckIntegrity(struct As *a) { + int i; + for (i = 0; i < a->things.n; ++i) { + CHECK_LT((int)a->things.p[i].s, a->sauces.n); + switch (a->things.p[i].t) { + case TT_INT: + case TT_FORWARD: + case TT_BACKWARD: + CHECK_LT(a->things.p[i].i, a->ints.n); + break; + case TT_FLOAT: + CHECK_LT(a->things.p[i].i, a->floats.n); + break; + case TT_SLICE: + CHECK_LT(a->things.p[i].i, a->slices.n); + break; + default: + break; + } + } + for (i = 0; i < a->sections.n; ++i) { + CHECK_LT(a->sections.p[i].name, a->strings.n); + } + for (i = 0; i < a->symbols.n; ++i) { + CHECK_LT(a->symbols.p[i].name, a->slices.n); + CHECK_LT(a->symbols.p[i].section, a->sections.n); + } + for (i = 0; i < a->labels.n; ++i) { + CHECK_LT(a->labels.p[i].tok, a->things.n); + CHECK_LT(a->labels.p[i].symbol, a->symbols.n); + } + for (i = 0; i < a->relas.n; ++i) { + CHECK_LT(a->relas.p[i].expr, a->exprs.n); + CHECK_LT(a->relas.p[i].section, a->sections.n); + } + for (i = 0; i < a->exprs.n; ++i) { + CHECK_LT(a->exprs.p[i].tok, a->things.n); + if (a->exprs.p[i].lhs != -1) CHECK_LT(a->exprs.p[i].lhs, a->exprs.n); + if (a->exprs.p[i].rhs != -1) CHECK_LT(a->exprs.p[i].rhs, a->exprs.n); + switch (a->exprs.p[i].kind) { + case EX_SYM: + CHECK_LT(a->exprs.p[i].x, a->things.n); + CHECK(a->things.p[a->exprs.p[i].x].t == TT_SLICE || + a->things.p[a->exprs.p[i].x].t == TT_FORWARD || + a->things.p[a->exprs.p[i].x].t == TT_BACKWARD); + break; + default: + break; + } + } +} + static void PrintThings(struct As *a) { int i; char pbuf[4], fbuf[32]; @@ -3929,17 +3982,18 @@ void Assembler(int argc, char *argv[]) { Tokenize(a, a->inpath); /* PrintThings(a); */ Assemble(a); + /* CheckIntegrity(a); */ Evaluate(a); MarkUndefinedSymbolsGlobal(a); Objectify(a, a->outpath); - malloc_stats(); + /* malloc_stats(); */ FreeAssembler(a); } int main(int argc, char *argv[]) { showcrashreports(); if (argc == 1) { - system("o//third_party/chibicc/as.com -o /tmp/o third_party/chibicc/hog.s"); + system("o//third_party/chibicc/as.com -o /tmp/o /home/jart/trash/hog.s"); system("objdump -xwd /tmp/o"); exit(0); } diff --git a/third_party/chibicc/chibicc.c b/third_party/chibicc/chibicc.c index 829267db..fd6ce4dd 100644 --- a/third_party/chibicc/chibicc.c +++ b/third_party/chibicc/chibicc.c @@ -32,6 +32,7 @@ bool opt_verbose; static bool opt_A; static bool opt_E; +static bool opt_J; static bool opt_M; static bool opt_MD; static bool opt_MMD; @@ -202,6 +203,8 @@ static void parse_args(int argc, char **argv) { opt_c = true; } else if (!strcmp(argv[i], "-E")) { opt_E = true; + } else if (!strcmp(argv[i], "-J")) { + opt_J = true; } else if (!strcmp(argv[i], "-A")) { opt_A = true; } else if (!strcmp(argv[i], "-I")) { @@ -364,7 +367,14 @@ static char *create_tmpfile(void) { return path; } -static void run_subprocess(char **argv) { +static void handle_exit(bool ok) { + if (!ok) { + opt_save_temps = true; + exit(1); + } +} + +static bool run_subprocess(char **argv) { // If -### is given, dump the subprocess's command line. if (opt_hash_hash_hash) { fprintf(stderr, "%s", argv[0]); @@ -384,13 +394,10 @@ static void run_subprocess(char **argv) { break; } } - if (status != 0) { - opt_save_temps = true; - exit(1); - } + return !status; } -static void run_cc1(int argc, char **argv, char *input, char *output) { +static bool run_cc1(int argc, char **argv, char *input, char *output) { char **args = calloc(argc + 10, sizeof(char *)); memcpy(args, argv, argc * sizeof(char *)); args[argc++] = "-cc1"; @@ -402,7 +409,7 @@ static void run_cc1(int argc, char **argv, char *input, char *output) { args[argc++] = "-cc1-output"; args[argc++] = output; } - run_subprocess(args); + return run_subprocess(args); } static void print_token(FILE *out, Token *tok) { @@ -540,6 +547,10 @@ static void cc1(void) { print_ast(stdout, prog); return; } + if (opt_J) { + output_javadown(output_file, prog); + return; + } FILE *out = open_file(output_file); codegen(prog, out); fclose(out); @@ -561,7 +572,7 @@ static void assemble(char *input, char *output) { strarray_push(&arr, "-o"); strarray_push(&arr, output); strarray_push(&arr, NULL); - run_subprocess(arr.data); + handle_exit(run_subprocess(arr.data)); } static void run_linker(StringArray *inputs, char *output) { @@ -591,7 +602,7 @@ static void run_linker(StringArray *inputs, char *output) { strarray_push(&arr, inputs->data[i]); } strarray_push(&arr, NULL); - run_subprocess(arr.data); + handle_exit(run_subprocess(arr.data)); } int chibicc(int argc, char **argv) { @@ -608,6 +619,7 @@ int chibicc(int argc, char **argv) { error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files"); } StringArray ld_args = {}; + StringArray dox_args = {}; for (int i = 0; i < input_paths.len; i++) { char *input = input_paths.data[i]; if (!strncmp(input, "-l", 2)) { @@ -647,25 +659,33 @@ int chibicc(int argc, char **argv) { assert(type == FILE_C || type == FILE_ASM_CPP); // Just preprocess if (opt_E || opt_M) { - run_cc1(argc, argv, input, NULL); + handle_exit(run_cc1(argc, argv, input, NULL)); continue; } // Compile if (opt_S) { - run_cc1(argc, argv, input, output); + handle_exit(run_cc1(argc, argv, input, output)); continue; } // Compile and assemble if (opt_c) { char *tmp = create_tmpfile(); - run_cc1(argc, argv, input, tmp); + handle_exit(run_cc1(argc, argv, input, tmp)); assemble(tmp, output); continue; } + // Dox + if (opt_J) { + char *tmp = create_tmpfile(); + if (run_cc1(argc, argv, input, tmp)) { + strarray_push(&dox_args, tmp); + } + continue; + } // Compile, assemble and link char *tmp1 = create_tmpfile(); char *tmp2 = create_tmpfile(); - run_cc1(argc, argv, input, tmp1); + handle_exit(run_cc1(argc, argv, input, tmp1)); assemble(tmp1, tmp2); strarray_push(&ld_args, tmp2); continue; @@ -673,5 +693,8 @@ int chibicc(int argc, char **argv) { if (ld_args.len > 0) { run_linker(&ld_args, opt_o ? opt_o : "a.out"); } + if (dox_args.len > 0) { + drop_dox(&dox_args, opt_o ? opt_o : "/dev/stdout"); + } return 0; } diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index 86df1cda..0e355049 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -26,6 +26,7 @@ #include "libc/unicode/unicode.h" #include "libc/x/x.h" #include "third_party/gdtoa/gdtoa.h" +#include "tool/build/lib/javadown.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -35,7 +36,10 @@ typedef struct Asm Asm; typedef struct AsmOperand AsmOperand; typedef struct File File; typedef struct FpClassify FpClassify; +typedef struct HashMap HashMap; typedef struct Hideset Hideset; +typedef struct Macro Macro; +typedef struct MacroParam MacroParam; typedef struct Member Member; typedef struct Node Node; typedef struct Obj Obj; @@ -47,6 +51,8 @@ typedef struct Token Token; typedef struct TokenStack TokenStack; typedef struct Type Type; +typedef Token *macro_handler_fn(Token *); + // // strarray.c // @@ -64,13 +70,14 @@ void strarray_push(StringArray *, char *); // typedef enum { - TK_IDENT, // Identifiers - TK_PUNCT, // Punctuators - TK_KEYWORD, // Keywords - TK_STR, // String literals - TK_NUM, // Numeric literals - TK_PP_NUM, // Preprocessing numbers - TK_EOF, // End-of-file markers + TK_IDENT, // Identifiers + TK_PUNCT, // Punctuators + TK_KEYWORD, // Keywords + TK_STR, // String literals + TK_NUM, // Numeric literals + TK_PP_NUM, // Preprocessing numbers + TK_JAVADOWN, // /** ... */ comments + TK_EOF, // End-of-file markers } TokenKind; struct File { @@ -80,6 +87,7 @@ struct File { // For #line directive char *display_name; int line_delta; + struct Javadown *javadown; }; struct thatispacked Token { @@ -96,6 +104,7 @@ struct thatispacked Token { char *filename; // Filename Hideset *hideset; // For macro expansion Token *origin; // If this is expanded from a macro, the original token + struct Javadown *javadown; union { int64_t val; // If kind is TK_NUM, its value long double fval; // If kind is TK_NUM, its value @@ -134,6 +143,23 @@ int read_escaped_char(char **, char *); // preprocess.c // +struct MacroParam { + MacroParam *next; + char *name; +}; + +struct Macro { + char *name; + bool is_objlike; // Object-like or function-like + MacroParam *params; + char *va_args_name; + Token *body; + macro_handler_fn *handler; + Token *javadown; +}; + +extern HashMap macros; + char *search_include_paths(char *); void init_macros(void); void define_macro(char *, char *); @@ -232,6 +258,7 @@ struct Obj { char *asmname; char *section; char *visibility; + Token *javadown; // Global variable bool is_tentative; bool is_string_literal; @@ -244,6 +271,9 @@ struct Obj { bool is_noreturn; bool is_destructor; bool is_constructor; + bool is_ms_abi; /* TODO */ + bool is_force_align_arg_pointer; + bool is_no_caller_saved_registers; int stack_size; Obj *params; Node *body; @@ -419,6 +449,7 @@ struct Type { int align; // alignment bool is_unsigned; // unsigned or signed bool is_atomic; // true if _Atomic + bool is_ms_abi; // microsoft abi Type *origin; // for type compatibility check // Pointer-to or array-of type. We intentionally use the same member // to represent pointer/array duality in C. @@ -534,11 +565,11 @@ typedef struct { void *val; } HashEntry; -typedef struct { +struct HashMap { HashEntry *buckets; int capacity; int used; -} HashMap; +}; void *hashmap_get(HashMap *, char *); void *hashmap_get2(HashMap *, char *, int); @@ -584,6 +615,13 @@ Token *alloc_token(void); Obj *alloc_obj(void); Type *alloc_type(void); +// +// javadown.c +// + +void output_javadown(const char *, Obj *); +void drop_dox(const StringArray *, const char *); + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */ diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index 67d0bd19..a3b7c132 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -49,6 +49,7 @@ THIRD_PARTY_CHIBICC_A_CHECKS = \ $(THIRD_PARTY_CHIBICC_A_HDRS:%=o/$(MODE)/%.ok) THIRD_PARTY_CHIBICC_A_DIRECTDEPS = \ + LIBC_ALG \ LIBC_BITS \ LIBC_CALLS \ LIBC_CALLS_HEFTY \ diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index 658cf35c..608c72f3 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -2265,7 +2265,7 @@ static void emit_data(Obj *prog) { } } -static void store_fp(int r, int offset, int sz) { +static void store_fp(Obj *fn, int r, int offset, int sz) { switch (sz) { case 4: println("\tmovss\t%%xmm%d,%d(%%rbp)", r, offset); @@ -2274,7 +2274,8 @@ static void store_fp(int r, int offset, int sz) { println("\tmovsd\t%%xmm%d,%d(%%rbp)", r, offset); return; case 16: - println("\tmovaps\t%%xmm%d,%d(%%rbp)", r, offset); + println("\t%s\t%%xmm%d,%d(%%rbp)", + fn->is_force_align_arg_pointer ? "movups" : "movaps", r, offset); return; } UNREACHABLE(); @@ -2381,13 +2382,13 @@ static void emit_text(Obj *prog) { case TY_UNION: assert(ty->size <= 16); if (has_flonum(ty, 0, 8, 0)) { - store_fp(fp++, var->offset, MIN(8, ty->size)); + store_fp(fn, fp++, var->offset, MIN(8, ty->size)); } else { store_gp(gp++, var->offset, MIN(8, ty->size)); } if (ty->size > 8) { if (has_flonum(ty, 8, 16, 0)) { - store_fp(fp++, var->offset + 8, ty->size - 8); + store_fp(fn, fp++, var->offset + 8, ty->size - 8); } else { store_gp(gp++, var->offset + 8, ty->size - 8); } @@ -2395,7 +2396,7 @@ static void emit_text(Obj *prog) { break; case TY_FLOAT: case TY_DOUBLE: - store_fp(fp++, var->offset, ty->size); + store_fp(fn, fp++, var->offset, ty->size); break; case TY_INT128: store_gp(gp++, var->offset + 0, 8); @@ -2405,6 +2406,20 @@ static void emit_text(Obj *prog) { store_gp(gp++, var->offset, ty->size); } } + if (fn->is_force_align_arg_pointer) { + emitlin("\tand\t$-16,%rsp"); + } + if (fn->is_no_caller_saved_registers) { + emitlin("\ +\tpush\t%rdi\n\ +\tpush\t%rsi\n\ +\tpush\t%rdx\n\ +\tpush\t%rcx\n\ +\tpush\t%r8\n\ +\tpush\t%r9\n\ +\tpush\t%r10\n\ +\tpush\t%r11"); + } // Emit code gen_stmt(fn->body); assert(!depth); @@ -2420,6 +2435,17 @@ static void emit_text(Obj *prog) { if (fn->is_noreturn) { emitlin("\tud2"); } else { + if (fn->is_no_caller_saved_registers) { + emitlin("\ +\tpop\t%r11\n\ +\tpop\t%r10\n\ +\tpop\t%r9\n\ +\tpop\t%r8\n\ +\tpop\t%rcx\n\ +\tpop\t%rdx\n\ +\tpop\t%rsi\n\ +\tpop\t%rdi"); + } emitlin("\tleave"); emitlin("\tret"); } diff --git a/third_party/chibicc/dox1.c b/third_party/chibicc/dox1.c new file mode 100644 index 00000000..a625d4bc --- /dev/null +++ b/third_party/chibicc/dox1.c @@ -0,0 +1,248 @@ +/*-*- 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 │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/gc.h" +#include "third_party/chibicc/chibicc.h" + +#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p)) + +struct DoxWriter { + struct Buffer { + size_t n; + char *p; + } buf; + struct Macros { + size_t n; + Macro **p; + } macros; + struct Objects { + size_t n; + Obj **p; + } objects; +}; + +static void SerializeData(struct Buffer *buf, const void *p, unsigned long n) { + struct Slice *s; + buf->p = realloc(buf->p, buf->n + n); + memcpy(buf->p + buf->n, p, n); + buf->n += n; +} + +static int SerializeInt(struct Buffer *buf, int x) { + unsigned char b[4]; + b[0] = x >> 000; + b[1] = x >> 010; + b[2] = x >> 020; + b[3] = x >> 030; + SerializeData(buf, b, 4); + return x; +} + +static void SerializeStr(struct Buffer *buf, const char *s) { + size_t n; + if (!s) s = ""; + n = strlen(s); + n = MIN(INT_MAX, n); + SerializeInt(buf, n); + SerializeData(buf, s, n); +} + +static void SerializeJavadown(struct Buffer *buf, struct Javadown *jd) { + int i; + SerializeInt(buf, jd->isfileoverview); + SerializeStr(buf, jd->title); + SerializeStr(buf, jd->text); + SerializeInt(buf, jd->tags.n); + for (i = 0; i < jd->tags.n; ++i) { + SerializeStr(buf, jd->tags.p[i].tag); + SerializeStr(buf, jd->tags.p[i].text); + } +} + +static char *DescribeScalar(struct Type *ty, char *name) { + return xasprintf("%s%s%s", ty->is_atomic ? "_Atomic " : "", + ty->is_unsigned ? "unsigned " : "", name); +} + +static char *DescribeType(struct Type *ty) { + switch (ty->kind) { + case TY_VOID: + return strdup("void"); + case TY_BOOL: + return strdup("_Bool"); + case TY_CHAR: + return DescribeScalar(ty, "char"); + case TY_SHORT: + return DescribeScalar(ty, "short"); + case TY_INT: + return DescribeScalar(ty, "int"); + case TY_LONG: + return DescribeScalar(ty, "long"); + case TY_INT128: + return DescribeScalar(ty, "__int128"); + case TY_FLOAT: + return DescribeScalar(ty, "float"); + case TY_DOUBLE: + return DescribeScalar(ty, "double"); + case TY_LDOUBLE: + return DescribeScalar(ty, "long double"); + case TY_PTR: + return xasprintf("%s*", gc(DescribeType(ty->base))); + case TY_ARRAY: + return xasprintf("%s[%d]", gc(DescribeType(ty->base)), ty->array_len); + case TY_ENUM: + if (ty->name_pos) { + return xasprintf("enum %.*s", ty->name_pos->len, ty->name_pos->loc); + } else { + return strdup("ANONYMOUS-ENUM"); + } + case TY_STRUCT: + if (ty->name_pos) { + return xasprintf("struct %.*s", ty->name_pos->len, ty->name_pos->loc); + } else { + return strdup("ANONYMOUS-STRUCT"); + } + case TY_UNION: + if (ty->name_pos) { + return xasprintf("union %.*s", ty->name_pos->len, ty->name_pos->loc); + } else { + return strdup("ANONYMOUS-UNION"); + } + case TY_FUNC: + return xasprintf("%s(*)()", gc(DescribeType(ty->return_ty))); + default: + return "UNKNOWN"; + } +} + +static int CountParams(Obj *params) { + int n; + for (n = 0; params; params = params->next) ++n; + return n; +} + +static const char *GetFileName(Obj *obj) { + if (obj->javadown && obj->javadown->file) return obj->javadown->file->name; + if (obj->tok && obj->tok->file) return obj->tok->file->name; + return "missingno.c"; +} + +static int GetLine(Obj *obj) { + if (obj->javadown && obj->javadown->file) return obj->javadown->line_no; + if (obj->tok && obj->tok->file) return obj->tok->line_no; + return 0; +} + +static void SerializeDox(struct DoxWriter *dox, Obj *prog) { + int i; + char *s; + Obj *param; + MacroParam *mparam; + SerializeInt(&dox->buf, dox->objects.n); + for (i = 0; i < dox->objects.n; ++i) { + s = DescribeType(dox->objects.p[i]->ty); + SerializeStr(&dox->buf, s); + free(s); + SerializeStr(&dox->buf, dox->objects.p[i]->name); + SerializeStr(&dox->buf, GetFileName(dox->objects.p[i])); + SerializeInt(&dox->buf, GetLine(dox->objects.p[i])); + SerializeInt(&dox->buf, dox->objects.p[i]->is_function); + SerializeInt(&dox->buf, dox->objects.p[i]->is_weak); + SerializeInt(&dox->buf, dox->objects.p[i]->is_inline); + SerializeInt(&dox->buf, dox->objects.p[i]->is_noreturn); + SerializeInt(&dox->buf, dox->objects.p[i]->is_destructor); + SerializeInt(&dox->buf, dox->objects.p[i]->is_constructor); + SerializeInt(&dox->buf, dox->objects.p[i]->is_force_align_arg_pointer); + SerializeInt(&dox->buf, dox->objects.p[i]->is_no_caller_saved_registers); + SerializeStr(&dox->buf, dox->objects.p[i]->visibility); + SerializeJavadown(&dox->buf, dox->objects.p[i]->javadown->javadown); + SerializeInt(&dox->buf, CountParams(dox->objects.p[i]->params)); + for (param = dox->objects.p[i]->params; param; param = param->next) { + s = DescribeType(param->ty); + SerializeStr(&dox->buf, s); + free(s); + SerializeStr(&dox->buf, param->name); + } + } + SerializeInt(&dox->buf, dox->macros.n); + for (i = 0; i < dox->macros.n; ++i) { + SerializeStr(&dox->buf, dox->macros.p[i]->name); + SerializeStr(&dox->buf, dox->macros.p[i]->javadown->file->name); + SerializeInt(&dox->buf, dox->macros.p[i]->javadown->line_no); + SerializeJavadown(&dox->buf, dox->macros.p[i]->javadown->javadown); + } + SerializeInt(&dox->buf, 31337); +} + +static void LoadPublicDefinitions(struct DoxWriter *dox, Obj *prog) { + int i; + Obj *obj; + Macro *macro; + for (obj = prog; obj; obj = obj->next) { + if (obj->is_static) continue; + if (*obj->name == '_') continue; + if (!obj->javadown) continue; + if (obj->is_string_literal) continue; + if (obj->visibility && !strcmp(obj->visibility, "hidden")) continue; + if (strchr(obj->name, '$')) continue; + APPEND(dox->objects); + dox->objects.p[dox->objects.n - 1] = obj; + } + for (i = 0; i < macros.capacity; ++i) { + if (!macros.buckets[i].key) continue; + if (macros.buckets[i].key == (char *)-1) continue; + macro = macros.buckets[i].val; + if (!macro->javadown) continue; + if (!macro->javadown->javadown) continue; + if (*macro->name == '_') continue; + if (strchr(macro->name, '$')) continue; + APPEND(dox->macros); + dox->macros.p[dox->macros.n - 1] = macro; + } +} + +static struct DoxWriter *NewDoxWriter(void) { + return calloc(1, sizeof(struct DoxWriter)); +} + +static void FreeDoxWriter(struct DoxWriter *dox) { + if (dox) { + free(dox->buf.p); + free(dox->macros.p); + free(dox->objects.p); + free(dox); + } +} + +static void WriteDox(struct DoxWriter *dox, const char *path) { + int fd; + CHECK_NE(-1, (fd = creat(path, 0644))); + CHECK_EQ(dox->buf.n, write(fd, dox->buf.p, dox->buf.n)); + close(fd); +} + +/** + * Emits documentation datum for compilation unit just parsed. + */ +void output_javadown(const char *path, Obj *prog) { + struct DoxWriter *dox = NewDoxWriter(); + LoadPublicDefinitions(dox, prog); + SerializeDox(dox, prog); + WriteDox(dox, path); + FreeDoxWriter(dox); +} diff --git a/third_party/chibicc/dox2.c b/third_party/chibicc/dox2.c new file mode 100644 index 00000000..8fa5ba52 --- /dev/null +++ b/third_party/chibicc/dox2.c @@ -0,0 +1,392 @@ +/*-*- 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 │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/alg.h" +#include "libc/bits/bits.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "third_party/chibicc/chibicc.h" + +#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p)) + +struct Dox { + unsigned char *p; + struct Freelist { + size_t n; + void **p; + } freelist; + struct Set { + size_t n; + struct SetEntry { + unsigned h; + char *s; + } * p; + } names; + struct DoxObjects { + size_t n; + struct DoxObject { + bool ignore; + char *type; + char *name; + char *path; + int line; + bool is_function; + bool is_weak; + bool is_inline; + bool is_noreturn; + bool is_destructor; + bool is_constructor; + bool is_force_align_arg_pointer; + bool is_no_caller_saved_registers; + char *visibility; + struct Javadown *javadown; + struct DoxObjectParams { + size_t n; + struct DoxObjectParam { + char *type; + char *name; + } * p; + } params; + } * p; + } objects; + struct { + size_t n; + int *p; + } objectindex; +}; + +static unsigned Hash(const void *p, unsigned long n) { + unsigned h, i; + for (h = i = 0; i < n; i++) { + h += ((unsigned char *)p)[i]; + h *= 0x9e3779b1; + } + return MAX(1, h); +} + +static struct Dox *NewDox(void) { + return calloc(1, sizeof(struct Dox)); +} + +static void FreeDox(struct Dox *dox) { + int i; + if (dox) { + for (i = 0; i < dox->freelist.n; ++i) { + free(dox->freelist.p[i]); + } + free(dox->names.p); + free(dox->freelist.p); + free(dox->objects.p); + free(dox); + } +} + +static void *FreeLater(struct Dox *dox, void *p) { + APPEND(dox->freelist); + dox->freelist.p[dox->freelist.n - 1] = p; + return p; +} + +static int DeserializeInt(struct Dox *dox) { + int x; + x = (unsigned)dox->p[0] << 000 | (unsigned)dox->p[1] << 010 | + (unsigned)dox->p[2] << 020 | (unsigned)dox->p[3] << 030; + dox->p += 4; + return x; +} + +static char *DeserializeStr(struct Dox *dox) { + char *s; + size_t n; + n = DeserializeInt(dox); + s = malloc(n + 1); + memcpy(s, dox->p, n); + s[n] = '\0'; + dox->p += n; + return FreeLater(dox, s); +} + +static struct Javadown *DeserializeJavadown(struct Dox *dox) { + int i; + struct Javadown *jd; + jd = FreeLater(dox, calloc(1, sizeof(struct Javadown))); + jd->isfileoverview = DeserializeInt(dox); + jd->title = DeserializeStr(dox); + jd->text = DeserializeStr(dox); + jd->tags.n = DeserializeInt(dox); + jd->tags.p = FreeLater(dox, malloc(jd->tags.n * sizeof(*jd->tags.p))); + for (i = 0; i < jd->tags.n; ++i) { + jd->tags.p[i].tag = DeserializeStr(dox); + jd->tags.p[i].text = DeserializeStr(dox); + } + return jd; +} + +static void DeserializeObject(struct Dox *dox, struct DoxObject *o) { + int i; + o->ignore = false; + o->type = DeserializeStr(dox); + o->name = DeserializeStr(dox); + o->path = DeserializeStr(dox); + o->line = DeserializeInt(dox); + o->is_function = DeserializeInt(dox); + o->is_weak = DeserializeInt(dox); + o->is_inline = DeserializeInt(dox); + o->is_noreturn = DeserializeInt(dox); + o->is_destructor = DeserializeInt(dox); + o->is_constructor = DeserializeInt(dox); + o->is_force_align_arg_pointer = DeserializeInt(dox); + o->is_no_caller_saved_registers = DeserializeInt(dox); + o->visibility = DeserializeStr(dox); + o->javadown = DeserializeJavadown(dox); + o->params.n = DeserializeInt(dox); + o->params.p = FreeLater(dox, malloc(o->params.n * sizeof(*o->params.p))); + for (i = 0; i < o->params.n; ++i) { + o->params.p[i].type = DeserializeStr(dox); + o->params.p[i].name = DeserializeStr(dox); + } +} + +static void DeserializeDox(struct Dox *dox) { + int i, j, n; + i = dox->objects.n; + n = DeserializeInt(dox); + dox->objects.p = + realloc(dox->objects.p, (dox->objects.n + n) * sizeof(*dox->objects.p)); + for (j = 0; j < n; ++j) { + DeserializeObject(dox, dox->objects.p + i + j); + } + dox->objects.n += n; +} + +static void ReadDox(struct Dox *dox, const StringArray *files) { + int i, fd; + void *map; + struct stat st; + for (i = 0; i < files->len; ++i) { + CHECK_NE(-1, (fd = open(files->data[i], O_RDONLY))); + CHECK_NE(-1, fstat(fd, &st)); + if (st.st_size) { + CHECK_NE(MAP_FAILED, + (map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))); + dox->p = map; + DeserializeDox(dox); + munmap(map, st.st_size); + } + close(fd); + } +} + +static bool AddSet(struct Set *set, char *s) { + unsigned i, h, k; + h = Hash(s, strlen(s)); + k = 0; + for (k = 0;; ++k) { + i = (h + k + ((k + 1) >> 1)) & (set->n - 1); + if (!set->p[i].h) { + set->p[i].h = h; + set->p[i].s = s; + return true; + } + if (h == set->p[i].h && !strcmp(s, set->p[i].s)) { + return false; + } + } +} + +static int CompareObjectNames(const void *a, const void *b, void *arg) { + int *i1, *i2; + struct Dox *dox; + i1 = a, i2 = b, dox = arg; + return strcmp(dox->objects.p[*i1].name, dox->objects.p[*i2].name); +} + +static void IndexDox(struct Dox *dox) { + size_t i, j, n; + dox->names.n = roundup2pow(dox->objects.n) << 1; + dox->names.p = calloc(dox->names.n, sizeof(*dox->names.p)); + for (n = i = 0; i < dox->objects.n; ++i) { + if (AddSet(&dox->names, dox->objects.p[i].name)) { + ++n; + } else { + dox->objects.p[i].ignore = true; + } + } + dox->objectindex.n = n; + dox->objectindex.p = malloc(n * sizeof(*dox->objectindex.p)); + for (j = i = 0; i < dox->objects.n; ++i) { + if (dox->objects.p[i].ignore) continue; + dox->objectindex.p[j++] = i; + } + qsort_r(dox->objectindex.p, dox->objectindex.n, sizeof(*dox->objectindex.p), + CompareObjectNames, dox); +} + +static void PrintText(FILE *f, const char *s) { + int c; + bool bol, pre; + for (pre = false, bol = true;;) { + switch ((c = *s++)) { + case '\0': + if (pre) { + fprintf(f, ""); + } + return; + case '&': + fprintf(f, "&"); + bol = false; + break; + case '<': + fprintf(f, "<"); + bol = false; + break; + case '>': + fprintf(f, ">"); + bol = false; + break; + case '"': + fprintf(f, """); + bol = false; + break; + case '\'': + fprintf(f, "'"); + bol = false; + break; + case '\n': + if (!pre && *s == '\n') { + ++s; + fprintf(f, "\n

"); + } else if (pre && + (s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) { + fprintf(f, "\n"); + pre = false; + } else { + fprintf(f, "\n"); + } + bol = true; + break; + case ' ': + if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') { + pre = true; + fprintf(f, "

");
+        }
+        fprintf(f, " ");
+        bol = false;
+        break;
+      default:
+        fprintf(f, "%c", c);
+        bol = false;
+        break;
+    }
+  }
+}
+
+static void PrintDox(struct Dox *dox, FILE *f) {
+  int i, j, k;
+  char *prefix;
+  struct DoxObject *o;
+  fprintf(f, "\
+\n\
+\n\
+\n\
+\n\
+
\n\ +

\n\ +"); + for (i = 0; i < dox->objectindex.n; ++i) { + o = dox->objects.p + dox->objectindex.p[i]; + if (o->ignore || !o->is_function) continue; + fprintf(f, "%s
\n", o->name, o->name); + fprintf(f, "
\n"); + } + fprintf(f, "

\n"); + for (i = 0; i < dox->objectindex.n; ++i) { + o = dox->objects.p + dox->objectindex.p[i]; + if (o->ignore || !o->is_function) continue; + fprintf(f, "\n
\n", o->name, o->name); + fprintf(f, "

", o->name); + fprintf(f, "%s

", o->name); + fprintf(f, "

"); + PrintText(f, o->javadown->title); + fprintf(f, "\n"); + if (*o->javadown->text) { + fprintf(f, "

"); + PrintText(f, o->javadown->text); + fprintf(f, "\n"); + } + fprintf(f, "

@param\n"); + fprintf(f, "

\n"); + if (o->params.n) { + fprintf(f, "
\n"); + for (j = 0; j < o->params.n; ++j) { + fprintf(f, "
"); + PrintText(f, o->params.p[j].type); + fprintf(f, " "); + PrintText(f, o->params.p[j].name); + fprintf(f, "\n"); + prefix = xasprintf("%s ", o->params.p[j].name); + for (k = 0; k < o->javadown->tags.n; ++k) { + if (!strcmp(o->javadown->tags.p[k].tag, "param") && + startswith(o->javadown->tags.p[k].text, prefix)) { + fprintf(f, "
"); + PrintText(f, o->javadown->tags.p[k].text + strlen(prefix)); + fprintf(f, "\n"); + break; + } + } + free(prefix); + } + fprintf(f, "
\n"); + } else { + fprintf(f, "

None.\n"); + } + fprintf(f, "

\n"); + for (k = 0; k < o->javadown->tags.n; ++k) { + if (!strcmp(o->javadown->tags.p[k].tag, "param")) continue; + fprintf(f, "

@"); + PrintText(f, o->javadown->tags.p[k].tag); + fprintf(f, "\n"); + if (*o->javadown->tags.p[k].text) { + PrintText(f, o->javadown->tags.p[k].text); + fprintf(f, "\n"); + } + } + fprintf(f, "

\n"); + } + fprintf(f, "
\n"); +} + +/** + * Merges documentation data and outputs HTML. + */ +void drop_dox(const StringArray *files, const char *path) { + FILE *f; + struct Dox *dox; + dox = NewDox(); + ReadDox(dox, files); + IndexDox(dox); + f = fopen(path, "w"); + PrintDox(dox, f); + fclose(f); + FreeDox(dox); +} diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c index 9866320a..0818f2d1 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -16,6 +16,7 @@ // So it is very easy to lookahead arbitrary number of tokens in this // parser. +#include "libc/nexgen32e/ffs.h" #include "libc/testlib/testlib.h" #include "third_party/chibicc/chibicc.h" @@ -50,11 +51,14 @@ typedef struct { bool is_const; bool is_tls; bool is_weak; + bool is_ms_abi; bool is_aligned; bool is_noreturn; bool is_destructor; bool is_constructor; bool is_externally_visible; + bool is_force_align_arg_pointer; + bool is_no_caller_saved_registers; int align; char *section; char *visibility; @@ -113,6 +117,8 @@ static Node *current_switch; static Obj *builtin_alloca; +static Token *current_javadown; + static Initializer *initializer(Token **, Token *, Type *, Type **); static Member *get_struct_member(Type *, Token *); static Node *binor(Token **, Token *); @@ -382,6 +388,10 @@ static Token *type_attributes(Token *tok, void *arg) { ty->is_packed = true; return tok; } + if (consume_attribute(&tok, tok, "ms_abi")) { + ty->is_ms_abi = true; + return tok; + } if (consume_attribute(&tok, tok, "aligned")) { ty->is_aligned = true; if (CONSUME(&tok, tok, "(")) { @@ -466,6 +476,18 @@ static Token *thing_attributes(Token *tok, void *arg) { attr->is_externally_visible = true; return tok; } + if (consume_attribute(&tok, tok, "force_align_arg_pointer")) { + attr->is_force_align_arg_pointer = true; + return tok; + } + if (consume_attribute(&tok, tok, "no_caller_saved_registers")) { + attr->is_no_caller_saved_registers = true; + return tok; + } + if (consume_attribute(&tok, tok, "ms_abi")) { + attr->is_ms_abi = true; + return tok; + } if (consume_attribute(&tok, tok, "constructor")) { attr->is_constructor = true; if (CONSUME(&tok, tok, "(")) { @@ -1080,6 +1102,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, // even if ty is not VLA because ty may be a pointer to VLA // (e.g. int (*foo)[n][m] where n and m are variables.) cur = cur->next = new_unary(ND_EXPR_STMT, compute_vla_size(ty, tok), tok); + tok = attribute_list(tok, attr, thing_attributes); if (ty->kind == TY_VLA) { if (EQUAL(tok, "=")) error_tok(tok, "variable-sized object may not be initialized"); @@ -1198,7 +1221,8 @@ static Member *struct_designator(Token **rest, Token *tok, Type *ty) { if (tok->kind != TK_IDENT) error_tok(tok, "expected a field designator"); for (Member *mem = ty->members; mem; mem = mem->next) { // Anonymous struct member - if (mem->ty->kind == TY_STRUCT && !mem->name) { + if ((mem->ty->kind == TY_STRUCT || mem->ty->kind == TY_UNION) && + !mem->name) { if (get_struct_member(mem->ty, tok)) { *rest = start; return mem; @@ -1920,6 +1944,7 @@ int64_t eval(Node *node) { // number. The latter form is accepted only as an initialization // expression for a global variable. int64_t eval2(Node *node, char ***label) { + int64_t x, y; add_type(node); if (is_flonum(node->ty)) return eval_double(node); switch (node->kind) { @@ -1930,15 +1955,25 @@ int64_t eval2(Node *node, char ***label) { case ND_MUL: return eval(node->lhs) * eval(node->rhs); case ND_DIV: - if (node->ty->is_unsigned) - return (uint64_t)eval(node->lhs) / eval(node->rhs); - return eval(node->lhs) / eval(node->rhs); + y = eval(node->rhs); + if (!y) error_tok(node->rhs->tok, "constexpr div by zero"); + if (node->ty->is_unsigned) { + return (uint64_t)eval(node->lhs) / y; + } + x = eval(node->lhs); + if (x == 0x8000000000000000 && y == -1) { + error_tok(node->rhs->tok, "constexpr divide error"); + } + return x / y; case ND_NEG: return -eval(node->lhs); case ND_REM: - if (node->ty->is_unsigned) - return (uint64_t)eval(node->lhs) % eval(node->rhs); - return eval(node->lhs) % eval(node->rhs); + y = eval(node->rhs); + if (!y) error_tok(node->rhs->tok, "constexpr rem by zero"); + if (node->ty->is_unsigned) { + return (uint64_t)eval(node->lhs) % y; + } + return eval(node->lhs) % y; case ND_BINAND: return eval(node->lhs) & eval(node->rhs); case ND_BINOR: @@ -2044,8 +2079,9 @@ int64_t eval2(Node *node, char ***label) { static int64_t eval_rval(Node *node, char ***label) { switch (node->kind) { case ND_VAR: - if (node->var->is_local) + if (node->var->is_local) { error_tok(node->tok, "not a compile-time constant"); + } *label = &node->var->name; return 0; case ND_DEREF: @@ -2063,6 +2099,7 @@ bool is_const_expr(Node *node) { case ND_SUB: case ND_MUL: case ND_DIV: + case ND_REM: case ND_BINAND: case ND_BINOR: case ND_BINXOR: @@ -2884,8 +2921,9 @@ static Node *postfix(Token **rest, Token *tok) { static Node *funcall(Token **rest, Token *tok, Node *fn) { add_type(fn); if (fn->ty->kind != TY_FUNC && - (fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC)) + (fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC)) { error_tok(fn->tok, "not a function"); + } Type *ty = (fn->ty->kind == TY_FUNC) ? fn->ty : fn->ty->base; Type *param_ty = ty->params; Node head = {}; @@ -2896,8 +2934,9 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { add_type(arg); if (!param_ty && !ty->is_variadic) error_tok(tok, "too many arguments"); if (param_ty) { - if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION) + if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION) { arg = new_cast(arg, param_ty); + } param_ty = param_ty->next; } else if (arg->ty->kind == TY_FLOAT) { // If parameter type is omitted (e.g. in "..."), float @@ -2914,8 +2953,9 @@ static Node *funcall(Token **rest, Token *tok, Node *fn) { node->args = head.next; // If a function returns a struct, it is caller's responsibility // to allocate a space for the return value. - if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION) + if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION) { node->ret_buffer = new_lvar("", node->ty); + } return node; } @@ -3138,13 +3178,37 @@ static Node *primary(Token **rest, Token *tok) { *rest = skip(tok, ')'); return node; } - if (EQUAL(tok, "__builtin_popcount") || EQUAL(tok, "__builtin_popcountl") || + if (EQUAL(tok, "__builtin_popcount")) { + Token *t = skip(tok->next, '('); + Node *node = assign(&t, t); + if (is_const_expr(node)) { + *rest = skip(t, ')'); + return new_num(__builtin_popcount(eval(node)), t); + } + } + if (EQUAL(tok, "__builtin_popcountl") || EQUAL(tok, "__builtin_popcountll")) { Token *t = skip(tok->next, '('); Node *node = assign(&t, t); if (is_const_expr(node)) { *rest = skip(t, ')'); - return new_num(popcnt(eval(node)), t); + return new_num(__builtin_popcountl(eval(node)), t); + } + } + if (EQUAL(tok, "__builtin_ffs")) { + Token *t = skip(tok->next, '('); + Node *node = assign(&t, t); + if (is_const_expr(node)) { + *rest = skip(t, ')'); + return new_num(__builtin_ffs(eval(node)), t); + } + } + if (EQUAL(tok, "__builtin_ffsl") || EQUAL(tok, "__builtin_ffsll")) { + Token *t = skip(tok->next, '('); + Node *node = assign(&t, t); + if (is_const_expr(node)) { + *rest = skip(t, ')'); + return new_num(__builtin_ffsl(eval(node)), t); } } } @@ -3328,15 +3392,19 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern); fn->is_inline = attr->is_inline; fn->is_weak = attr->is_weak; + fn->is_ms_abi = attr->is_ms_abi; fn->is_aligned = attr->is_aligned; fn->is_noreturn = attr->is_noreturn; fn->is_destructor = attr->is_destructor; fn->is_constructor = attr->is_constructor; fn->is_externally_visible = attr->is_externally_visible; + fn->is_force_align_arg_pointer = attr->is_force_align_arg_pointer; + fn->is_no_caller_saved_registers = attr->is_no_caller_saved_registers; fn->align = attr->align; fn->section = attr->section; fn->visibility = attr->visibility; } + fn->javadown = fn->javadown ?: current_javadown; fn->is_root = !(fn->is_static && fn->is_inline); if (consume_attribute(&tok, tok, "asm")) { tok = skip(tok, '('); @@ -3352,11 +3420,13 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { // A buffer for a struct/union return value is passed // as the hidden first parameter. Type *rty = ty->return_ty; - if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16) + if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16) { new_lvar("", pointer_to(rty)); + } fn->params = locals; - if (ty->is_variadic) + if (ty->is_variadic) { fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136)); + } fn->alloca_bottom = new_lvar("__alloca_size__", pointer_to(ty_char)); tok = skip(tok, '{'); // [https://www.sigbus.info/n1570#6.4.2.2p1] "__func__" is @@ -3382,6 +3452,7 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) { Type *ty = declarator(&tok, tok, basety); if (!ty->name) error_tok(ty->name_pos, "variable name omitted"); Obj *var = new_gvar(get_ident(ty->name), ty); + var->javadown = current_javadown; if (consume_attribute(&tok, tok, "asm")) { tok = skip(tok, '('); var->asmname = ConsumeStringLiteral(&tok, tok); @@ -3528,6 +3599,12 @@ Obj *parse(Token *tok) { tok = static_assertion(tok); continue; } + if (tok->kind == TK_JAVADOWN) { + current_javadown = tok; + tok = tok->next; + } else { + current_javadown = NULL; + } VarAttr attr = {}; tok = attribute_list(tok, &attr, thing_attributes); Type *basety = declspec(&tok, tok, &attr); diff --git a/third_party/chibicc/preprocess.c b/third_party/chibicc/preprocess.c index 6098b3b9..1d4e9cfc 100644 --- a/third_party/chibicc/preprocess.c +++ b/third_party/chibicc/preprocess.c @@ -26,11 +26,7 @@ typedef struct CondIncl CondIncl; typedef struct Hideset Hideset; -typedef struct Macro Macro; typedef struct MacroArg MacroArg; -typedef struct MacroParam MacroParam; - -typedef Token *macro_handler_fn(Token *); typedef enum { STR_NONE, @@ -40,11 +36,6 @@ typedef enum { STR_WIDE, } StringKind; -struct MacroParam { - MacroParam *next; - char *name; -}; - struct MacroArg { MacroArg *next; char *name; @@ -52,15 +43,6 @@ struct MacroArg { Token *tok; }; -struct Macro { - char *name; - bool is_objlike; // Object-like or function-like - MacroParam *params; - char *va_args_name; - Token *body; - macro_handler_fn *handler; -}; - // `#if` can be nested, so we use a stack to manage nested `#if`s. struct CondIncl { CondIncl *next; @@ -74,7 +56,8 @@ struct Hideset { char *name; }; -static HashMap macros; +HashMap macros; + static CondIncl *cond_incl; static HashMap pragma_once; static int include_next_idx; @@ -338,21 +321,24 @@ static MacroParam *read_macro_params(Token **rest, Token *tok, return head.next; } -static void read_macro_definition(Token **rest, Token *tok) { +static Macro *read_macro_definition(Token **rest, Token *tok) { + Macro *m; + char *name; if (tok->kind != TK_IDENT) error_tok(tok, "macro name must be an identifier"); - char *name = strndup(tok->loc, tok->len); + name = strndup(tok->loc, tok->len); tok = tok->next; if (!tok->has_space && EQUAL(tok, "(")) { // Function-like macro char *va_args_name = NULL; MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name); - Macro *m = add_macro(name, false, copy_line(rest, tok)); + m = add_macro(name, false, copy_line(rest, tok)); m->params = params; m->va_args_name = va_args_name; } else { // Object-like macro - add_macro(name, true, copy_line(rest, tok)); + m = add_macro(name, true, copy_line(rest, tok)); } + return m; } static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) { @@ -742,6 +728,12 @@ static Token *preprocess2(Token *tok) { while (tok->kind != TK_EOF) { // If it is a macro, expand it. if (expand_macro(&tok, tok)) continue; + // make sure javadown is removed if it's for a macro definition + if (tok->kind == TK_JAVADOWN && is_hash(tok->next) && + EQUAL(tok->next->next, "define")) { + read_macro_definition(&tok, tok->next->next->next)->javadown = tok; + continue; + } // Pass through if it is not a "#". if (!is_hash(tok)) { tok->line_delta = tok->file->line_delta; @@ -936,6 +928,8 @@ __GNUC_PATCHLEVEL__\000\ 0\000\ __NO_INLINE__\000\ 16\000\ +__GNUC_STDC_INLINE__\000\ +1\000\ __BIGGEST_ALIGNMENT__\000\ 16\000\ __C99_MACRO_WITH_VA_ARGS\000\ @@ -1010,6 +1004,10 @@ __UINT32_MAX__\000\ 0xffffffffu\000\ __INT64_MAX__\000\ 0x7fffffffffffffffl\000\ +__LONG_MAX__\000\ +0x7fffffffffffffffl\000\ +__LONG_LONG_MAX__\000\ +0x7fffffffffffffffl\000\ __UINT64_MAX__\000\ 0xfffffffffffffffful\000\ __SIZE_MAX__\000\ diff --git a/third_party/chibicc/test/attribute_test.c b/third_party/chibicc/test/attribute_test.c index 7d99d5c7..92647301 100644 --- a/third_party/chibicc/test/attribute_test.c +++ b/third_party/chibicc/test/attribute_test.c @@ -12,7 +12,8 @@ __attribute__((__nonnull__(1))) void cate2(char *); __attribute__((__section__(".data.var"))) int var2; __attribute__((__section__(".data.var"))) int ar2[4]; -int main() { +__attribute__((__force_align_arg_pointer__, __no_caller_saved_registers__)) int +main() { int2 a; ASSERT(64, _Alignof(int2)); ASSERT(64, _Alignof(a)); diff --git a/third_party/chibicc/test/vla_test.c b/third_party/chibicc/test/vla_test.c index 7f98e1ca..4d00cbaa 100644 --- a/third_party/chibicc/test/vla_test.c +++ b/third_party/chibicc/test/vla_test.c @@ -1,3 +1,4 @@ +#include "libc/macros.h" #include "third_party/chibicc/test/test.h" int main() { @@ -6,6 +7,11 @@ int main() { int x[n]; sizeof(x); })); + ASSERT(5, ({ + int n = 5; + int x[n]; + ARRAYLEN(x); + })); ASSERT((5 + 1) * (8 * 2) * 4, ({ int m = 5, n = 8; int x[m + 1][n * 2]; diff --git a/third_party/chibicc/tokenize.c b/third_party/chibicc/tokenize.c index c20507fc..f339f558 100644 --- a/third_party/chibicc/tokenize.c +++ b/third_party/chibicc/tokenize.c @@ -470,6 +470,7 @@ Token *tokenize(File *file) { char *p = file->contents; Token head = {}; Token *cur = &head; + struct Javadown *javadown; at_bol = true; has_space = false; while (*p) { @@ -480,6 +481,22 @@ Token *tokenize(File *file) { has_space = true; continue; } + // Javadoc-style markdown comments. + if (LOOKINGAT(p, "/**") && p[3] != '/' && p[3] != '*') { + char *q = strstr(p + 3, "*/"); + if (!q) error_at(p, "unclosed javadown"); + javadown = ParseJavadown(p + 3, q - p - 3 - 2); + if (javadown->isfileoverview) { + FreeJavadown(file->javadown); + file->javadown = javadown; + } else { + cur = cur->next = new_token(TK_JAVADOWN, p, q + 2); + cur->javadown = javadown; + } + p = q + 2; + has_space = true; + continue; + } // Skip block comments. if (LOOKINGAT(p, "/*")) { char *q = strstr(p + 2, "*/"); @@ -505,12 +522,13 @@ Token *tokenize(File *file) { if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) { char *q = p++; for (;;) { - if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) + if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1])) { p += 2; - else if (isalnum(*p) || *p == '.') + } else if (isalnum(*p) || *p == '.') { p++; - else + } else { break; + } } cur = cur->next = new_token(TK_PP_NUM, q, p); continue; @@ -663,7 +681,30 @@ void remove_backslash_newline(char *p) { // the logical line number matches the physical one. // This counter maintain the number of newlines we have removed. int n = 0; + bool instring = false; while (p[i]) { + if (instring) { + if (p[i] == '"' && p[i - 1] != '\\') { + instring = false; + } + } else { + if (p[i] == '"') { + instring = true; + } else if (p[i] == '/' && p[i + 1] == '*') { + p[j++] = p[i++]; + p[j++] = p[i++]; + while (p[i]) { + if (p[i] == '*' && p[i + 1] == '/') { + p[j++] = p[i++]; + p[j++] = p[i++]; + break; + } else { + p[j++] = p[i++]; + } + } + continue; + } + } if (p[i] == '\\' && p[i + 1] == '\n') { i += 2; n++; diff --git a/third_party/dlmalloc/mallinfo.c b/third_party/dlmalloc/mallinfo.c index 4d8b0e88..b696a505 100644 --- a/third_party/dlmalloc/mallinfo.c +++ b/third_party/dlmalloc/mallinfo.c @@ -4,19 +4,28 @@ /** * Returns (by copy) a struct containing various summary statistics: * - * arena: current total non-mmapped bytes allocated from system - * ordblks: the number of free chunks - * smblks: always zero. - * hblks: current number of mmapped regions - * hblkhd: total bytes held in mmapped regions - * usmblks: the maximum total allocated space. This will be greater - * than current total if trimming has occurred. - * fsmblks: always zero - * uordblks: current total allocated space (normal or mmapped) - * fordblks: total free space - * keepcost: the maximum number of bytes that could ideally be released - * back to system via malloc_trim. ("ideally" means that - * it ignores page restrictions etc.) + * - arena: current total non-mmapped bytes allocated from system + * + * - ordblks: the number of free chunks + * + * - smblks: always zero. + * + * - hblks: current number of mmapped regions + * + * - hblkhd: total bytes held in mmapped regions + * + * - usmblks: the maximum total allocated space. This will be greater + * than current total if trimming has occurred. + * + * - fsmblks: always zero + * + * - uordblks: current total allocated space (normal or mmapped) + * + * - fordblks: total free space + * + * - keepcost: the maximum number of bytes that could ideally be + * released back to system via malloc_trim. ("ideally" means that it + * ignores page restrictions etc.) * * Because these fields are ints, but internal bookkeeping may * be kept as longs, the reported values may wrap around zero and diff --git a/third_party/musl/glob.c b/third_party/musl/glob.c index 336e38f4..6fa3370c 100644 --- a/third_party/musl/glob.c +++ b/third_party/musl/glob.c @@ -227,13 +227,13 @@ static int GlobPredicate(const void *a, const void *b) { * * For example: * - * glob_t g = {.gl_offs = 2}; - * glob("*.*", GLOB_DOOFFS, NULL, &g); - * glob("../.*", GLOB_DOOFFS | GLOB_APPEND, NULL, &g); - * g.gl_pathv[0] = "ls"; - * g.gl_pathv[1] = "-l"; - * execvp("ls", &g.gl_pathv[0]); - * globfree(g); + * glob_t g = {.gl_offs = 2}; + * glob("*.*", GLOB_DOOFFS, NULL, &g); + * glob("../.*", GLOB_DOOFFS | GLOB_APPEND, NULL, &g); + * g.gl_pathv[0] = "ls"; + * g.gl_pathv[1] = "-l"; + * execvp("ls", &g.gl_pathv[0]); + * globfree(g); * * @param pat can have star wildcard see fnmatch() * @param g will receive matching entries and needs globfree() diff --git a/third_party/regex/regcomp.c b/third_party/regex/regcomp.c index c60d7bbd..093afc37 100644 --- a/third_party/regex/regcomp.c +++ b/third_party/regex/regcomp.c @@ -2387,10 +2387,10 @@ static reg_errcode_t tre_ast_to_tnfa(tre_ast_node_t *node, /** * Compiles regular expression, e.g. * - * regex_t rx; - * EXPECT_EQ(REG_OK, regcomp(&rx, "^[A-Za-z\x7f-\uFFFF]{2}$", REG_EXTENDED)); - * EXPECT_EQ(REG_OK, regexec(&rx, "→A", 0, NULL, 0)); - * regfree(&rx); + * regex_t rx; + * EXPECT_EQ(REG_OK, regcomp(&rx, "^[A-Za-z]{2}$", REG_EXTENDED)); + * EXPECT_EQ(REG_OK, regexec(&rx, "→A", 0, NULL, 0)); + * regfree(&rx); * * @param preg points to state, and needs regfree() afterwards * @param regex is utf-8 regular expression string diff --git a/third_party/zlib/zlib.h b/third_party/zlib/zlib.h index d3587cf7..f2219a21 100644 --- a/third_party/zlib/zlib.h +++ b/third_party/zlib/zlib.h @@ -38,11 +38,11 @@ * even in the case of corrupted input. */ -#define ZLIB_VERSION "1.2.11" -#define ZLIB_VERNUM 0x12b0 -#define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 11 +#define ZLIB_VERSION "1.2.11" +#define ZLIB_VERNUM 0x12b0 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 11 #define ZLIB_VER_SUBREVISION 0 /** @@ -81,25 +81,25 @@ * (particularly if the decompressor wants to decompress everything in a * single step). */ -#define Z_NO_FLUSH 0 +#define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -#define Z_TREES 6 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 /** * Allowed flush values; see deflate() and inflate() below for details. */ -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /** @@ -107,26 +107,26 @@ * values are errors, positive values are used for special but normal * events. */ -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /** * Compression levels. */ -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /** * Compression strategy; see deflateInit2() below for details */ -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /** @@ -1139,7 +1139,7 @@ int inflateBack(z_streamp strm, in_func in, void *in_desc, out_func out, */ int inflateBackEnd(z_streamp strm); -/** +/* * Return flags indicating compile-time options. * * Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: @@ -1160,10 +1160,13 @@ int inflateBackEnd(z_streamp strm); * 14,15: 0 (reserved) * * Library content (indicates missing functionality): + * * 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - * deflate code when not needed) - * 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - * and decode gzip streams (to avoid linking crc code) + * deflate code when not needed) + * + * 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't + * detect and decode gzip streams (to avoid linking crc code) + * * 18-19: 0 (reserved) * * Operation variations (changes in library functionality): @@ -1685,12 +1688,11 @@ uLong adler32_combine(uLong adler1, uLong adler2, int64_t len2); * * Usage example: * - * uLong crc = crc32(0L, Z_NULL, 0); - * - * while (read_buffer(buffer, length) != EOF) { - * crc = crc32(crc, buffer, length); - * } - * if (crc != original_crc) error(); + * uLong crc = crc32(0L, Z_NULL, 0); + * while (read_buffer(buffer, length) != EOF) { + * crc = crc32(crc, buffer, length); + * } + * if (crc != original_crc) error(); */ uLong crc32(uLong crc, const Bytef *buf, uInt len); diff --git a/tool/build/lib/javadown.c b/tool/build/lib/javadown.c new file mode 100644 index 00000000..0b9014b5 --- /dev/null +++ b/tool/build/lib/javadown.c @@ -0,0 +1,276 @@ +/*-*- 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/limits.h" +#include "libc/mem/mem.h" +#include "libc/str/str.h" +#include "tool/build/lib/javadown.h" + +#define FILEOVERVIEW "@fileoverview" + +struct Lines { + size_t n; + struct Line { + char *p; + size_t n; + } * p; +}; + +static char *SkipEmptyFirstLine(char *p) { + int i = 0; + while (p[i] == ' ' || p[i] == '\t') ++i; + return p[i] == '\n' ? p + i + 1 : p; +} + +static void DeleteLastEmptyLine(char *p, size_t n) { + while (n && (p[n - 1] == ' ' || p[n - 1] == '\t')) --n; + if (n && p[n - 1] == '\n') p[n - 1] = '\0'; +} + +static void AppendLine(struct Lines *lines) { + lines->p = realloc(lines->p, ++lines->n * sizeof(*lines->p)); + memset(lines->p + lines->n - 1, 0, sizeof(*lines->p)); +} + +static void AppendTag(struct JavadownTags *tags) { + tags->p = realloc(tags->p, ++tags->n * sizeof(*tags->p)); + memset(tags->p + tags->n - 1, 0, sizeof(*tags->p)); +} + +static unsigned GetSpacePrefixLen(const char *p, size_t n) { + int i; + for (i = 0; i < n; ++i) { + if (p[i] != ' ' && p[i] != '\t') { + break; + } + } + return i; +} + +static unsigned GetSpaceStarPrefixLen(const char *p, size_t n) { + int i; + i = GetSpacePrefixLen(p, n); + return i < n && (p[i] == '*') ? i + 1 : 0; +} + +static unsigned GetTagLen(const char *p, size_t n) { + int i; + for (i = 0; i < n; ++i) { + if (!islower(p[i])) { + break; + } + } + return i; +} + +static unsigned GetMinPrefixLen(struct Lines *lines, + unsigned GetPrefixLen(const char *, size_t)) { + int i; + unsigned n, m; + for (m = -1, i = 0; i < lines->n; ++i) { + if (lines->p[i].n) { + n = GetPrefixLen(lines->p[i].p, lines->p[i].n); + if (n < m) m = n; + } + } + return m == -1 ? 0 : m; +} + +static void RemovePrefixes(struct Lines *lines, unsigned m) { + int i; + for (i = 0; i < lines->n; ++i) { + if (m <= lines->p[i].n) { + lines->p[i].p += m; + lines->p[i].n -= m; + } + } +} + +static void SplitLines(struct Lines *lines, char *p) { + char *q; + DeleteLastEmptyLine(p, strlen(p)); + p = SkipEmptyFirstLine(p); + for (;;) { + AppendLine(lines); + lines->p[lines->n - 1].p = p; + lines->p[lines->n - 1].n = (q = strchr(p, '\n')) ? q - p : strlen(p); + if (!q) break; + p = q + 1; + } + RemovePrefixes(lines, GetMinPrefixLen(lines, GetSpaceStarPrefixLen)); + RemovePrefixes(lines, GetMinPrefixLen(lines, GetSpacePrefixLen)); +} + +static bool ConsumeFileOverview(struct Lines *lines) { + int i; + if (lines->n && lines->p[0].n >= strlen(FILEOVERVIEW) && + startswith(lines->p[0].p, FILEOVERVIEW)) { + lines->p[0].p += strlen(FILEOVERVIEW); + lines->p[0].n -= strlen(FILEOVERVIEW); + while (lines->p[0].n && + (lines->p[0].p[0] == ' ' || lines->p[0].p[0] == '\t')) { + lines->p[0].p += 1; + lines->p[0].n -= 1; + } + return true; + } else { + return false; + } +} + +static void RemoveTrailingWhitespace(struct Lines *lines) { + int i; + for (i = 0; i < lines->n; ++i) { + while (lines->p[i].n && isspace(lines->p[i].p[lines->p[i].n - 1])) { + --lines->p[i].n; + } + } +} + +static int ExtractTitle(struct Javadown *jd, struct Lines *lines) { + int i; + char *p; + size_t n; + for (p = NULL, n = i = 0; i < lines->n; ++i) { + if (!lines->p[i].n) { + ++i; + break; + } + if (*lines->p[i].p == '@') { + break; + } + if (i) { + p = realloc(p, ++n); + p[n - 1] = ' '; + } + p = realloc(p, n + lines->p[i].n); + memcpy(p + n, lines->p[i].p, lines->p[i].n); + n += lines->p[i].n; + } + p = realloc(p, n + 1); + p[n] = '\0'; + jd->title = p; + return i; +} + +static int ExtractText(struct Javadown *jd, struct Lines *lines, int i) { + int j; + char *p; + size_t n; + for (p = NULL, n = j = 0; i + j < lines->n; ++j) { + if (lines->p[i + j].n && lines->p[i + j].p[0] == '@') break; + if (j) { + p = realloc(p, ++n); + p[n - 1] = '\n'; + } + p = realloc(p, n + lines->p[i + j].n); + memcpy(p + n, lines->p[i + j].p, lines->p[i + j].n); + n += lines->p[i + j].n; + } + p = realloc(p, n + 1); + p[n] = '\0'; + jd->text = p; + return i; +} + +static void ExtractTags(struct Javadown *jd, struct Lines *lines, int i) { + size_t n; + char *p, *tag, *text, *p2; + unsigned taglen, textlen, n2; + for (p = NULL, n = 0; i < lines->n; ++i) { + if (!lines->p[i].n) continue; + if (lines->p[i].p[0] != '@') continue; + tag = lines->p[i].p + 1; + taglen = GetTagLen(tag, lines->p[i].n - 1); + if (!taglen) continue; + text = tag + taglen; + tag = strndup(tag, taglen); + textlen = lines->p[i].n - 1 - taglen; + while (textlen && isspace(*text)) { + ++text; + --textlen; + } + text = strndup(text, textlen); + while (i + 1 < lines->n && + (!lines->p[i + 1].n || lines->p[i + 1].p[0] != '@')) { + ++i; + p2 = lines->p[i].p; + n2 = lines->p[i].n; + if (n2 && *p2 == '\t') { + p2 += 1; + n2 -= 1; + } + if (n2 >= 4 && !memcmp(p2, " ", 4)) { + p2 += 4; + n2 -= 4; + } + text = realloc(text, textlen + 1 + n2 + 1); + text[textlen] = '\n'; + memcpy(text + textlen + 1, p2, n2); + textlen += 1 + n2; + text[textlen] = '\0'; + } + AppendTag(&jd->tags); + jd->tags.p[jd->tags.n - 1].tag = tag; + jd->tags.p[jd->tags.n - 1].text = text; + } +} + +/** + * Parses javadown. + * + * @param data should point to text inside the slash star markers + * @param size is length of data in bytes + * @return object that should be passed to FreeJavadown() + */ +struct Javadown *ParseJavadown(const char *data, size_t size) { + int i; + char *p; + struct Lines lines; + struct Javadown *jd; + memset(&lines, 0, sizeof(lines)); + jd = calloc(1, sizeof(struct Javadown)); + p = strndup(data, size); + SplitLines(&lines, p); + RemoveTrailingWhitespace(&lines); + jd->isfileoverview = ConsumeFileOverview(&lines); + i = ExtractTitle(jd, &lines); + i = ExtractText(jd, &lines, i); + ExtractTags(jd, &lines, i); + free(lines.p); + free(p); + return jd; +} + +/** + * Frees object returned by ParseJavadown(). + */ +void FreeJavadown(struct Javadown *jd) { + int i; + if (jd) { + for (i = 0; i < jd->tags.n; ++i) { + free(jd->tags.p[i].tag); + free(jd->tags.p[i].text); + } + free(jd->tags.p); + free(jd->title); + free(jd->text); + free(jd); + } +} diff --git a/tool/build/lib/javadown.h b/tool/build/lib/javadown.h new file mode 100644 index 00000000..3a8b7240 --- /dev/null +++ b/tool/build/lib/javadown.h @@ -0,0 +1,24 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_JAVADOWN_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_JAVADOWN_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct Javadown { + bool isfileoverview; + char *title; + char *text; + struct JavadownTags { + size_t n; + struct JavadownTag { + char *tag; + char *text; + } * p; + } tags; +}; + +struct Javadown *ParseJavadown(const char *, size_t); +void FreeJavadown(struct Javadown *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_JAVADOWN_H_ */ diff --git a/tool/emacs/javadown.el b/tool/emacs/javadown.el index 275e14cb..d32f7808 100644 --- a/tool/emacs/javadown.el +++ b/tool/emacs/javadown.el @@ -43,6 +43,27 @@ "\\)*>") 0 ,c-doc-markup-face-name prepend nil))) +;; (defconst javadown-font-lock-doc-comments +;; `(("{@[a-z]+[^}\n\r]*}" ; "{@foo ...}" markup. +;; 0 ,c-doc-markup-face-name prepend nil) +;; ("^\\(/\\*\\)?\\(\\s \\|\\*\\)*\\(@[a-z]+\\)" ; "@foo ..." markup. +;; 3 ,c-doc-markup-face-name prepend nil) +;; (,(concat "") +;; 0 ,c-doc-markup-face-name prepend nil) +;; ;; ("&\\(\\sw\\|[.:]\\)+;" ; HTML entities. +;; ;; 0 ,c-doc-markup-face-name prepend nil) +;; ;; Fontify remaining markup characters as invalid. Note +;; ;; that the Javadoc spec is hazy about when "@" is +;; ;; allowed in non-markup use. [jart: we like markdown] +;; ;; (,(lambda (limit) +;; ;; (c-find-invalid-doc-markup "[<>&]\\|{@" limit)) +;; ;; 0 'font-lock-warning-face prepend nil) +;; )) + (defconst javadown-font-lock-keywords `((,(lambda (limit) (c-font-lock-doc-comments "/\\*\\*" limit