Further refine documentation

main
Justine Tunney 2020-12-27 17:05:03 -08:00
parent 1bc3a25505
commit 548dcb9f08
27 changed files with 389 additions and 1478 deletions

View File

@ -312,8 +312,12 @@ o/cosmopolitan.h: \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
@ACTION=ROLLUP TARGET=$@ build/do $^ >$@ @ACTION=ROLLUP TARGET=$@ build/do $^ >$@
o/cosmopolitan.html: o/$(MODE)/third_party/chibicc/chibicc.com.dbg o/cosmopolitan.html: \
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/$(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 # UNSPECIFIED PREREQUISITES TUTORIAL
# #

View File

@ -54,6 +54,7 @@ EXAMPLES_DIRECTDEPS = \
LIBC_NT_KERNELBASE \ LIBC_NT_KERNELBASE \
LIBC_NT_NTDLL \ LIBC_NT_NTDLL \
LIBC_NT_USER32 \ LIBC_NT_USER32 \
LIBC_NT_WS2_32 \
LIBC_OHMYPLUS \ LIBC_OHMYPLUS \
LIBC_RAND \ LIBC_RAND \
LIBC_RUNTIME \ LIBC_RUNTIME \

View File

@ -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[] = "\
/\tsign\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

View File

@ -98,25 +98,37 @@ typedef float __m128_u _Vector_size(16) forcealign(1) mayalias;
cosmopolitan § it's a trap! » sse » scalar ops cosmopolitan § it's a trap! » sse » scalar ops
*/ */
forceinline __m128 _mm_add_ss(__m128 m128_0, __m128 m128_1) { #define _mm_add_ss(m128_0, m128_1) \
m128_0[0] += m128_1[0]; ({ \
return m128_0; __m128 a = m128_0; \
} __m128 b = m128_0; \
a[0] += b[0]; \
a; \
})
forceinline __m128 _mm_sub_ss(__m128 m128_0, __m128 m128_1) { #define _mm_sub_ss(m128_0, m128_1) \
m128_0[0] -= m128_1[0]; ({ \
return m128_0; __m128 a = m128_0; \
} __m128 b = m128_0; \
a[0] -= b[0]; \
a; \
})
forceinline __m128 _mm_mul_ss(__m128 m128_0, __m128 m128_1) { #define _mm_mul_ss(m128_0, m128_1) \
m128_0[0] *= m128_1[0]; ({ \
return m128_0; __m128 a = m128_0; \
} __m128 b = m128_0; \
a[0] *= b[0]; \
a; \
})
forceinline __m128 _mm_div_ss(__m128 m128_0, __m128 m128_1) { #define _mm_div_ss(m128_0, m128_1) \
m128_0[0] /= m128_1[0]; ({ \
return m128_0; __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_rcp_ss(M128) __builtin_ia32_rcpss((__v4sf)(M128)) /*~1/x*/
#define _mm_sqrt_ss(M128) __builtin_ia32_sqrtss((__v4sf)(M128)) /*sqrt𝑥*/ #define _mm_sqrt_ss(M128) __builtin_ia32_sqrtss((__v4sf)(M128)) /*sqrt𝑥*/

View File

@ -5,13 +5,13 @@
#define va_end(AP) #define va_end(AP)
#define va_copy(DST, SRC) ((DST)[0] = (SRC)[0]) #define va_copy(DST, SRC) ((DST)[0] = (SRC)[0])
#define va_start(AP, LAST) \ #define va_start(AP, LAST) \
do { \ do { \
*(AP) = *(struct __va *)__va_area__; \ *(AP) = *(struct __va_list *)__va_area__; \
} while (0) } while (0)
#define va_arg(AP, TYPE) \ #define va_arg(AP, TYPE) \
(*(TYPE *)__va_arg(AP, sizeof(TYPE), _Alignof(TYPE), \ (*(TYPE *)__va_arg(AP, sizeof(TYPE), _Alignof(TYPE), \
__builtin_reg_class(TYPE))) __builtin_reg_class(TYPE)))
typedef struct __va va_list[1]; typedef struct __va_list va_list[1];

View File

@ -73,7 +73,7 @@ void vflogf_onfail(FILE *f) {
fseek(f, SEEK_SET, 0); fseek(f, SEEK_SET, 0);
f->beg = f->end = 0; f->beg = f->end = 0;
clearerr(f); 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); (vfprintf)(f, fmt, va);
va_end(va); va_end(va);
fputs("\r\n", f); fputs("\n", f);
if (level == kLogFatal) { if (level == kLogFatal) {
__start_fatal(file, line); __start_fatal(file, line);
(dprintf)(STDERR_FILENO, "fatal error see logfile\r\n"); (dprintf)(STDERR_FILENO, "fatal error see logfile\n");
__die(); __die();
unreachable; unreachable;
} }

View File

@ -285,28 +285,6 @@ void sincos(double, double *, double *);
void sincosf(float, float *, float *); void sincosf(float, float *, float *);
void sincosl(long double, long double *, long double *); 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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_MATH_H_ */ #endif /* COSMOPOLITAN_LIBC_MATH_H_ */

View File

@ -21,15 +21,15 @@
/ Returns binary logarithm of integer 𝑥. / Returns binary logarithm of integer 𝑥.
/ /
/ uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥) / uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
/ 0x00000000 wut 32 0 wut 32 / 0x00000000 wut 32 0 wut 32
/ 0x00000001 0 0 1 0 31 / 0x00000001 0 0 1 0 31
/ 0x80000001 0 0 1 31 0 / 0x80000001 0 0 1 31 0
/ 0x80000000 31 31 32 31 0 / 0x80000000 31 31 32 31 0
/ 0x00000010 4 4 5 4 27 / 0x00000010 4 4 5 4 27
/ 0x08000010 4 4 5 27 4 / 0x08000010 4 4 5 27 4
/ 0x08000000 27 27 28 27 4 / 0x08000000 27 27 28 27 4
/ 0xffffffff 0 0 1 31 0 / 0xffffffff 0 0 1 31 0
/ /
/ @param rsi:rdi is 128-bit unsigned 𝑥 value / @param rsi:rdi is 128-bit unsigned 𝑥 value
/ @return eax number in range [0,128) or undef if 𝑥 is 0 / @return eax number in range [0,128) or undef if 𝑥 is 0

View File

@ -409,7 +409,7 @@ int WSARecvFrom(uint64_t s, const struct NtIovec *out_lpBuffers,
uint32_t *inout_fromsockaddrlen, uint32_t *inout_fromsockaddrlen,
struct NtOverlapped *opt_inout_lpOverlapped, struct NtOverlapped *opt_inout_lpOverlapped,
const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine) const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine)
paramsnonnull((2, 5, 6, 7)); paramsnonnull((2, 5));
int WSARecvDisconnect(uint64_t s, int WSARecvDisconnect(uint64_t s,
const struct NtIovec *opt_lpInboundDisconnectData); const struct NtIovec *opt_lpInboundDisconnectData);

View File

@ -20,13 +20,13 @@
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/runtime/valist.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); void *r = (void *)ROUNDUP((intptr_t)ap->overflow_arg_area, align);
ap->overflow_arg_area = (void *)ROUNDUP((intptr_t)r + sz, 8); ap->overflow_arg_area = (void *)ROUNDUP((intptr_t)r + sz, 8);
return r; 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; void *r;
switch (k) { switch (k) {
case 0: case 0:

View File

@ -3,14 +3,14 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
struct __va { struct __va_list {
uint32_t gp_offset; uint32_t gp_offset;
uint32_t fp_offset; uint32_t fp_offset;
void *overflow_arg_area; void *overflow_arg_area;
void *reg_save_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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View File

@ -27,6 +27,8 @@
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/o.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 "third_party/gdtoa/gdtoa.h"
#include "tool/build/lib/elfwriter.h" #include "tool/build/lib/elfwriter.h"
@ -443,49 +445,6 @@ static unsigned Hash(const void *p, unsigned long n) {
return MAX(1, h); 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) { static bool IsPunctMergeable(int c) {
switch (c) { switch (c) {
case ';': case ';':
@ -613,11 +572,11 @@ static void ReadFlags(struct As *a, int argc, char *argv[]) {
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-o")) { if (!strcmp(argv[i], "-o")) {
a->outpath = StrDup(a, argv[++i]); 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); a->outpath = StrDup(a, argv[i] + 2);
} else if (!strcmp(argv[i], "-I")) { } else if (!strcmp(argv[i], "-I")) {
SaveString(&a->incpaths, strdup(argv[++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)); SaveString(&a->incpaths, strdup(argv[i] + 2));
} else if (!strcmp(argv[i], "-Z")) { } else if (!strcmp(argv[i], "-Z")) {
a->inhibiterr = true; 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) { static void PrintLocation(struct As *a) {
fprintf(stderr, fprintf(stderr,
"%s:%d:: ", a->strings.p[a->sauces.p[a->things.p[a->i].s].path], "%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; char *path;
struct stat st; struct stat st;
for (i = 0; i < a->incpaths.n; ++i) { 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; if (stat(path, &st) != -1 && S_ISREG(st.st_mode)) return path;
free(path); free(path);
} }
@ -780,10 +673,10 @@ static void Tokenize(struct As *a, int path) {
char *p, *path2; char *p, *path2;
struct Slice buf; struct Slice buf;
bool bol, isfloat, isfpu; bool bol, isfloat, isfpu;
p = SaveString(&a->strings, ReadFile(a->strings.p[path])); p = SaveString(&a->strings, read_file(a->strings.p[path]));
if (!memcmp(p, "\357\273\277", 3)) p += 3; p = skip_bom(p);
CanonicalizeNewline(p); canonicalize_newline(p);
RemoveBackslashNewline(p); remove_backslash_newline(p);
line = 1; line = 1;
bol = true; bol = true;
while ((c = *p)) { while ((c = *p)) {
@ -1031,7 +924,7 @@ static void OnSymbol(struct As *a, int name) {
static void OnLocalLabel(struct As *a, int id) { static void OnLocalLabel(struct As *a, int id) {
int i; int i;
char *name; char *name;
name = Format(".Label.%d", a->counter++); name = xasprintf(".Label.%d", a->counter++);
SaveString(&a->strings, name); SaveString(&a->strings, name);
AppendSlice(a); AppendSlice(a);
a->slices.p[a->slices.n - 1].p = name; 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) { static void OnSection(struct As *a, struct Slice s) {
int name, flags, type; int name, flags, type;
name = SliceDup(a, GetSlice(a)); name = SliceDup(a, GetSlice(a));
if (StartsWith(a->strings.p[name], ".text")) { if (startswith(a->strings.p[name], ".text")) {
flags = SHF_ALLOC | SHF_EXECINSTR; flags = SHF_ALLOC | SHF_EXECINSTR;
type = SHT_PROGBITS; type = SHT_PROGBITS;
} else if (StartsWith(a->strings.p[name], ".data")) { } else if (startswith(a->strings.p[name], ".data")) {
flags = SHF_ALLOC | SHF_WRITE; flags = SHF_ALLOC | SHF_WRITE;
type = SHT_PROGBITS; type = SHT_PROGBITS;
} else if (StartsWith(a->strings.p[name], ".bss")) { } else if (startswith(a->strings.p[name], ".bss")) {
flags = SHF_ALLOC | SHF_WRITE; flags = SHF_ALLOC | SHF_WRITE;
type = SHT_NOBITS; type = SHT_NOBITS;
} else { } else {
@ -2372,7 +2265,7 @@ static noinline void OpBsu(struct As *a, struct Slice opname, int op) {
OpBsuImpl(a, opname, 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; int modrm, imm, disp;
modrm = ParseModrm(a, &disp); modrm = ParseModrm(a, &disp);
reg |= GetOpSize(a, s, modrm, 1) << 3; reg |= GetOpSize(a, s, modrm, 1) << 3;
@ -2380,6 +2273,10 @@ static int OpF6(struct As *a, struct Slice s, int reg) {
return 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) { static void OnTest(struct As *a, struct Slice s) {
int reg, modrm, imm, disp; int reg, modrm, imm, disp;
if (IsPunct(a, a->i, '$')) { if (IsPunct(a, a->i, '$')) {
@ -2571,8 +2468,8 @@ static bool HasXmmOnLine(struct As *a) {
int i; int i;
for (i = 0; !IsPunct(a, a->i + i, ';'); ++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 && 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; return true;
} }
} }
@ -4002,7 +3899,7 @@ void Assembler(int argc, char *argv[]) {
a = NewAssembler(); a = NewAssembler();
ReadFlags(a, argc, argv); ReadFlags(a, argc, argv);
SaveString(&a->incpaths, strdup(".")); 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); Tokenize(a, a->inpath);
/* PrintThings(a); */ /* PrintThings(a); */
Assemble(a); Assemble(a);

View File

@ -130,9 +130,6 @@ Token *tokenize_string_literal(Token *, Type *);
bool consume(Token **, Token *, char *, size_t); bool consume(Token **, Token *, char *, size_t);
bool equal(Token *, char *, size_t); bool equal(Token *, char *, size_t);
void convert_pp_tokens(Token *); void convert_pp_tokens(Token *);
void remove_backslash_newline(char *);
void canonicalize_newline(char *);
char *read_file(char *);
int read_escaped_char(char **, char *); int read_escaped_char(char **, char *);
#define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__) #define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__)
@ -450,6 +447,7 @@ struct Type {
int align; // alignment int align; // alignment
bool is_unsigned; // unsigned or signed bool is_unsigned; // unsigned or signed
bool is_atomic; // true if _Atomic bool is_atomic; // true if _Atomic
bool is_const; // const
bool is_ms_abi; // microsoft abi bool is_ms_abi; // microsoft abi
Type *origin; // for type compatibility check Type *origin; // for type compatibility check
// Pointer-to or array-of type. We intentionally use the same member // Pointer-to or array-of type. We intentionally use the same member

View File

@ -79,7 +79,8 @@ static void SerializeJavadown(struct Buffer *buf, struct Javadown *jd) {
} }
static char *DescribeScalar(struct Type *ty, char *name) { 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); ty->is_unsigned ? "unsigned " : "", name);
} }
@ -134,7 +135,7 @@ static char *DescribeType(struct Type *ty) {
return strdup("ANONYMOUS-UNION"); return strdup("ANONYMOUS-UNION");
} }
default: 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])); SerializeStr(&dox->buf, GetFileName(dox->objects.p[i]));
SerializeInt(&dox->buf, GetLine(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_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_weak);
SerializeInt(&dox->buf, dox->objects.p[i]->is_inline); 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_noreturn);
@ -248,6 +250,7 @@ static void SerializeAsmdown(struct DoxWriter *dox, struct Asmdown *ad,
SerializeStr(&dox->buf, filename); SerializeStr(&dox->buf, filename);
SerializeInt(&dox->buf, ad->symbols.p[i].line); SerializeInt(&dox->buf, ad->symbols.p[i].line);
SerializeInt(&dox->buf, true); // TODO: is_function SerializeInt(&dox->buf, true); // TODO: is_function
SerializeInt(&dox->buf, false); // is_variadic
SerializeInt(&dox->buf, false); // TODO: is_weak SerializeInt(&dox->buf, false); // TODO: is_weak
SerializeInt(&dox->buf, false); // is_inline SerializeInt(&dox->buf, false); // is_inline
SerializeInt(&dox->buf, false); // is_noreturn SerializeInt(&dox->buf, false); // is_noreturn

View File

@ -47,6 +47,7 @@ struct Dox {
char *path; char *path;
int line; int line;
bool is_function; bool is_function;
bool is_variadic;
bool is_weak; bool is_weak;
bool is_inline; bool is_inline;
bool is_noreturn; bool is_noreturn;
@ -177,6 +178,7 @@ static void DeserializeObject(struct Dox *dox, struct DoxObject *o) {
o->path = DeserializeStr(dox); o->path = DeserializeStr(dox);
o->line = DeserializeInt(dox); o->line = DeserializeInt(dox);
o->is_function = DeserializeInt(dox); o->is_function = DeserializeInt(dox);
o->is_variadic = DeserializeInt(dox);
o->is_weak = DeserializeInt(dox); o->is_weak = DeserializeInt(dox);
o->is_inline = DeserializeInt(dox); o->is_inline = DeserializeInt(dox);
o->is_noreturn = 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; int i, j, n;
i = dox->objects.n; i = dox->objects.n;
n = DeserializeInt(dox); n = DeserializeInt(dox);
@ -242,7 +244,7 @@ static void ReadDox(struct Dox *dox, const StringArray *files) {
CHECK_NE(MAP_FAILED, CHECK_NE(MAP_FAILED,
(map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))); (map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)));
dox->p = map; dox->p = map;
DeserializeDox(dox); DeserializeDox(dox, files->data[i]);
munmap(map, st.st_size); munmap(map, st.st_size);
} }
close(fd); close(fd);
@ -317,15 +319,19 @@ static void IndexDox(struct Dox *dox) {
CompareDoxIndexEntry, dox); CompareDoxIndexEntry, dox);
} }
/**
* Escapes HTML entities and interprets basic Markdown syntax.
*/
static void PrintText(FILE *f, const char *s) { static void PrintText(FILE *f, const char *s) {
int c; int c;
bool bol, pre, ul0, ul2, bt1, bt2; bool bol, pre, ul0, ul2, ol0, ol2, bt1, bt2;
for (bt1 = bt2 = ul2 = ul0 = pre = false, bol = true;;) { for (bt1 = bt2 = ul2 = ul0 = ol2 = ol0 = pre = false, bol = true;;) {
switch ((c = *s++)) { switch ((c = *s++)) {
case '\0': case '\0':
if (bt1 || bt2) fprintf(f, "</code>"); if (bt1 || bt2) fprintf(f, "</code>");
if (pre) fprintf(f, "</pre>"); if (pre) fprintf(f, "</pre>");
if (ul0 || ul2) fprintf(f, "</ul>"); if (ul0 || ul2) fprintf(f, "</ul>");
if (ol0 || ol2) fprintf(f, "</ol>");
return; return;
case '&': case '&':
fprintf(f, "&amp;"); fprintf(f, "&amp;");
@ -368,14 +374,19 @@ static void PrintText(FILE *f, const char *s) {
bol = false; bol = false;
break; break;
case '\n': case '\n':
if (!pre && !ul0 && !ul2 && *s == '\n') { if (!pre && !ul0 && !ul2 && !ol0 && !ol2 && *s == '\n') {
fprintf(f, "\n<p>"); fprintf(f, "\n<p>");
bol = true; bol = true;
} else if (pre && s[0] != '\n' && } else if (pre && s[0] != '\n') {
(s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) { if (s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ') {
fprintf(f, "</pre>\n"); fprintf(f, "</pre>\n");
pre = false; pre = false;
bol = true; bol = true;
} else {
fprintf(f, "\n");
bol = false;
s += 4;
}
} else if (ul0 && s[0] == '-' && s[1] == ' ') { } else if (ul0 && s[0] == '-' && s[1] == ' ') {
fprintf(f, "\n<li>"); fprintf(f, "\n<li>");
s += 2; s += 2;
@ -394,29 +405,65 @@ static void PrintText(FILE *f, const char *s) {
fprintf(f, "\n</ul>\n"); fprintf(f, "\n</ul>\n");
bol = true; bol = true;
ul2 = false; ul2 = false;
} else if (ol0 && ('0' <= s[0] && s[0] <= '9') && s[1] == '.' &&
s[2] == ' ') {
fprintf(f, "\n<li>");
s += 3;
bol = false;
} else if (ol2 && s[0] == ' ' && s[1] == ' ' &&
('0' <= s[2] && s[2] <= '9') && s[3] == '.' && s[3] == ' ') {
fprintf(f, "\n<li>");
s += 5;
bol = false;
} else if (ol0 && s[0] != '\n' && (s[0] != ' ' || s[1] != ' ')) {
fprintf(f, "\n</ol>\n");
bol = true;
ol0 = false;
} else if (ol2 && s[0] != '\n' &&
(s[0] != ' ' || s[1] != ' ' || s[2] != ' ' || s[3] != ' ')) {
fprintf(f, "\n</ol>\n");
bol = true;
ol2 = false;
} else { } else {
fprintf(f, "\n"); fprintf(f, "\n");
bol = true; bol = true;
} }
break; break;
case '-': case '-':
if (bol && !ul0 && !ul2 && s[0] == ' ') { if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ') {
ul0 = true; ul0 = true;
fprintf(f, "<ul><li>"); fprintf(f, "<ul><li>");
++s;
} else { } else {
fprintf(f, "-"); fprintf(f, "-");
} }
bol = false; bol = false;
break; break;
case '1':
if (bol && !ol0 && !ol2 && !ul0 && !ul2 && s[0] == '.' && s[1] == ' ') {
ol0 = true;
fprintf(f, "<ol><li>");
s += 2;
} else {
fprintf(f, "1");
}
bol = false;
break;
case ' ': case ' ':
if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') { if (bol && !pre && s[0] == ' ' && s[1] == ' ' && s[2] == ' ') {
pre = true; pre = true;
fprintf(f, "<pre> "); fprintf(f, "<pre>");
} else if (bol && !ul0 && !ul2 && s[0] == ' ' && s[1] == '-' && s += 3;
s[2] == ' ') { } else if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ' &&
s[1] == '-' && s[2] == ' ') {
ul2 = true; ul2 = true;
fprintf(f, "<ul><li>"); fprintf(f, "<ul><li>");
s += 3; s += 3;
} else if (bol && !ul0 && !ul2 && !ol0 && !ol2 && s[0] == ' ' &&
('0' <= s[1] && s[1] <= '9') && s[2] == '.' && s[3] == ' ') {
ol2 = true;
fprintf(f, "<ol><li>");
s += 4;
} else { } else {
fprintf(f, " "); fprintf(f, " ");
} }
@ -469,6 +516,9 @@ static void PrintDox(struct Dox *dox, FILE *f) {
.nav {\n\ .nav {\n\
margin-bottom: 0;\n\ margin-bottom: 0;\n\
}\n\ }\n\
.toc {\n\
overflow-x: auto;\n\
}\n\
.toc a {\n\ .toc a {\n\
text-decoration: none;\n\ text-decoration: none;\n\
}\n\ }\n\
@ -514,7 +564,10 @@ static void PrintDox(struct Dox *dox, FILE *f) {
</style>\n\ </style>\n\
\n\ \n\
<header>\n\ <header>\n\
<img width=\"196\" height=\"105\" src=\"//storage.googleapis.com/justine/cosmopolitan/cosmopolitan.png\" alt=\"honeybadger\">\n\ <img width=\"196\" height=\"105\"\n\
src=\"//storage.googleapis.com/justine/cosmopolitan/cosmopolitan.png\"\n\
title=\"cosmopolitan honeybadger\"\n\
alt=\"honeybadger\">\n\
<h1>cosmopolitan libc</h1>\n\ <h1>cosmopolitan libc</h1>\n\
<span>build-once run-anywhere c without devops</span>\n\ <span>build-once run-anywhere c without devops</span>\n\
</header>\n\ </header>\n\
@ -533,7 +586,7 @@ static void PrintDox(struct Dox *dox, FILE *f) {
\n\ \n\
<table class=\"dox\" width=\"960\">\n\ <table class=\"dox\" width=\"960\">\n\
<tr>\n\ <tr>\n\
<td width=\"320\" valign=\"top\" class=\"toc\">\n\ <td width=\"283\" valign=\"top\" class=\"toc\">\n\
"); ");
/* // lefthand index: objects */ /* // lefthand index: objects */
@ -581,7 +634,7 @@ static void PrintDox(struct Dox *dox, FILE *f) {
} }
// righthand contents // righthand contents
fprintf(f, "<td width=\"640\" valign=\"top\">\n"); fprintf(f, "<td width=\"667\" valign=\"top\">\n");
for (i = 0; i < dox->index.n; ++i) { for (i = 0; i < dox->index.n; ++i) {
if (dox->index.p[i].t == kObject) { if (dox->index.p[i].t == kObject) {
o = dox->objects.p + dox->index.p[i].i; o = dox->objects.p + dox->index.p[i].i;
@ -606,7 +659,8 @@ static void PrintDox(struct Dox *dox, FILE *f) {
} }
// parameters // 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, "<div class=\"tag\">\n"); fprintf(f, "<div class=\"tag\">\n");
fprintf(f, "<span class=\"tagname\">@param</span>\n"); fprintf(f, "<span class=\"tagname\">@param</span>\n");
fprintf(f, "<dl>\n"); fprintf(f, "<dl>\n");
@ -641,6 +695,9 @@ static void PrintDox(struct Dox *dox, FILE *f) {
} }
} }
} }
if (o->is_variadic) {
fprintf(f, "<dt>...\n");
}
fprintf(f, "</dl>\n"); fprintf(f, "</dl>\n");
fprintf(f, "</div>\n"); // .tag fprintf(f, "</div>\n"); // .tag
} }
@ -676,6 +733,17 @@ static void PrintDox(struct Dox *dox, FILE *f) {
} }
} }
// type
if (!o->is_function) {
fprintf(f, "<div class=\"tag\">\n");
fprintf(f, "<span class=\"tagname\">@type</span>\n");
fprintf(f, "<dl>\n");
fprintf(f, "<dt>");
PrintText(f, o->type);
fprintf(f, "</dl>\n");
fprintf(f, "</div>\n"); // .tag
}
// tags // tags
if (o->javadown) { if (o->javadown) {
for (k = 0; k < o->javadown->tags.n; ++k) { 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, "<hr>"); if (i) fprintf(f, "<hr>");
fprintf(f, "<div id=\"%s\" class=\"api\">\n", m->name); fprintf(f, "<div id=\"%s\" class=\"api\">\n", m->name);
fprintf(f, "<h3><a href=\"#%s\">%s</a></h3>", m->name, m->name); fprintf(f, "<h3><a href=\"#%s\">%s</a></h3>", m->name, m->name);
// title // title
if (m->javadown && *m->javadown->title) { if (m->javadown && *m->javadown->title) {
fprintf(f, "<p>"); fprintf(f, "<p>");
PrintText(f, m->javadown->title); PrintText(f, m->javadown->title);
fprintf(f, "\n"); fprintf(f, "\n");
} }
// text // text
if (m->javadown && *m->javadown->text) { if (m->javadown && *m->javadown->text) {
fprintf(f, "<p>"); fprintf(f, "<p>");
PrintText(f, m->javadown->text); PrintText(f, m->javadown->text);
fprintf(f, "\n"); fprintf(f, "\n");
} }
// parameters // parameters
if (!m->is_objlike && (m->params.n || HasTag(m->javadown, "param"))) { if (!m->is_objlike && (m->params.n || HasTag(m->javadown, "param"))) {
fprintf(f, "<div class=\"tag\">\n"); fprintf(f, "<div class=\"tag\">\n");
@ -767,7 +832,6 @@ static void PrintDox(struct Dox *dox, FILE *f) {
fprintf(f, "</dl>\n"); fprintf(f, "</dl>\n");
fprintf(f, "</div>\n"); // .tag fprintf(f, "</div>\n"); // .tag
} }
fprintf(f, "</div>\n"); /* class=".api" */ fprintf(f, "</div>\n"); /* class=".api" */
} }
} }

106
third_party/chibicc/file.c vendored 100644
View File

@ -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';
}

13
third_party/chibicc/file.h vendored 100644
View File

@ -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_ */

View File

@ -48,7 +48,6 @@ typedef struct {
bool is_static; bool is_static;
bool is_extern; bool is_extern;
bool is_inline; bool is_inline;
bool is_const;
bool is_tls; bool is_tls;
bool is_weak; bool is_weak;
bool is_ms_abi; 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) { static Node *new_var_node(Obj *var, Token *tok) {
if (!var) DebugBreak();
CHECK_NOTNULL(var);
Node *node = new_node(ND_VAR, tok); Node *node = new_node(ND_VAR, tok);
node->var = var; node->var = var;
return node; return node;
@ -647,6 +648,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
}; };
Type *ty = copy_type(ty_int); Type *ty = copy_type(ty_int);
int counter = 0; int counter = 0;
bool is_const = false;
bool is_atomic = false; bool is_atomic = false;
while (is_typename(tok)) { while (is_typename(tok)) {
// Handle storage class specifiers. // Handle storage class specifiers.
@ -682,7 +684,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
goto Continue; goto Continue;
} }
if (CONSUME(&tok, tok, "const")) { if (CONSUME(&tok, tok, "const")) {
if (attr) attr->is_const = true; is_const = true;
goto Continue; goto Continue;
} }
// These keywords are recognized but ignored. // These keywords are recognized but ignored.
@ -841,6 +843,10 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
ty = copy_type(ty); ty = copy_type(ty);
ty->is_atomic = true; ty->is_atomic = true;
} }
/* if (attr && is_const) { */
/* ty = copy_type(ty); */
/* ty->is_const = true; */
/* } */
*rest = tok; *rest = tok;
return ty; return ty;
} }
@ -873,6 +879,7 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
Type head = {}; Type head = {};
Type *cur = &head; Type *cur = &head;
bool is_variadic = false; bool is_variadic = false;
enter_scope();
while (!EQUAL(tok, ")")) { while (!EQUAL(tok, ")")) {
if (cur != &head) tok = skip(tok, ','); if (cur != &head) tok = skip(tok, ',');
if (EQUAL(tok, "...")) { if (EQUAL(tok, "...")) {
@ -884,6 +891,9 @@ static Type *func_params(Token **rest, Token *tok, Type *ty) {
Type *ty2 = declspec(&tok, tok, NULL); Type *ty2 = declspec(&tok, tok, NULL);
ty2 = declarator(&tok, tok, ty2); ty2 = declarator(&tok, tok, ty2);
Token *name = ty2->name; Token *name = ty2->name;
if (name) {
new_lvar(strndup(name->loc, name->len), ty2);
}
if (ty2->kind == TY_ARRAY) { if (ty2->kind == TY_ARRAY) {
// "array of T" is converted to "pointer to T" only in the parameter // "array of T" is converted to "pointer to T" only in the parameter
// context. For example, *argv[] is converted to **argv by this. // 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); cur = cur->next = copy_type(ty2);
} }
leave_scope();
if (cur == &head) is_variadic = true; if (cur == &head) is_variadic = true;
ty = func_type(ty); ty = func_type(ty);
ty->params = head.next; 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. // 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, // 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. // 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 // VLA + num
if (lhs->ty->base->kind == TY_VLA) { if (lhs->ty->base->kind == TY_VLA) {
rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), rhs = new_binary(ND_MUL, rhs, get_vla_size(lhs->ty->base, tok), tok);
tok);
return new_binary(ND_ADD, lhs, rhs, tok); return new_binary(ND_ADD, lhs, rhs, tok);
} }
// ptr + num // ptr + num
@ -2509,8 +2529,7 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) {
return new_binary(ND_SUB, lhs, rhs, tok); return new_binary(ND_SUB, lhs, rhs, tok);
// VLA + num // VLA + num
if (lhs->ty->base->kind == TY_VLA) { if (lhs->ty->base->kind == TY_VLA) {
rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), rhs = new_binary(ND_MUL, rhs, get_vla_size(lhs->ty->base, tok), tok);
tok);
add_type(rhs); add_type(rhs);
Node *node = new_binary(ND_SUB, lhs, rhs, tok); Node *node = new_binary(ND_SUB, lhs, rhs, tok);
node->ty = lhs->ty; node->ty = lhs->ty;
@ -3044,7 +3063,9 @@ static Node *primary(Token **rest, Token *tok) {
if (EQUAL(tok, "sizeof")) { if (EQUAL(tok, "sizeof")) {
Node *node = unary(rest, tok->next); Node *node = unary(rest, tok->next);
add_type(node); 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); return new_ulong(node->ty->size, tok);
} }
if ((EQUAL(tok, "_Alignof") || EQUAL(tok, "__alignof__")) && 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_no_instrument_function |= attr->is_no_instrument_function;
fn->is_force_align_arg_pointer |= attr->is_force_align_arg_pointer; 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->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->is_root = !(fn->is_static && fn->is_inline);
fn->javadown = fn->javadown ?: current_javadown;
current_javadown = NULL;
if (consume_attribute(&tok, tok, "asm")) { if (consume_attribute(&tok, tok, "asm")) {
tok = skip(tok, '('); tok = skip(tok, '(');
fn->asmname = ConsumeStringLiteral(&tok, tok); fn->asmname = ConsumeStringLiteral(&tok, tok);
@ -3526,16 +3548,20 @@ static void scan_globals(void) {
globals = head.next; globals = head.next;
} }
static char *prefix_builtin(const char *name) {
return xstrcat("__builtin_", name);
}
static Obj *declare0(char *name, Type *ret) { static Obj *declare0(char *name, Type *ret) {
if (!opt_no_builtin) new_gvar(name, func_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) { static Obj *declare1(char *name, Type *ret, Type *p1) {
Type *ty = func_type(ret); Type *ty = func_type(ret);
ty->params = copy_type(p1); ty->params = copy_type(p1);
if (!opt_no_builtin) new_gvar(name, ty); 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) { 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 = copy_type(p1);
ty->params->next = copy_type(p2); ty->params->next = copy_type(p2);
if (!opt_no_builtin) new_gvar(name, ty); 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) { 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 = copy_type(b);
ty->params->next->next = copy_type(c); ty->params->next->next = copy_type(c);
if (!opt_no_builtin) new_gvar(s, ty); 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) { static void math0(char *name) {

View File

@ -1,3 +1,4 @@
asm(".ident\t\"hello\"");
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi

View File

@ -1,7 +1,30 @@
#include "libc/macros.h" #include "libc/macros.h"
#include "third_party/chibicc/test/test.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() { 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, ({ ASSERT(20, ({
int n = 5; int n = 5;
int x[n]; int x[n];

View File

@ -1,4 +1,5 @@
#include "third_party/chibicc/chibicc.h" #include "third_party/chibicc/chibicc.h"
#include "third_party/chibicc/file.h"
#define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, sizeof(OP) - 1)) #define LOOKINGAT(TOK, OP) (!memcmp(TOK, OP, sizeof(OP) - 1))
@ -610,40 +611,6 @@ Token *tokenize(File *file) {
return head.next; 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) { File **get_input_files(void) {
return input_files; return input_files;
} }
@ -657,68 +624,6 @@ File *new_file(char *name, int file_no, char *contents) {
return file; 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) { static uint32_t read_universal_char(char *p, int len) {
uint32_t c = 0; uint32_t c = 0;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
@ -761,11 +666,7 @@ static void convert_universal_chars(char *p) {
Token *tokenize_file(char *path) { Token *tokenize_file(char *path) {
char *p = read_file(path); char *p = read_file(path);
if (!p) return NULL; if (!p) return NULL;
// UTF-8 texts may start with a 3-byte "BOM" marker sequence. p = skip_bom(p);
// 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;
canonicalize_newline(p); canonicalize_newline(p);
remove_backslash_newline(p); remove_backslash_newline(p);
convert_universal_chars(p); convert_universal_chars(p);

View File

@ -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 $ */ /* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
/* /*
* Copyright (c) 1987, 1993, 1994 * Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved. * 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 * @(#)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 $ * $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 * $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/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.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"); STATIC_YOINK("_init_getopt");
#define BADCH (int)'?' #define BADCH (int)'?'
@ -50,48 +47,65 @@ STATIC_YOINK("_init_getopt");
/** /**
* If error message should be printed. * If error message should be printed.
* @see getopt()
*/ */
int opterr; int opterr;
/** /**
* Index into parent argv vector. * Index into parent argv vector.
* @see getopt()
*/ */
int optind; int optind;
/** /**
* Character checked for validity. * Character checked for validity.
* @see getopt()
*/ */
int optopt; int optopt;
/** /**
* Reset getopt. * Reset getopt.
* @see getopt()
*/ */
int optreset; int optreset;
/** /**
* Argument associated with option. * Argument associated with option.
* @see getopt()
*/ */
char *optarg; char *optarg;
/** hidden char *getopt_place;
* Option letter processing.
*/
char *getopt_place;
char kGetoptEmsg[1] hidden; 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) { int getopt(int nargc, char *const nargv[], const char *ostr) {
char *oli; /* option letter list index */ char *oli; /* option letter list index */
/* /*
* Some programs like cvs expect optind = 0 to trigger * Some programs like cvs expect optind = 0 to trigger
* a reset of getopt. * a reset of getopt.
*/ */
if (optind == 0) optind = 1; if (optind == 0) optind = 1;
if (optreset || *getopt_place == 0) { /* update scanning pointer */ if (optreset || *getopt_place == 0) { /* update scanning pointer */
optreset = 0; optreset = 0;
getopt_place = nargv[optind]; getopt_place = nargv[optind];
@ -117,7 +131,6 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
} else { } else {
optopt = *getopt_place++; optopt = *getopt_place++;
} }
/* See if option letter is one the caller wanted... */ /* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) { if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*getopt_place == 0) ++optind; if (*getopt_place == 0) ++optind;
@ -127,7 +140,6 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
} }
return (BADCH); return (BADCH);
} }
/* Does this option need an argument? */ /* Does this option need an argument? */
if (oli[1] != ':') { if (oli[1] != ':') {
/* don't need argument */ /* don't need argument */
@ -152,5 +164,5 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
getopt_place = kGetoptEmsg; getopt_place = kGetoptEmsg;
++optind; ++optind;
} }
return (optopt); /* return option letter */ return optopt; /* return option letter */
} }

View File

@ -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).

View File

@ -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 <Todd.Miller@courtesan.com>\\n\
The getopt_long code is derived from software contributed to The\\n\
NetBSD Foundation by Dieter Baron and Thomas Klausner. This code\\n\
has received sponsorship from the U.S. Military. Special thanks\\n\
to the OpenBSD, NetBSD, FreeBSD, and DragonFlyBSD teams.\"");
asm(".include \"libc/disclaimer.inc\"");
#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
/* clang-format off */
/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $*/
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*
* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.15 2006/09/23 14:48:31 ache Exp $
* $DragonFly: src/lib/libc/stdlib/getopt_long.c,v 1.14 2005/11/20 12:37:48 swildner Exp $
*/
#include "third_party/getopt/getopt.h"
#include "libc/str/str.h"
#include "libc/runtime/runtime.h"
#include "libc/log/bsd.h"
STATIC_YOINK("stoa");
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG2 ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static int dash_prefix = NO_PREFIX;
#define recargchar "option requires an argument -- %c"
#define illoptchar "illegal option -- %c" /* From P1003.2 */
#define gnuoptchar "invalid option -- %c"
#define recargstring "option `%s%s' requires an argument"
#define ambig "option `%s%.*s' is ambiguous"
#define noarg "option `%s%.*s' doesn't allow an argument"
#define illoptstring "unrecognized option `%s%s'"
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
(__DECONST(char **, nargv))[pos] = nargv[cstart];
/* LINTED const cast */
(__DECONST(char **, nargv))[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too, int flags)
{
char *current_argv, *has_equal;
char *current_dash;
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
current_argv = place;
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
match = -1;
exact_match = 0;
second_partial_match = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
(warnx)(ambig,
current_dash,
(int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
(warnx)(noarg,
current_dash,
(int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADCH);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
(warnx)(recargstring,
current_dash,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG2);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
(warnx)(illoptstring,
current_dash,
current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
int posixly_correct; /* no static, can be changed on the fly */
if (options == NULL)
return (-1);
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
place[1] == '\0') {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
dash_prefix = D_PREFIX;
if (*place == '-') {
place++; /* --foo long option */
dash_prefix = DD_PREFIX;
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
(warnx)(posixly_correct ? illoptchar : gnuoptchar,
optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
(warnx)(recargchar, optchar);
optopt = optchar;
return (BADARG2);
} else /* white space */
place = nargv[optind];
dash_prefix = W_PREFIX;
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
(warnx)(recargchar, optchar);
optopt = optchar;
return (BADARG2);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}

View File

@ -25,6 +25,5 @@
pop %rax pop %rax
mov %eax,opterr(%rip) mov %eax,opterr(%rip)
mov %eax,optind(%rip) mov %eax,optind(%rip)
lea kGetoptEmsg(%rip),%rax movl $kGetoptEmsg,getopt_place(%rip)
mov %rax,getopt_place(%rip)
.init.end 201,_init_getopt .init.end 201,_init_getopt

View File

@ -40,15 +40,15 @@ M(0, i, "true", True, 1, "1")
M(0, i, "intmin", IntMin, INT128_MIN, "native integer minimum") M(0, i, "intmin", IntMin, INT128_MIN, "native integer minimum")
M(0, i, "intmax", IntMax, INT128_MAX, "native integer maximum") M(0, i, "intmax", IntMax, INT128_MAX, "native integer maximum")
M(0, f, "e", Euler, M_E, "𝑒") M(0, f, "e", Euler, M_E, "𝑒")
M(0, f, "pi", Fldpi, fldpi(), "π") M(0, f, "pi", Fldpi, M_PI, "π")
M(0, f, "epsilon", Epsilon, EPSILON, "ɛ") M(0, f, "epsilon", Epsilon, EPSILON, "ɛ")
M(0, f, "inf", Inf, INFINITY, "") M(0, f, "inf", Inf, INFINITY, "")
M(0, f, "nan", Nan, NAN, "NAN") M(0, f, "nan", Nan, NAN, "NAN")
M(0, f, "-0", Negzero, -0., "wut") M(0, f, "-0", Negzero, -0., "wut")
M(0, f, "l2t", Fldl2t, fldl2t(), "log₂10") M(0, f, "l2t", Fldl2t, M_LOG2_10, "log₂10")
M(0, f, "lg2", Fldlg2, fldlg2(), "log₁₀2") M(0, f, "lg2", Fldlg2, M_LOG10_2, "log₁₀2")
M(0, f, "ln2", Fldln2, fldln2(), "logₑ2") M(0, f, "ln2", Fldln2, M_LN2, "logₑ2")
M(0, f, "l2e", Fldl2e, fldl2e(), "logₑ10") M(0, f, "l2e", Fldl2e, M_LOG2E, "logₑ10")
M(1, f, "sqrt", Sqrt, sqrtl(x), "√𝑥") M(1, f, "sqrt", Sqrt, sqrtl(x), "√𝑥")
M(1, f, "exp", Exp, expl(x), "𝑒ˣ") M(1, f, "exp", Exp, expl(x), "𝑒ˣ")

View File

@ -86,7 +86,6 @@
#include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/shut.h" #include "libc/sysv/consts/shut.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/splice.h" #include "libc/sysv/consts/splice.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/consts/w.h" #include "libc/sysv/consts/w.h"
@ -251,7 +250,6 @@ static const struct NamedVector kLightings[] = {
}; };
static plm_t *plm_; static plm_t *plm_;
static FILE *fsock_;
static float gamma_; static float gamma_;
static int volscale_; static int volscale_;
static enum Blur blur_; static enum Blur blur_;
@ -1210,8 +1208,6 @@ static void PerformBestEffortIo(void) {
struct pollfd fds[] = { struct pollfd fds[] = {
{infd_, POLLIN}, {infd_, POLLIN},
{outfd_, f1_ && f1_->n ? POLLOUT : 0}, {outfd_, f1_ && f1_->n ? POLLOUT : 0},
{fsock_ ? fileno(fsock_) : -1,
fsock_ && favail(fsock_) < (NETBUFSIZ >> 1) ? POLLIN : 0},
}; };
pollms = MAX(0, AsMilliseconds(GetGraceTime())); pollms = MAX(0, AsMilliseconds(GetGraceTime()));
DEBUGF("poll() ms=%,d", pollms); DEBUGF("poll() ms=%,d", pollms);
@ -1221,12 +1217,6 @@ static void PerformBestEffortIo(void) {
if (toto) { if (toto) {
if (fds[0].revents & (POLLIN | POLLERR)) ReadKeyboard(); if (fds[0].revents & (POLLIN | POLLERR)) ReadKeyboard();
if (fds[1].revents & (POLLOUT | POLLERR)) WriteVideo(); if (fds[1].revents & (POLLOUT | POLLERR)) WriteVideo();
if (fds[2].revents & (POLLHUP | POLLERR)) {
LOGIFNEG1(shutdown(fsock_->fd, SHUT_RD));
fsock_ = NULL; /* plm destroys it */
} else if (fds[2].revents & POLLIN) {
freplenish(fsock_);
}
} }
} else if (errno == EINTR) { } else if (errno == EINTR) {
DEBUGF("poll() → EINTR"); DEBUGF("poll() → EINTR");