mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Further refine documentation
This commit is contained in:
parent
1bc3a25505
commit
548dcb9f08
27 changed files with 389 additions and 1478 deletions
8
Makefile
8
Makefile
|
@ -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
|
||||||
#
|
#
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
120
examples/fld.c
120
examples/fld.c
|
@ -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
|
|
|
@ -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𝑥*/
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
22
libc/math.h
22
libc/math.h
|
@ -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_ */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
145
third_party/chibicc/as.c
vendored
145
third_party/chibicc/as.c
vendored
|
@ -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);
|
||||||
|
|
4
third_party/chibicc/chibicc.h
vendored
4
third_party/chibicc/chibicc.h
vendored
|
@ -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
|
||||||
|
|
7
third_party/chibicc/dox1.c
vendored
7
third_party/chibicc/dox1.c
vendored
|
@ -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
|
||||||
|
|
108
third_party/chibicc/dox2.c
vendored
108
third_party/chibicc/dox2.c
vendored
|
@ -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, "&");
|
fprintf(f, "&");
|
||||||
|
@ -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
Normal file
106
third_party/chibicc/file.c
vendored
Normal 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
Normal file
13
third_party/chibicc/file.h
vendored
Normal 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_ */
|
50
third_party/chibicc/parse.c
vendored
50
third_party/chibicc/parse.c
vendored
|
@ -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) {
|
||||||
|
|
1
third_party/chibicc/test/asm_test.c
vendored
1
third_party/chibicc/test/asm_test.c
vendored
|
@ -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│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
|
23
third_party/chibicc/test/vla_test.c
vendored
23
third_party/chibicc/test/vla_test.c
vendored
|
@ -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];
|
||||||
|
|
103
third_party/chibicc/tokenize.c
vendored
103
third_party/chibicc/tokenize.c
vendored
|
@ -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);
|
||||||
|
|
50
third_party/getopt/getopt.c
vendored
50
third_party/getopt/getopt.c
vendored
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
444
third_party/getopt/getopt_long.3
vendored
444
third_party/getopt/getopt_long.3
vendored
|
@ -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).
|
|
553
third_party/getopt/getopt_long.c
vendored
553
third_party/getopt/getopt_long.c
vendored
|
@ -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));
|
|
||||||
}
|
|
3
third_party/getopt/initgetopt.S
vendored
3
third_party/getopt/initgetopt.S
vendored
|
@ -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
|
||||||
|
|
|
@ -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), "𝑒ˣ")
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in a new issue