diff --git a/Makefile b/Makefile index 06465884..f865fae0 100644 --- a/Makefile +++ b/Makefile @@ -312,8 +312,12 @@ o/cosmopolitan.h: \ $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) @ACTION=ROLLUP TARGET=$@ build/do $^ >$@ -o/cosmopolitan.html: o/$(MODE)/third_party/chibicc/chibicc.com.dbg - o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J -fno-common -include libc/integral/normalize.inc -o $@ $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) +o/cosmopolitan.html: \ + o/$(MODE)/third_party/chibicc/chibicc.com.dbg \ + $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) + o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \ + -fno-common -include libc/integral/normalize.inc -o $@ \ + $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) # UNSPECIFIED PREREQUISITES TUTORIAL # diff --git a/examples/examples.mk b/examples/examples.mk index 5a51e2cd..4ca27f10 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -54,6 +54,7 @@ EXAMPLES_DIRECTDEPS = \ LIBC_NT_KERNELBASE \ LIBC_NT_NTDLL \ LIBC_NT_USER32 \ + LIBC_NT_WS2_32 \ LIBC_OHMYPLUS \ LIBC_RAND \ LIBC_RUNTIME \ diff --git a/examples/fld.c b/examples/fld.c deleted file mode 100644 index f18c1452..00000000 --- a/examples/fld.c +++ /dev/null @@ -1,120 +0,0 @@ -#if 0 -/*─────────────────────────────────────────────────────────────────╗ -│ To the extent possible under law, Justine Tunney has waived │ -│ all copyright and related or neighboring rights to this file, │ -│ as it is written in the following disclaimers: │ -│ • http://unlicense.org/ │ -│ • http://creativecommons.org/publicdomain/zero/1.0/ │ -╚─────────────────────────────────────────────────────────────────*/ -#endif -#include "libc/bits/bits.h" -#include "libc/inttypes.h" -#include "libc/literal.h" -#include "libc/math.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" - -static const char kHeaderBin[] = "\ -/\t┌sign\n\ -/\t│ ┌exponent\n\ -/\t│ │ ┌intpart\n\ -/\t│ │ │ ┌fraction\n\ -/\t│ │ │ │\n\ -/\t│┌┴────────────┐│┌┴────────────────────────────────────────────────────────────┐\n"; - -static const char kHeaderHex[] = "\ -/\t ┌sign/exponent\n\ -/\t │ ┌intpart/fraction\n\ -/\t │ │\n\ -/\t┌┴─┐┌┴─────────────┐\n"; - -void dobin(const char *op, long double x, FILE *f) { - uint16_t hi; - uint64_t lo; - uint8_t buf[16]; - memcpy(buf, &x, sizeof(x)); - memcpy(&lo, &buf[0], sizeof(lo)); - memcpy(&hi, &buf[8], sizeof(hi)); - fprintf(f, "/\t%016" PRIb16 "%064" PRIb64 " %-8s % 17.14Lf\n", hi, lo, op, x); -} - -void dohex(const char *op, long double x, FILE *f) { - uint16_t hi; - uint64_t lo; - uint8_t buf[16]; - memcpy(buf, &x, sizeof(x)); - memcpy(&lo, &buf[0], sizeof(lo)); - memcpy(&hi, &buf[8], sizeof(hi)); - fprintf(f, "/\t%04" PRIx16 "%016" PRIx64 " %-8s % 17.14Lf\n", hi, lo, op, x); -} - -#define DOBIN(OP) \ - dobin(" " #OP, OP(), stdout); \ - dobin("-" #OP, -OP(), stdout) - -#define DOHEX(OP) \ - dohex(" " #OP, OP(), stdout); \ - dohex("-" #OP, -OP(), stdout) - -int main(int argc, char *argv[]) { - fputs(kHeaderBin, stdout); - DOBIN(fldz); - DOBIN(fld1); - DOBIN(fldpi); - DOBIN(fldl2t); - DOBIN(fldlg2); - DOBIN(fldln2); - DOBIN(fldl2e); - fputc('\n', stdout); - fputs(kHeaderHex, stdout); - DOHEX(fldz); - DOHEX(fld1); - DOHEX(fldpi); - DOHEX(fldl2t); - DOHEX(fldlg2); - DOHEX(fldln2); - DOHEX(fldl2e); - return 0; -} - -// clang-format off -// -// ┌sign -// │ ┌exponent -// │ │ ┌intpart -// │ │ │ ┌fraction -// │ │ │ │ -// │┌┴────────────┐│┌┴────────────────────────────────────────────────────────────┐ -// 00000000000000000000000000000000000000000000000000000000000000000000000000000000 fldz 0.0000000000000000000 -// 10000000000000000000000000000000000000000000000000000000000000000000000000000000 -fldz -0.0000000000000000000 -// 00111111111111111000000000000000000000000000000000000000000000000000000000000000 fld1 1.0000000000000000000 -// 10111111111111111000000000000000000000000000000000000000000000000000000000000000 -fld1 -1.0000000000000000000 -// 01000000000000001100100100001111110110101010001000100001011010001100001000110101 fldpi 3.1415926540000000000 -// 11000000000000001100100100001111110110101010001000100001011010001100001000110101 -fldpi -3.1415926540000000000 -// 01000000000000001101010010011010011110000100101111001101000110111000101011111110 fldl2t 3.3219280950000000000 -// 11000000000000001101010010011010011110000100101111001101000110111000101011111110 -fldl2t -3.3219280950000000000 -// 00111111111111011001101000100000100110101000010011111011110011111111011110011001 fldlg2 0.3010299960000000000 -// 10111111111111011001101000100000100110101000010011111011110011111111011110011001 -fldlg2 -0.3010299960000000000 -// 00111111111111101011000101110010000101111111011111010001110011110111100110101100 fldln2 0.6931471810000000000 -// 10111111111111101011000101110010000101111111011111010001110011110111100110101100 -fldln2 -0.6931471810000000000 -// 00111111111111111011100010101010001110110010100101011100000101111111000010111100 fldl2e 1.4426950410000000000 -// 10111111111111111011100010101010001110110010100101011100000101111111000010111100 -fldl2e -1.4426950410000000000 -// -// ┌sign/exponent -// │ ┌intpart/fraction -// │ │ -// ┌┴─┐┌┴─────────────┐ -// 00000000000000000000 fldz 0.0000000000000000000 -// 80000000000000000000 -fldz -0.0000000000000000000 -// 3fff8000000000000000 fld1 1.0000000000000000000 -// bfff8000000000000000 -fld1 -1.0000000000000000000 -// 4000c90fdaa22168c235 fldpi 3.1415926540000000000 -// c000c90fdaa22168c235 -fldpi -3.1415926540000000000 -// 4000d49a784bcd1b8afe fldl2t 3.3219280950000000000 -// c000d49a784bcd1b8afe -fldl2t -3.3219280950000000000 -// 3ffd9a209a84fbcff799 fldlg2 0.3010299960000000000 -// bffd9a209a84fbcff799 -fldlg2 -0.3010299960000000000 -// 3ffeb17217f7d1cf79ac fldln2 0.6931471810000000000 -// bffeb17217f7d1cf79ac -fldln2 -0.6931471810000000000 -// 3fffb8aa3b295c17f0bc fldl2e 1.4426950410000000000 -// bfffb8aa3b295c17f0bc -fldl2e -1.4426950410000000000 diff --git a/libc/bits/xmmintrin.internal.h b/libc/bits/xmmintrin.internal.h index 8d7c9d08..b5e073c6 100644 --- a/libc/bits/xmmintrin.internal.h +++ b/libc/bits/xmmintrin.internal.h @@ -98,25 +98,37 @@ typedef float __m128_u _Vector_size(16) forcealign(1) mayalias; │ cosmopolitan § it's a trap! » sse » scalar ops ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -forceinline __m128 _mm_add_ss(__m128 m128_0, __m128 m128_1) { - m128_0[0] += m128_1[0]; - return m128_0; -} +#define _mm_add_ss(m128_0, m128_1) \ + ({ \ + __m128 a = m128_0; \ + __m128 b = m128_0; \ + a[0] += b[0]; \ + a; \ + }) -forceinline __m128 _mm_sub_ss(__m128 m128_0, __m128 m128_1) { - m128_0[0] -= m128_1[0]; - return m128_0; -} +#define _mm_sub_ss(m128_0, m128_1) \ + ({ \ + __m128 a = m128_0; \ + __m128 b = m128_0; \ + a[0] -= b[0]; \ + a; \ + }) -forceinline __m128 _mm_mul_ss(__m128 m128_0, __m128 m128_1) { - m128_0[0] *= m128_1[0]; - return m128_0; -} +#define _mm_mul_ss(m128_0, m128_1) \ + ({ \ + __m128 a = m128_0; \ + __m128 b = m128_0; \ + a[0] *= b[0]; \ + a; \ + }) -forceinline __m128 _mm_div_ss(__m128 m128_0, __m128 m128_1) { - m128_0[0] /= m128_1[0]; - return m128_0; -} +#define _mm_div_ss(m128_0, m128_1) \ + ({ \ + __m128 a = m128_0; \ + __m128 b = m128_0; \ + a[0] /= b[0]; \ + a; \ + }) #define _mm_rcp_ss(M128) __builtin_ia32_rcpss((__v4sf)(M128)) /*~1/x*/ #define _mm_sqrt_ss(M128) __builtin_ia32_sqrtss((__v4sf)(M128)) /*sqrt𝑥*/ diff --git a/libc/integral/lp64arg.inc b/libc/integral/lp64arg.inc index ece9f466..669ec7c0 100644 --- a/libc/integral/lp64arg.inc +++ b/libc/integral/lp64arg.inc @@ -5,13 +5,13 @@ #define va_end(AP) #define va_copy(DST, SRC) ((DST)[0] = (SRC)[0]) -#define va_start(AP, LAST) \ - do { \ - *(AP) = *(struct __va *)__va_area__; \ +#define va_start(AP, LAST) \ + do { \ + *(AP) = *(struct __va_list *)__va_area__; \ } while (0) #define va_arg(AP, TYPE) \ (*(TYPE *)__va_arg(AP, sizeof(TYPE), _Alignof(TYPE), \ __builtin_reg_class(TYPE))) -typedef struct __va va_list[1]; +typedef struct __va_list va_list[1]; diff --git a/libc/log/vflogf.c b/libc/log/vflogf.c index db1f9345..19824ee3 100644 --- a/libc/log/vflogf.c +++ b/libc/log/vflogf.c @@ -73,7 +73,7 @@ void vflogf_onfail(FILE *f) { fseek(f, SEEK_SET, 0); f->beg = f->end = 0; clearerr(f); - (fprintf)(f, "performed emergency log truncation: %s\r\n", strerror(err)); + (fprintf)(f, "performed emergency log truncation: %s\n", strerror(err)); } } @@ -112,10 +112,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, } (vfprintf)(f, fmt, va); va_end(va); - fputs("\r\n", f); + fputs("\n", f); if (level == kLogFatal) { __start_fatal(file, line); - (dprintf)(STDERR_FILENO, "fatal error see logfile\r\n"); + (dprintf)(STDERR_FILENO, "fatal error see logfile\n"); __die(); unreachable; } diff --git a/libc/math.h b/libc/math.h index f17ad172..a1e6396f 100644 --- a/libc/math.h +++ b/libc/math.h @@ -285,28 +285,6 @@ void sincos(double, double *, double *); void sincosf(float, float *, float *); void sincosl(long double, long double *, long double *); -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § mathematics » x87 ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#define fldz() __X87_CONST(fldz, 0x0p+0) -#define fld1() __X87_CONST(fld1, 0x8p-3) -#define fldpi() __X87_CONST(fldpi, M_PI) -#define fldl2t() __X87_CONST(fldl2t, M_LOG2_10) -#define fldlg2() __X87_CONST(fldlg2, M_LOG10_2) -#define fldln2() __X87_CONST(fldln2, M_LN2) -#define fldl2e() __X87_CONST(fldl2e, M_LOG2E) -#ifdef __x86__ -#define __X87_CONST(OP, VALUE) \ - ({ \ - long double St0##OP; \ - asm(#OP : "=t"(St0##OP)); \ - St0##OP; \ - }) -#else -#define __X87_CONST(OP, VALUE) VALUE -#endif - COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_MATH_H_ */ diff --git a/libc/nexgen32e/bsrmax.S b/libc/nexgen32e/bsrmax.S index be493e34..3d22aaa8 100644 --- a/libc/nexgen32e/bsrmax.S +++ b/libc/nexgen32e/bsrmax.S @@ -21,15 +21,15 @@ / Returns binary logarithm of integer 𝑥. / -/ 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 +/ 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 / / @param rsi:rdi is 128-bit unsigned 𝑥 value / @return eax number in range [0,128) or undef if 𝑥 is 0 diff --git a/libc/nt/winsock.h b/libc/nt/winsock.h index 2d92713b..5cad3bc9 100644 --- a/libc/nt/winsock.h +++ b/libc/nt/winsock.h @@ -409,7 +409,7 @@ int WSARecvFrom(uint64_t s, const struct NtIovec *out_lpBuffers, uint32_t *inout_fromsockaddrlen, struct NtOverlapped *opt_inout_lpOverlapped, const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine) - paramsnonnull((2, 5, 6, 7)); + paramsnonnull((2, 5)); int WSARecvDisconnect(uint64_t s, const struct NtIovec *opt_lpInboundDisconnectData); diff --git a/libc/runtime/valist.c b/libc/runtime/valist.c index 18d924b4..8a84c20a 100644 --- a/libc/runtime/valist.c +++ b/libc/runtime/valist.c @@ -20,13 +20,13 @@ #include "libc/macros.h" #include "libc/runtime/valist.h" -static void *__va_arg_mem(struct __va *ap, size_t sz, size_t align) { +static void *__va_arg_mem(struct __va_list *ap, size_t sz, size_t align) { void *r = (void *)ROUNDUP((intptr_t)ap->overflow_arg_area, align); ap->overflow_arg_area = (void *)ROUNDUP((intptr_t)r + sz, 8); return r; } -void *__va_arg(struct __va *ap, size_t sz, unsigned align, unsigned k) { +void *__va_arg(struct __va_list *ap, size_t sz, unsigned align, unsigned k) { void *r; switch (k) { case 0: diff --git a/libc/runtime/valist.h b/libc/runtime/valist.h index def8a2dd..73ae2cc2 100644 --- a/libc/runtime/valist.h +++ b/libc/runtime/valist.h @@ -3,14 +3,14 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -struct __va { +struct __va_list { uint32_t gp_offset; uint32_t fp_offset; void *overflow_arg_area; void *reg_save_area; }; -void *__va_arg(struct __va *, size_t, unsigned, unsigned); +void *__va_arg(struct __va_list *, size_t, unsigned, unsigned); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index b4c58e5d..99136b5e 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -27,6 +27,8 @@ #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" +#include "libc/x/x.h" +#include "third_party/chibicc/file.h" #include "third_party/gdtoa/gdtoa.h" #include "tool/build/lib/elfwriter.h" @@ -443,49 +445,6 @@ static unsigned Hash(const void *p, unsigned long n) { return MAX(1, h); } -static bool StartsWith(const char *s, const char *prefix) { - for (;;) { - if (!*prefix) return true; - if (!*s) return false; - if (*s++ != *prefix++) return false; - } -} - -static bool EndsWith(const char *s, const char *suffix) { - size_t n, m; - n = strlen(s); - m = strlen(suffix); - if (m > n) return false; - return !memcmp(s + n - m, suffix, m); -} - -static char *Format(const char *fmt, ...) { - char *res; - va_list va; - va_start(va, fmt); - vasprintf(&res, fmt, va); - va_end(va); - return res; -} - -static char *DirName(const char *path) { - return dirname(strdup(path)); -} - -static char *JoinPaths(const char *path, const char *other) { - if (!*other) { - return strdup(path); - } else if (!*path) { - return strdup(other); - } else if (StartsWith(other, "/") || !strcmp(path, ".")) { - return strdup(other); - } else if (EndsWith(path, "/")) { - return Format("%s%s", path, other); - } else { - return Format("%s/%s", path, other); - } -} - static bool IsPunctMergeable(int c) { switch (c) { case ';': @@ -613,11 +572,11 @@ static void ReadFlags(struct As *a, int argc, char *argv[]) { for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-o")) { a->outpath = StrDup(a, argv[++i]); - } else if (StartsWith(argv[i], "-o")) { + } else if (startswith(argv[i], "-o")) { a->outpath = StrDup(a, argv[i] + 2); } else if (!strcmp(argv[i], "-I")) { SaveString(&a->incpaths, strdup(argv[++i])); - } else if (StartsWith(argv[i], "-I")) { + } else if (startswith(argv[i], "-I")) { SaveString(&a->incpaths, strdup(argv[i] + 2)); } else if (!strcmp(argv[i], "-Z")) { a->inhibiterr = true; @@ -677,72 +636,6 @@ static int ReadCharLiteral(struct Slice *buf, int c, char *p, int *i) { } } -static void CanonicalizeNewline(char *p) { - int i = 0, j = 0; - while (p[i]) { - if (p[i] == '\r' && p[i + 1] == '\n') { - i += 2; - p[j++] = '\n'; - } else if (p[i] == '\r') { - i++; - p[j++] = '\n'; - } else { - p[j++] = p[i++]; - } - } - p[j] = '\0'; -} - -static void RemoveBackslashNewline(char *p) { - int i, j, n; - for (i = j = n = 0; p[i];) { - if (p[i] == '\\' && p[i + 1] == '\n') { - i += 2; - n++; - } else if (p[i] == '\n') { - p[j++] = p[i++]; - for (; n > 0; n--) p[j++] = '\n'; - } else { - p[j++] = p[i++]; - } - } - for (; n > 0; n--) p[j++] = '\n'; - p[j] = '\0'; -} - -static char *ReadFile(const char *path) { - char *p; - FILE *fp; - int buflen, nread, end, n; - if (!strcmp(path, "-")) { - fp = stdin; - } else { - fp = fopen(path, "r"); - if (!fp) return NULL; - } - buflen = 4096; - nread = 0; - p = calloc(1, buflen); - for (;;) { - end = buflen - 2; - n = fread(p + nread, 1, end - nread, fp); - if (n == 0) break; - nread += n; - if (nread == end) { - buflen *= 2; - p = realloc(p, buflen); - } - } - if (fp != stdin) fclose(fp); - if (nread > 0 && p[nread - 1] == '\\') { - p[nread - 1] = '\n'; - } else if (nread == 0 || p[nread - 1] != '\n') { - p[nread++] = '\n'; - } - p[nread] = '\0'; - return p; -} - static void PrintLocation(struct As *a) { fprintf(stderr, "%s:%d:: ", a->strings.p[a->sauces.p[a->things.p[a->i].s].path], @@ -768,7 +661,7 @@ static char *FindInclude(struct As *a, const char *file) { char *path; struct stat st; for (i = 0; i < a->incpaths.n; ++i) { - path = JoinPaths(a->incpaths.p[i], file); + path = xjoinpaths(a->incpaths.p[i], file); if (stat(path, &st) != -1 && S_ISREG(st.st_mode)) return path; free(path); } @@ -780,10 +673,10 @@ static void Tokenize(struct As *a, int path) { char *p, *path2; struct Slice buf; bool bol, isfloat, isfpu; - p = SaveString(&a->strings, ReadFile(a->strings.p[path])); - if (!memcmp(p, "\357\273\277", 3)) p += 3; - CanonicalizeNewline(p); - RemoveBackslashNewline(p); + p = SaveString(&a->strings, read_file(a->strings.p[path])); + p = skip_bom(p); + canonicalize_newline(p); + remove_backslash_newline(p); line = 1; bol = true; while ((c = *p)) { @@ -1031,7 +924,7 @@ static void OnSymbol(struct As *a, int name) { static void OnLocalLabel(struct As *a, int id) { int i; char *name; - name = Format(".Label.%d", a->counter++); + name = xasprintf(".Label.%d", a->counter++); SaveString(&a->strings, name); AppendSlice(a); a->slices.p[a->slices.n - 1].p = name; @@ -1796,13 +1689,13 @@ static int GrabSection(struct As *a, int name, int flags, int type) { static void OnSection(struct As *a, struct Slice s) { int name, flags, type; name = SliceDup(a, GetSlice(a)); - if (StartsWith(a->strings.p[name], ".text")) { + if (startswith(a->strings.p[name], ".text")) { flags = SHF_ALLOC | SHF_EXECINSTR; type = SHT_PROGBITS; - } else if (StartsWith(a->strings.p[name], ".data")) { + } else if (startswith(a->strings.p[name], ".data")) { flags = SHF_ALLOC | SHF_WRITE; type = SHT_PROGBITS; - } else if (StartsWith(a->strings.p[name], ".bss")) { + } else if (startswith(a->strings.p[name], ".bss")) { flags = SHF_ALLOC | SHF_WRITE; type = SHT_NOBITS; } else { @@ -2372,7 +2265,7 @@ static noinline void OpBsu(struct As *a, struct Slice opname, int op) { OpBsuImpl(a, opname, op); } -static int OpF6(struct As *a, struct Slice s, int reg) { +static noinline int OpF6Impl(struct As *a, struct Slice s, int reg) { int modrm, imm, disp; modrm = ParseModrm(a, &disp); reg |= GetOpSize(a, s, modrm, 1) << 3; @@ -2380,6 +2273,10 @@ static int OpF6(struct As *a, struct Slice s, int reg) { return reg; } +static noinline int OpF6(struct As *a, struct Slice s, int reg) { + return OpF6Impl(a, s, reg); +} + static void OnTest(struct As *a, struct Slice s) { int reg, modrm, imm, disp; if (IsPunct(a, a->i, '$')) { @@ -2571,8 +2468,8 @@ static bool HasXmmOnLine(struct As *a) { int i; for (i = 0; !IsPunct(a, a->i + i, ';'); ++i) { if (IsSlice(a, a->i + i) && a->slices.p[a->things.p[a->i + i].i].n >= 4 && - (StartsWith(a->slices.p[a->things.p[a->i + i].i].p, "xmm") || - StartsWith(a->slices.p[a->things.p[a->i + i].i].p, "%xmm"))) { + (startswith(a->slices.p[a->things.p[a->i + i].i].p, "xmm") || + startswith(a->slices.p[a->things.p[a->i + i].i].p, "%xmm"))) { return true; } } @@ -4002,7 +3899,7 @@ void Assembler(int argc, char *argv[]) { a = NewAssembler(); ReadFlags(a, argc, argv); SaveString(&a->incpaths, strdup(".")); - SaveString(&a->incpaths, DirName(a->strings.p[a->inpath])); + SaveString(&a->incpaths, xdirname(a->strings.p[a->inpath])); Tokenize(a, a->inpath); /* PrintThings(a); */ Assemble(a); diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index d9beb355..cfeb24cd 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -130,9 +130,6 @@ Token *tokenize_string_literal(Token *, Type *); bool consume(Token **, Token *, char *, size_t); bool equal(Token *, char *, size_t); void convert_pp_tokens(Token *); -void remove_backslash_newline(char *); -void canonicalize_newline(char *); -char *read_file(char *); int read_escaped_char(char **, char *); #define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__) @@ -450,6 +447,7 @@ struct Type { int align; // alignment bool is_unsigned; // unsigned or signed bool is_atomic; // true if _Atomic + bool is_const; // const bool is_ms_abi; // microsoft abi Type *origin; // for type compatibility check // Pointer-to or array-of type. We intentionally use the same member diff --git a/third_party/chibicc/dox1.c b/third_party/chibicc/dox1.c index ffefad3a..89b91f9b 100644 --- a/third_party/chibicc/dox1.c +++ b/third_party/chibicc/dox1.c @@ -79,7 +79,8 @@ static void SerializeJavadown(struct Buffer *buf, struct Javadown *jd) { } static char *DescribeScalar(struct Type *ty, char *name) { - return xasprintf("%s%s%s", ty->is_atomic ? "_Atomic " : "", + return xasprintf("%s%s%s%s", ty->is_atomic ? "_Atomic " : "", + ty->is_const ? "const " : "", ty->is_unsigned ? "unsigned " : "", name); } @@ -134,7 +135,7 @@ static char *DescribeType(struct Type *ty) { return strdup("ANONYMOUS-UNION"); } default: - return "UNKNOWN"; + return strdup("UNKNOWN"); } } @@ -178,6 +179,7 @@ static void SerializeDox(struct DoxWriter *dox, Obj *prog) { 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]->ty->is_variadic); 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); @@ -248,6 +250,7 @@ static void SerializeAsmdown(struct DoxWriter *dox, struct Asmdown *ad, SerializeStr(&dox->buf, filename); SerializeInt(&dox->buf, ad->symbols.p[i].line); SerializeInt(&dox->buf, true); // TODO: is_function + SerializeInt(&dox->buf, false); // is_variadic SerializeInt(&dox->buf, false); // TODO: is_weak SerializeInt(&dox->buf, false); // is_inline SerializeInt(&dox->buf, false); // is_noreturn diff --git a/third_party/chibicc/dox2.c b/third_party/chibicc/dox2.c index 58816977..64863c0d 100644 --- a/third_party/chibicc/dox2.c +++ b/third_party/chibicc/dox2.c @@ -47,6 +47,7 @@ struct Dox { char *path; int line; bool is_function; + bool is_variadic; bool is_weak; bool is_inline; bool is_noreturn; @@ -177,6 +178,7 @@ static void DeserializeObject(struct Dox *dox, struct DoxObject *o) { o->path = DeserializeStr(dox); o->line = DeserializeInt(dox); o->is_function = DeserializeInt(dox); + o->is_variadic = DeserializeInt(dox); o->is_weak = DeserializeInt(dox); o->is_inline = DeserializeInt(dox); o->is_noreturn = DeserializeInt(dox); @@ -210,7 +212,7 @@ static void DeserializeMacro(struct Dox *dox, struct DoxMacro *m) { } } -static void DeserializeDox(struct Dox *dox) { +static void DeserializeDox(struct Dox *dox, const char *path) { int i, j, n; i = dox->objects.n; n = DeserializeInt(dox); @@ -242,7 +244,7 @@ static void ReadDox(struct Dox *dox, const StringArray *files) { CHECK_NE(MAP_FAILED, (map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))); dox->p = map; - DeserializeDox(dox); + DeserializeDox(dox, files->data[i]); munmap(map, st.st_size); } close(fd); @@ -317,15 +319,19 @@ static void IndexDox(struct Dox *dox) { CompareDoxIndexEntry, dox); } +/** + * Escapes HTML entities and interprets basic Markdown syntax. + */ static void PrintText(FILE *f, const char *s) { int c; - bool bol, pre, ul0, ul2, bt1, bt2; - for (bt1 = bt2 = ul2 = ul0 = pre = false, bol = true;;) { + bool bol, pre, ul0, ul2, ol0, ol2, bt1, bt2; + for (bt1 = bt2 = ul2 = ul0 = ol2 = ol0 = pre = false, bol = true;;) { switch ((c = *s++)) { case '\0': if (bt1 || bt2) fprintf(f, ""); if (pre) fprintf(f, ""); if (ul0 || ul2) fprintf(f, ""); + if (ol0 || ol2) fprintf(f, ""); return; case '&': fprintf(f, "&"); @@ -368,14 +374,19 @@ static void PrintText(FILE *f, const char *s) { bol = false; break; case '\n': - if (!pre && !ul0 && !ul2 && *s == '\n') { + if (!pre && !ul0 && !ul2 && !ol0 && !ol2 && *s == '\n') { fprintf(f, "\n
"); bol = true; - } else if (pre && s[0] != '\n' && - (s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) { - fprintf(f, "\n"); - pre = false; - bol = true; + } else if (pre && s[0] != '\n') { + if (s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ') { + fprintf(f, "\n"); + pre = false; + bol = true; + } else { + fprintf(f, "\n"); + bol = false; + s += 4; + } } else if (ul0 && s[0] == '-' && s[1] == ' ') { fprintf(f, "\n
"); - } else if (bol && !ul0 && !ul2 && s[0] == ' ' && s[1] == '-' && - s[2] == ' ') { + fprintf(f, ""); + s += 3; + } else if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ' && + s[1] == '-' && s[2] == ' ') { ul2 = true; fprintf(f, "
\n\ + | \n\ "); /* // lefthand index: objects */ @@ -581,7 +634,7 @@ static void PrintDox(struct Dox *dox, FILE *f) { } // righthand contents - fprintf(f, " | \n"); + fprintf(f, " | \n");
for (i = 0; i < dox->index.n; ++i) {
if (dox->index.p[i].t == kObject) {
o = dox->objects.p + dox->index.p[i].i;
@@ -606,7 +659,8 @@ static void PrintDox(struct Dox *dox, FILE *f) {
}
// parameters
- if (o->is_function && (o->params.n || HasTag(o->javadown, "param"))) {
+ if (o->is_function &&
+ (o->is_variadic || o->params.n || HasTag(o->javadown, "param"))) {
fprintf(f, " \n");
fprintf(f, "@param\n");
fprintf(f, " \n"); // .tag
}
@@ -676,6 +733,17 @@ static void PrintDox(struct Dox *dox, FILE *f) {
}
}
+ // type
+ if (!o->is_function) {
+ fprintf(f, "
\n");
+ fprintf(f, "@type\n");
+ fprintf(f, " \n"); // .tag
+ }
+
// tags
if (o->javadown) {
for (k = 0; k < o->javadown->tags.n; ++k) {
@@ -714,21 +782,18 @@ static void PrintDox(struct Dox *dox, FILE *f) {
if (i) fprintf(f, "
"); fprintf(f, " \n", m->name);
fprintf(f, " \n"); /* class=".api" */
}
}
diff --git a/third_party/chibicc/file.c b/third_party/chibicc/file.c
new file mode 100644
index 00000000..0ed48ba2
--- /dev/null
+++ b/third_party/chibicc/file.c
@@ -0,0 +1,106 @@
+#include "third_party/chibicc/chibicc.h"
+
+// Slurps contents of file.
+char *read_file(const char *path) {
+ char *p;
+ FILE *fp;
+ int buflen, nread, end, n;
+ if (!strcmp(path, "-")) {
+ fp = stdin;
+ } else {
+ fp = fopen(path, "r");
+ if (!fp) return NULL;
+ }
+ buflen = 4096;
+ nread = 0;
+ p = calloc(1, buflen);
+ for (;;) {
+ end = buflen - 2;
+ n = fread(p + nread, 1, end - nread, fp);
+ if (n == 0) break;
+ nread += n;
+ if (nread == end) {
+ buflen *= 2;
+ p = realloc(p, buflen);
+ }
+ }
+ if (fp != stdin) fclose(fp);
+ if (nread > 0 && p[nread - 1] == '\\') {
+ p[nread - 1] = '\n';
+ } else if (nread == 0 || p[nread - 1] != '\n') {
+ p[nread++] = '\n';
+ }
+ p[nread] = '\0';
+ return p;
+}
+
+char *skip_bom(char *p) {
+ // UTF-8 texts may start with a 3-byte "BOM" marker sequence.
+ // If exists, just skip them because they are useless bytes.
+ // (It is actually not recommended to add BOM markers to UTF-8
+ // texts, but it's not uncommon particularly on Windows.)
+ if (!memcmp(p, "\357\273\277", 3)) p += 3;
+ return p;
+}
+
+// Replaces \r or \r\n with \n.
+void canonicalize_newline(char *p) {
+ int i = 0, j = 0;
+ while (p[i]) {
+ if (p[i] == '\r' && p[i + 1] == '\n') {
+ i += 2;
+ p[j++] = '\n';
+ } else if (p[i] == '\r') {
+ i++;
+ p[j++] = '\n';
+ } else {
+ p[j++] = p[i++];
+ }
+ }
+ p[j] = '\0';
+}
+
+// Removes backslashes followed by a newline.
+void remove_backslash_newline(char *p) {
+ int i = 0, j = 0;
+ // We want to keep the number of newline characters so that
+ // 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++;
+ } else if (p[i] == '\n') {
+ p[j++] = p[i++];
+ for (; n > 0; n--) p[j++] = '\n';
+ } else {
+ p[j++] = p[i++];
+ }
+ }
+ for (; n > 0; n--) p[j++] = '\n';
+ p[j] = '\0';
+}
diff --git a/third_party/chibicc/file.h b/third_party/chibicc/file.h
new file mode 100644
index 00000000..4a449dd9
--- /dev/null
+++ b/third_party/chibicc/file.h
@@ -0,0 +1,13 @@
+#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_FILE_H_
+#define COSMOPOLITAN_THIRD_PARTY_CHIBICC_FILE_H_
+#if !(__ASSEMBLER__ + __LINKER__ + 0)
+COSMOPOLITAN_C_START_
+
+char *skip_bom(char *);
+char *read_file(const char *);
+void remove_backslash_newline(char *);
+void canonicalize_newline(char *);
+
+COSMOPOLITAN_C_END_
+#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
+#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_FILE_H_ */
diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c
index 006db9b8..6609ce53 100644
--- a/third_party/chibicc/parse.c
+++ b/third_party/chibicc/parse.c
@@ -48,7 +48,6 @@ typedef struct {
bool is_static;
bool is_extern;
bool is_inline;
- bool is_const;
bool is_tls;
bool is_weak;
bool is_ms_abi;
@@ -233,6 +232,8 @@ static Node *new_ulong(long val, Token *tok) {
}
static Node *new_var_node(Obj *var, Token *tok) {
+ if (!var) DebugBreak();
+ CHECK_NOTNULL(var);
Node *node = new_node(ND_VAR, tok);
node->var = var;
return node;
@@ -647,6 +648,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
};
Type *ty = copy_type(ty_int);
int counter = 0;
+ bool is_const = false;
bool is_atomic = false;
while (is_typename(tok)) {
// Handle storage class specifiers.
@@ -682,7 +684,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
goto Continue;
}
if (CONSUME(&tok, tok, "const")) {
- if (attr) attr->is_const = true;
+ is_const = true;
goto Continue;
}
// These keywords are recognized but ignored.
@@ -841,6 +843,10 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
ty = copy_type(ty);
ty->is_atomic = true;
}
+ /* if (attr && is_const) { */
+ /* ty = copy_type(ty); */
+ /* ty->is_const = true; */
+ /* } */
*rest = tok;
return ty;
}
@@ -873,6 +879,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
Type head = {};
Type *cur = &head;
bool is_variadic = false;
+ enter_scope();
while (!EQUAL(tok, ")")) {
if (cur != &head) tok = skip(tok, ',');
if (EQUAL(tok, "...")) {
@@ -884,6 +891,9 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
Type *ty2 = declspec(&tok, tok, NULL);
ty2 = declarator(&tok, tok, ty2);
Token *name = ty2->name;
+ if (name) {
+ new_lvar(strndup(name->loc, name->len), ty2);
+ }
if (ty2->kind == TY_ARRAY) {
// "array of T" is converted to "pointer to T" only in the parameter
// context. For example, *argv[] is converted to **argv by this.
@@ -897,6 +907,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
}
cur = cur->next = copy_type(ty2);
}
+ leave_scope();
if (cur == &head) is_variadic = true;
ty = func_type(ty);
ty->params = head.next;
@@ -2471,6 +2482,16 @@ static Node *shift(Token **rest, Token *tok) {
}
}
+static Node *get_vla_size(Type *ty, Token *tok) {
+ if (ty->vla_size) {
+ return new_var_node(ty->vla_size, tok);
+ } else {
+ Node *lhs = compute_vla_size(ty, tok);
+ Node *rhs = new_var_node(ty->vla_size, tok);
+ return new_binary(ND_COMMA, lhs, rhs, tok);
+ }
+}
+
// In C, `+` operator is overloaded to perform the pointer arithmetic.
// If p is a pointer, p+n adds not n but sizeof(*p)*n to the value of p,
// so that p+n points to the location n elements (not bytes) ahead of p.
@@ -2491,8 +2512,7 @@ static Node *new_add(Node *lhs, Node *rhs, Token *tok) {
}
// VLA + num
if (lhs->ty->base->kind == TY_VLA) {
- rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok),
- tok);
+ rhs = new_binary(ND_MUL, rhs, get_vla_size(lhs->ty->base, tok), tok);
return new_binary(ND_ADD, lhs, rhs, tok);
}
// ptr + num
@@ -2509,8 +2529,7 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) {
return new_binary(ND_SUB, lhs, rhs, tok);
// VLA + num
if (lhs->ty->base->kind == TY_VLA) {
- rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok),
- tok);
+ rhs = new_binary(ND_MUL, rhs, get_vla_size(lhs->ty->base, tok), tok);
add_type(rhs);
Node *node = new_binary(ND_SUB, lhs, rhs, tok);
node->ty = lhs->ty;
@@ -3044,7 +3063,9 @@ static Node *primary(Token **rest, Token *tok) {
if (EQUAL(tok, "sizeof")) {
Node *node = unary(rest, tok->next);
add_type(node);
- if (node->ty->kind == TY_VLA) return new_var_node(node->ty->vla_size, tok);
+ if (node->ty->kind == TY_VLA) {
+ return get_vla_size(node->ty, tok);
+ }
return new_ulong(node->ty->size, tok);
}
if ((EQUAL(tok, "_Alignof") || EQUAL(tok, "__alignof__")) &&
@@ -3416,8 +3437,9 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) {
fn->is_no_instrument_function |= attr->is_no_instrument_function;
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->javadown = fn->javadown ?: current_javadown;
fn->is_root = !(fn->is_static && fn->is_inline);
+ fn->javadown = fn->javadown ?: current_javadown;
+ current_javadown = NULL;
if (consume_attribute(&tok, tok, "asm")) {
tok = skip(tok, '(');
fn->asmname = ConsumeStringLiteral(&tok, tok);
@@ -3526,16 +3548,20 @@ static void scan_globals(void) {
globals = head.next;
}
+static char *prefix_builtin(const char *name) {
+ return xstrcat("__builtin_", name);
+}
+
static Obj *declare0(char *name, Type *ret) {
if (!opt_no_builtin) new_gvar(name, func_type(ret));
- return new_gvar(xstrcat("__builtin_", name), func_type(ret));
+ return new_gvar(prefix_builtin(name), func_type(ret));
}
static Obj *declare1(char *name, Type *ret, Type *p1) {
Type *ty = func_type(ret);
ty->params = copy_type(p1);
if (!opt_no_builtin) new_gvar(name, ty);
- return new_gvar(xstrcat("__builtin_", name), ty);
+ return new_gvar(prefix_builtin(name), ty);
}
static Obj *declare2(char *name, Type *ret, Type *p1, Type *p2) {
@@ -3543,7 +3569,7 @@ static Obj *declare2(char *name, Type *ret, Type *p1, Type *p2) {
ty->params = copy_type(p1);
ty->params->next = copy_type(p2);
if (!opt_no_builtin) new_gvar(name, ty);
- return new_gvar(xstrcat("__builtin_", name), ty);
+ return new_gvar(prefix_builtin(name), ty);
}
static Obj *declare3(char *s, Type *r, Type *a, Type *b, Type *c) {
@@ -3552,7 +3578,7 @@ static Obj *declare3(char *s, Type *r, Type *a, Type *b, Type *c) {
ty->params->next = copy_type(b);
ty->params->next->next = copy_type(c);
if (!opt_no_builtin) new_gvar(s, ty);
- return new_gvar(xstrcat("__builtin_", s), ty);
+ return new_gvar(prefix_builtin(s), ty);
}
static void math0(char *name) {
diff --git a/third_party/chibicc/test/asm_test.c b/third_party/chibicc/test/asm_test.c
index b892c454..8521da8d 100644
--- a/third_party/chibicc/test/asm_test.c
+++ b/third_party/chibicc/test/asm_test.c
@@ -1,3 +1,4 @@
+asm(".ident\t\"hello\"");
/*-*- 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│
╞══════════════════════════════════════════════════════════════════════════════╡
diff --git a/third_party/chibicc/test/vla_test.c b/third_party/chibicc/test/vla_test.c
index 4d00cbaa..870e0477 100644
--- a/third_party/chibicc/test/vla_test.c
+++ b/third_party/chibicc/test/vla_test.c
@@ -1,7 +1,30 @@
#include "libc/macros.h"
#include "third_party/chibicc/test/test.h"
+int index1d(int xn, int p[xn], int x) {
+ return p[x];
+}
+
+int index2d(int yn, int xn, int (*p)[yn][xn], int y, int x) {
+ return (*p)[y][x];
+}
+
int main() {
+
+ ASSERT(30, ({
+ int a[5] = {00, 10, 20, 30, 40, 50};
+ index1d(5, a, 3);
+ }));
+
+ /* ASSERT(210, ({ */
+ /* int a[3][3] = { */
+ /* {000, 010, 020}, */
+ /* {100, 110, 120}, */
+ /* {200, 210, 220}, */
+ /* }; */
+ /* index2d(3, 3, a, 2, 1); */
+ /* })); */
+
ASSERT(20, ({
int n = 5;
int x[n];
diff --git a/third_party/chibicc/tokenize.c b/third_party/chibicc/tokenize.c
index f339f558..73056fcb 100644
--- a/third_party/chibicc/tokenize.c
+++ b/third_party/chibicc/tokenize.c
@@ -1,4 +1,5 @@
#include "third_party/chibicc/chibicc.h"
+#include "third_party/chibicc/file.h"
#define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, sizeof(OP) - 1))
@@ -610,40 +611,6 @@ Token *tokenize(File *file) {
return head.next;
}
-// Returns the contents of a given file.
-char *read_file(char *path) {
- FILE *fp;
- if (strcmp(path, "-") == 0) {
- // By convention, read from stdin if a given filename is "-".
- fp = stdin;
- } else {
- fp = fopen(path, "r");
- if (!fp) return NULL;
- }
- int buflen = 4096;
- int nread = 0;
- char *buf = calloc(1, buflen);
- // Read the entire file.
- for (;;) {
- int end = buflen - 2; // extra 2 bytes for the trailing "\n\0"
- int n = fread(buf + nread, 1, end - nread, fp);
- if (n == 0) break;
- nread += n;
- if (nread == end) {
- buflen *= 2;
- buf = realloc(buf, buflen);
- }
- }
- if (fp != stdin) fclose(fp);
- // Make sure that the last logical line is properly terminated with '\n'.
- if (nread > 0 && buf[nread - 1] == '\\')
- buf[nread - 1] = '\n';
- else if (nread == 0 || buf[nread - 1] != '\n')
- buf[nread++] = '\n';
- buf[nread] = '\0';
- return buf;
-}
-
File **get_input_files(void) {
return input_files;
}
@@ -657,68 +624,6 @@ File *new_file(char *name, int file_no, char *contents) {
return file;
}
-// Replaces \r or \r\n with \n.
-void canonicalize_newline(char *p) {
- int i = 0, j = 0;
- while (p[i]) {
- if (p[i] == '\r' && p[i + 1] == '\n') {
- i += 2;
- p[j++] = '\n';
- } else if (p[i] == '\r') {
- i++;
- p[j++] = '\n';
- } else {
- p[j++] = p[i++];
- }
- }
- p[j] = '\0';
-}
-
-// Removes backslashes followed by a newline.
-void remove_backslash_newline(char *p) {
- int i = 0, j = 0;
- // We want to keep the number of newline characters so that
- // 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++;
- } else if (p[i] == '\n') {
- p[j++] = p[i++];
- for (; n > 0; n--) p[j++] = '\n';
- } else {
- p[j++] = p[i++];
- }
- }
- for (; n > 0; n--) p[j++] = '\n';
- p[j] = '\0';
-}
-
static uint32_t read_universal_char(char *p, int len) {
uint32_t c = 0;
for (int i = 0; i < len; i++) {
@@ -761,11 +666,7 @@ static void convert_universal_chars(char *p) {
Token *tokenize_file(char *path) {
char *p = read_file(path);
if (!p) return NULL;
- // UTF-8 texts may start with a 3-byte "BOM" marker sequence.
- // If exists, just skip them because they are useless bytes.
- // (It is actually not recommended to add BOM markers to UTF-8
- // texts, but it's not uncommon particularly on Windows.)
- if (!memcmp(p, "\xef\xbb\xbf", 3)) p += 3;
+ p = skip_bom(p);
canonicalize_newline(p);
remove_backslash_newline(p);
convert_universal_chars(p);
diff --git a/third_party/getopt/getopt.c b/third_party/getopt/getopt.c
index 6136b48a..c6426140 100644
--- a/third_party/getopt/getopt.c
+++ b/third_party/getopt/getopt.c
@@ -1,10 +1,4 @@
-asm(".ident\t\"\\n\\n\
-getopt (BSD-3)\\n\
-Copyright 1987, 1993, 1994 The Regents of the University of California\"");
-asm(".include \"libc/disclaimer.inc\"");
-
/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
-
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
@@ -36,13 +30,16 @@ asm(".include \"libc/disclaimer.inc\"");
* @(#)getopt.c 8.3 (Berkeley) 4/27/95
* $FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.8 2007/01/09 00:28:10 imp Exp $
* $DragonFly: src/lib/libc/stdlib/getopt.c,v 1.7 2005/11/20 12:37:48 swildner
- *Exp $
*/
-
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
+asm(".ident\t\"\\n\\n\
+getopt (BSD-3)\\n\
+Copyright 1987, 1993, 1994 The Regents of the University of California\"");
+asm(".include \"libc/disclaimer.inc\"");
+
STATIC_YOINK("_init_getopt");
#define BADCH (int)'?'
@@ -50,48 +47,65 @@ STATIC_YOINK("_init_getopt");
/**
* If error message should be printed.
+ * @see getopt()
*/
int opterr;
/**
* Index into parent argv vector.
+ * @see getopt()
*/
int optind;
/**
* Character checked for validity.
+ * @see getopt()
*/
int optopt;
/**
* Reset getopt.
+ * @see getopt()
*/
int optreset;
/**
* Argument associated with option.
+ * @see getopt()
*/
char *optarg;
-/**
- * Option letter processing.
- */
-char *getopt_place;
-
+hidden char *getopt_place;
char kGetoptEmsg[1] hidden;
/**
- * Parses argc/argv argument vector.
+ * Parses argc/argv argument vector, e.g.
+ *
+ * while ((opt = getopt(argc, argv, "hvx:")) != -1) {
+ * switch (opt) {
+ * case 'x':
+ * x = atoi(optarg);
+ * break;
+ * case 'v':
+ * ++verbose;
+ * break;
+ * case 'h':
+ * PrintUsage(EXIT_SUCCESS, stdout);
+ * default:
+ * PrintUsage(EX_USAGE, stderr);
+ * }
+ * }
+ *
+ * @see optind
+ * @see optarg
*/
int getopt(int nargc, char *const nargv[], const char *ostr) {
char *oli; /* option letter list index */
-
/*
* Some programs like cvs expect optind = 0 to trigger
* a reset of getopt.
*/
if (optind == 0) optind = 1;
-
if (optreset || *getopt_place == 0) { /* update scanning pointer */
optreset = 0;
getopt_place = nargv[optind];
@@ -117,7 +131,6 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
} else {
optopt = *getopt_place++;
}
-
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*getopt_place == 0) ++optind;
@@ -127,7 +140,6 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
}
return (BADCH);
}
-
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
@@ -152,5 +164,5 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
getopt_place = kGetoptEmsg;
++optind;
}
- return (optopt); /* return option letter */
+ return optopt; /* return option letter */
}
diff --git a/third_party/getopt/getopt_long.3 b/third_party/getopt/getopt_long.3
deleted file mode 100644
index 88e0dffb..00000000
--- a/third_party/getopt/getopt_long.3
+++ /dev/null
@@ -1,444 +0,0 @@
-.\" $OpenBSD: getopt_long.3,v 1.21 2016/01/04 19:43:13 tb Exp $
-.\" $NetBSD: getopt_long.3,v 1.11 2002/10/02 10:54:19 wiz Exp $
-.\"
-.\" Copyright (c) 1988, 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
-.\"
-.Dd $Mdocdate: January 4 2016 $
-.Dt GETOPT_LONG 3
-.Os
-.Sh NAME
-.Nm getopt_long ,
-.Nm getopt_long_only
-.Nd get long options from command line argument list
-.Sh SYNOPSIS
-.In getopt.h
-.Vt extern char *optarg;
-.Vt extern int optind;
-.Vt extern int optopt;
-.Vt extern int opterr;
-.Vt extern int optreset;
-.Ft int
-.Fn getopt_long "int argc" "char * const *argv" "const char *optstring" "const struct option *longopts" "int *longindex"
-.Ft int
-.Fn getopt_long_only "int argc" "char * const *argv" "const char *optstring" "const struct option *longopts" "int *longindex"
-.Sh DESCRIPTION
-The
-.Fn getopt_long
-function is similar to
-.Xr getopt 3
-but it accepts options in two forms: words and characters.
-The
-.Fn getopt_long
-function provides a superset of the functionality of
-.Xr getopt 3 .
-.Fn getopt_long
-can be used in two ways.
-In the first way, every long option understood by the program has a
-corresponding short option, and the option structure is only used to
-translate from long options to short options.
-When used in this fashion,
-.Fn getopt_long
-behaves identically to
-.Xr getopt 3 .
-This is a good way to add long option processing to an existing program
-with the minimum of rewriting.
-.Pp
-In the second mechanism, a long option sets a flag in the
-.Fa option
-structure passed, or will store a pointer to the command line argument
-in the
-.Fa option
-structure passed to it for options that take arguments.
-Additionally, the long option's argument may be specified as a single
-argument with an equal sign, e.g.
-.Bd -literal -offset indent
-$ myprogram --myoption=somevalue
-.Ed
-.Pp
-When a long option is processed, the call to
-.Fn getopt_long
-will return 0.
-For this reason, long option processing without
-shortcuts is not backwards compatible with
-.Xr getopt 3 .
-.Pp
-It is possible to combine these methods, providing for long options
-processing with short option equivalents for some options.
-Less frequently used options would be processed as long options only.
-.Pp
-Abbreviated long option names are accepted when
-.Fn getopt_long
-processes long options if the abbreviation is unique.
-An exact match is always preferred for a defined long option.
-.Pp
-The
-.Fn getopt_long
-call requires an array to be initialized describing the long
-options.
-Each element of the array is a structure:
-.Bd -literal -offset indent
-struct option {
- char *name;
- int has_arg;
- int *flag;
- int val;
-};
-.Ed
-.Pp
-The
-.Fa name
-field should contain the option name without the leading double dash.
-.Pp
-The
-.Fa has_arg
-field should be one of:
-.Pp
-.Bl -tag -width "optional_argument" -compact -offset indent
-.It Dv no_argument
-no argument to the option is expected.
-.It Dv required_argument
-an argument to the option is required.
-.It Dv optional_argument
-an argument to the option may be presented.
-.El
-.Pp
-If
-.Fa flag
-is not
-.Dv NULL ,
-then the integer pointed to by it will be set to the value in the
-.Fa val
-field.
-If the
-.Fa flag
-field is
-.Dv NULL ,
-then the
-.Fa val
-field will be returned.
-Setting
-.Fa flag
-to
-.Dv NULL
-and setting
-.Fa val
-to the corresponding short option will make this function act just
-like
-.Xr getopt 3 .
-.Pp
-If the
-.Fa longindex
-field is not
-.Dv NULL ,
-then the integer pointed to by it will be set to the index of the long
-option relative to
-.Fa longopts .
-.Pp
-The last element of the
-.Fa longopts
-array has to be filled with zeroes.
-.Pp
-The
-.Fn getopt_long_only
-function behaves identically to
-.Fn getopt_long
-with the exception that long options may start with
-.Sq -
-in addition to
-.Sq -- .
-If an option starting with
-.Sq -
-does not match a long option but does match a single-character option,
-the single-character option is returned.
-.Sh RETURN VALUES
-If the
-.Fa flag
-field in
-.Li struct option
-is
-.Dv NULL ,
-.Fn getopt_long
-and
-.Fn getopt_long_only
-return the value specified in the
-.Fa val
-field, which is usually just the corresponding short option.
-If
-.Fa flag
-is not
-.Dv NULL ,
-these functions return 0 and store
-.Fa val
-in the location pointed to by
-.Fa flag .
-These functions return
-.Sq \&:
-if there was a missing option argument,
-.Sq \&?
-if the user specified an unknown or ambiguous option, and
-\-1 when the argument list has been exhausted.
-.Sh IMPLEMENTATION DIFFERENCES
-This section describes differences to the GNU implementation
-found in glibc-2.1.3:
-.Bl -bullet
-.It
-handling of
-.Ql -
-within the option string (not the first character):
-.Bl -tag -width "OpenBSD"
-.It GNU
-treats a
-.Ql -
-on the command line as a non-argument.
-.It OpenBSD
-a
-.Ql -
-within the option string matches a
-.Ql -
-(single dash) on the command line.
-This functionality is provided for backward compatibility with
-programs, such as
-.Xr su 1 ,
-that use
-.Ql -
-as an option flag.
-This practice is wrong, and should not be used in any current development.
-.El
-.It
-handling of
-.Ql ::
-in the option string in the presence of
-.Ev POSIXLY_CORRECT :
-.Bl -tag -width "OpenBSD"
-.It Both
-GNU and
-.Ox
-ignore
-.Ev POSIXLY_CORRECT
-here and take
-.Ql ::
-to mean the preceding option takes an optional argument.
-.El
-.It
-return value in case of missing argument if first character
-(after
-.Ql +
-or
-.Ql - )
-in the option string is not
-.Ql \&: :
-.Bl -tag -width "OpenBSD"
-.It GNU
-returns
-.Ql \&?
-.It OpenBSD
-returns
-.Ql \&:
-(since
-.Ox Ns 's
-.Xr getopt 3
-does).
-.El
-.It
-handling of
-.Ql --a
-in
-.Xr getopt 3 :
-.Bl -tag -width "OpenBSD"
-.It GNU
-parses this as option
-.Ql - ,
-option
-.Ql a .
-.It OpenBSD
-parses this as
-.Ql -- ,
-and returns \-1 (ignoring the
-.Ql a )
-(because the original
-.Fn getopt
-did.)
-.El
-.It
-setting of
-.Va optopt
-for long options with
-.Va flag
-.No non- Ns Dv NULL :
-.Bl -tag -width "OpenBSD"
-.It GNU
-sets
-.Va optopt
-to
-.Va val .
-.It OpenBSD
-sets
-.Va optopt
-to 0 (since
-.Va val
-would never be returned).
-.El
-.It
-handling of
-.Ql -W
-with
-.Ql W;
-in the option string in
-.Xr getopt 3
-(not
-.Fn getopt_long ) :
-.Bl -tag -width "OpenBSD"
-.It GNU
-causes a segmentation fault.
-.It OpenBSD
-no special handling is done;
-.Ql W;
-is interpreted as two separate options, neither of which take an argument.
-.El
-.It
-setting of
-.Va optarg
-for long options without an argument that are invoked via
-.Ql -W
-(with
-.Ql W;
-in the option string):
-.Bl -tag -width "OpenBSD"
-.It GNU
-sets
-.Va optarg
-to the option name (the argument of
-.Ql -W ) .
-.It OpenBSD
-sets
-.Va optarg
-to
-.Dv NULL
-(the argument of the long option).
-.El
-.It
-handling of
-.Ql -W
-with an argument that is not (a prefix to) a known long option
-(with
-.Ql W;
-in the option string):
-.Bl -tag -width "OpenBSD"
-.It GNU
-returns
-.Ql -W
-with
-.Va optarg
-set to the unknown option.
-.It OpenBSD
-treats this as an error (unknown option) and returns
-.Ql \&?
-with
-.Va optopt
-set to 0 and
-.Va optarg
-set to
-.Dv NULL
-(as GNU's man page documents).
-.El
-.It
-The error messages are different.
-.It
-.Ox
-does not permute the argument vector at the same points in
-the calling sequence as GNU does.
-The aspects normally used by the caller
-(ordering after \-1 is returned, value of
-.Va optind
-relative to current positions) are the same, though.
-(We do fewer variable swaps.)
-.El
-.Sh ENVIRONMENT
-.Bl -tag -width Ev
-.It Ev POSIXLY_CORRECT
-If set, option processing stops when the first non-option is found and
-a leading
-.Sq +
-in the
-.Ar optstring
-is ignored.
-.El
-.Sh EXAMPLES
-.Bd -literal
-int bflag, ch, fd;
-int daggerset;
-
-/* options descriptor */
-static struct option longopts[] = {
- { "buffy", no_argument, NULL, 'b' },
- { "fluoride", required_argument, NULL, 'f' },
- { "daggerset", no_argument, &daggerset, 1 },
- { NULL, 0, NULL, 0 }
-};
-
-bflag = 0;
-while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1)
- switch (ch) {
- case 'b':
- bflag = 1;
- break;
- case 'f':
- if ((fd = open(optarg, O_RDONLY, 0)) == -1)
- err(1, "unable to open %s", optarg);
- break;
- case 0:
- if (daggerset)
- fprintf(stderr, "Buffy will use her dagger to "
- "apply fluoride to dracula's teeth\en");
- break;
- default:
- usage();
- }
-argc -= optind;
-argv += optind;
-.Ed
-.Sh SEE ALSO
-.Xr getopt 3
-.Sh HISTORY
-The
-.Fn getopt_long
-and
-.Fn getopt_long_only
-functions first appeared in GNU libiberty.
-This implementation first appeared in
-.Ox 3.3 .
-.Sh BUGS
-The
-.Ar argv
-argument is not really
-.Dv const
-as its elements may be permuted (unless
-.Ev POSIXLY_CORRECT
-is set).
diff --git a/third_party/getopt/getopt_long.c b/third_party/getopt/getopt_long.c
deleted file mode 100644
index 39c75bf6..00000000
--- a/third_party/getopt/getopt_long.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/**
- * This file has an inappropriate amount of legal text for its
- * complexity and should be rewritten. Consider using getopt().
- */
-asm(".ident\t\"\\n\\n\
-getopt_long (Licensed BSD-4, MIT)\\n\
-Copyright (c) 2000 The NetBSD Foundation, Inc.\\n\
-Copyright (c) 2002 Todd C. Miller %s", m->name, m->name); - // title if (m->javadown && *m->javadown->title) { fprintf(f, ""); PrintText(f, m->javadown->title); fprintf(f, "\n"); } - // text if (m->javadown && *m->javadown->text) { fprintf(f, " "); PrintText(f, m->javadown->text); fprintf(f, "\n"); } - // parameters if (!m->is_objlike && (m->params.n || HasTag(m->javadown, "param"))) { fprintf(f, " \n");
@@ -767,7 +832,6 @@ static void PrintDox(struct Dox *dox, FILE *f) {
fprintf(f, "\n");
fprintf(f, " \n"); // .tag
}
-
fprintf(f, " |