mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Improve performance of printf functions
This commit is contained in:
parent
b107d2709f
commit
dc6d11a031
39 changed files with 577 additions and 650 deletions
|
@ -8,9 +8,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main() {
|
||||
printf("%s \n", "hello world");
|
||||
printf("%`'s\n", "hello\1\2world→→");
|
||||
return errno;
|
||||
}
|
||||
|
|
|
@ -228,6 +228,7 @@ int gethostname_bsd(char *, size_t) hidden;
|
|||
int gethostname_nt(char *, size_t) hidden;
|
||||
size_t __iovec_size(const struct iovec *, size_t) hidden;
|
||||
void __rusage2linux(struct rusage *) hidden;
|
||||
ssize_t WritevUninterruptible(int, struct iovec *, int);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
||||
|
|
|
@ -70,10 +70,6 @@ long double ConvertTicksToNanos(uint64_t ticks) {
|
|||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
static long double ConvertTicksToSeconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * ConvertTicksToNanos(ticks);
|
||||
}
|
||||
|
||||
long double nowl_sys(void) {
|
||||
return dtime(CLOCK_REALTIME);
|
||||
}
|
||||
|
@ -82,5 +78,5 @@ long double nowl_art(void) {
|
|||
uint64_t ticks;
|
||||
if (!g_now.once) RefreshTime();
|
||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||
return g_now.r0 + ConvertTicksToSeconds(ticks);
|
||||
return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn));
|
||||
}
|
||||
|
|
|
@ -22,43 +22,55 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct VdprintfState {
|
||||
int n;
|
||||
int fd;
|
||||
unsigned char buf[1024];
|
||||
int n, t, fd;
|
||||
char b[1024];
|
||||
};
|
||||
|
||||
static int vdprintf_flush(struct VdprintfState *df, int n) {
|
||||
int i, rc;
|
||||
for (i = 0; i < n; i += rc) {
|
||||
if ((rc = write(df->fd, df->buf + i, n - i)) == -1) {
|
||||
static int vdprintf_putc(const char *s, struct VdprintfState *t, size_t n) {
|
||||
struct iovec iov[2];
|
||||
if (n) {
|
||||
if (t->n + n < sizeof(t->b)) {
|
||||
memcpy(t->b + t->n, s, n);
|
||||
t->n += n;
|
||||
} else {
|
||||
iov[0].iov_base = t->b;
|
||||
iov[0].iov_len = t->n;
|
||||
iov[1].iov_base = s;
|
||||
iov[1].iov_len = n;
|
||||
if (WritevUninterruptible(t->fd, iov, 2) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t->t += t->n;
|
||||
t->n = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdprintf_putc(int c, struct VdprintfState *df) {
|
||||
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
|
||||
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
return vdprintf_flush(df, ARRAYLEN(df->buf));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats string directly to system i/o device.
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
||||
struct VdprintfState df;
|
||||
df.n = 0;
|
||||
df.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &df, fmt, va) == -1) return -1;
|
||||
if (vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) == -1) return -1;
|
||||
return df.n;
|
||||
struct iovec iov[1];
|
||||
struct VdprintfState t;
|
||||
t.n = 0;
|
||||
t.t = 0;
|
||||
t.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &t, fmt, va) == -1) return -1;
|
||||
if (t.n) {
|
||||
iov[0].iov_base = t.b;
|
||||
iov[0].iov_len = t.n;
|
||||
if (WritevUninterruptible(t.fd, iov, 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t.t += t.n;
|
||||
}
|
||||
return t.t;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,28 +16,30 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/notice.inc"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
||||
// Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
||||
//
|
||||
// @param edi is the initial hash value (0 is fine)
|
||||
// @param rsi points to the data
|
||||
// @param rdx is the byte size of data
|
||||
// @return eax is the new hash value
|
||||
// @note Used by ISCSI, TensorFlow, etc.
|
||||
.initbss 300,_init_crc32c
|
||||
crc32c: .quad 0
|
||||
.endobj crc32c,globl
|
||||
.previous
|
||||
|
||||
.init.start 300,_init_crc32c
|
||||
ezlea crc32c_pure,ax
|
||||
ezlea crc32c_sse42,cx
|
||||
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
|
||||
cmovnz %rcx,%rax
|
||||
stosq
|
||||
.init.end 300,_init_crc32c
|
||||
.source __FILE__
|
||||
ssize_t WritevUninterruptible(int fd, struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
do {
|
||||
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
||||
wrote = rc;
|
||||
do {
|
||||
if (wrote >= iov->iov_len) {
|
||||
wrote -= iov->iov_len;
|
||||
++iov;
|
||||
--iovlen;
|
||||
} else {
|
||||
iov->iov_base = (char *)iov->iov_base + wrote;
|
||||
iov->iov_len -= wrote;
|
||||
wrote = 0;
|
||||
}
|
||||
} while (wrote);
|
||||
} else if (errno != EINTR) {
|
||||
return -1;
|
||||
}
|
||||
} while (iovlen);
|
||||
return 0;
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
@ -33,7 +34,8 @@
|
|||
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
if (out(C, arg) == -1) { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -121,14 +123,18 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
uint32_t u[2];
|
||||
uint64_t q;
|
||||
} pun;
|
||||
long ld;
|
||||
void *p;
|
||||
unsigned u;
|
||||
char ibuf[21];
|
||||
bool longdouble;
|
||||
long double ldbl;
|
||||
unsigned long lu;
|
||||
wchar_t charbuf[1];
|
||||
const char *alphabet;
|
||||
int (*out)(long, void *);
|
||||
int (*out)(const char *, void *, size_t);
|
||||
unsigned char signbit, log2base;
|
||||
int c, d, k, w, i1, ui, bw, bex;
|
||||
int c, d, k, w, n, i1, ui, bw, bex;
|
||||
char *s, *q, *se, qchar, special[8];
|
||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||
|
||||
|
@ -136,18 +142,64 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
out = fn ? fn : (void *)missingno;
|
||||
|
||||
while (*format) {
|
||||
/* %[flags][width][.prec][length] */
|
||||
if (*format != '%') {
|
||||
/* no */
|
||||
PUT(*format);
|
||||
format++;
|
||||
for (n = 1; format[n]; ++n) {
|
||||
if (format[n] == '%') break;
|
||||
}
|
||||
if (out(format, arg, n) == -1) return -1;
|
||||
format += n;
|
||||
continue;
|
||||
} else {
|
||||
/* yes, evaluate it */
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate flags */
|
||||
if (!IsTiny()) {
|
||||
if (format[1] == 's') { /* FAST PATH: PLAIN STRING */
|
||||
s = va_arg(va, char *);
|
||||
if (!s) s = "(null)";
|
||||
if (out(s, arg, strlen(s)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
||||
d = va_arg(va, int);
|
||||
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix16(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'x') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN LONG HEX */
|
||||
if (out(ibuf, arg, uint64toarray_radix16(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||
n = va_arg(va, unsigned); /* FAST PATH: PRECISION STRING */
|
||||
s = va_arg(va, const char *);
|
||||
if (!s) s = "(null)", n = MIN(6, n);
|
||||
if (out(s, arg, n) == -1) return -1;
|
||||
format += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* GENERAL PATH */
|
||||
format++;
|
||||
sign = 0;
|
||||
flags = 0;
|
||||
getflag:
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int __fmt_pad(int (*)(long, void *), void *, unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(long, void *), void *, void *, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char,
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(long, void *), void *, va_list, unsigned char,
|
||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||
unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||
const char *) hidden;
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||
unsigned char, const char *) hidden;
|
||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
@ -25,12 +26,11 @@
|
|||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||
unsigned len, bool negative, unsigned log2base,
|
||||
unsigned prec, unsigned width,
|
||||
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||
char *buf, unsigned len, bool negative,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
idx = 0;
|
||||
unsigned i;
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
|
@ -82,24 +82,21 @@ static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
|||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (i = 0U; i < len; i++) {
|
||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
reverse(buf, len);
|
||||
if (out(buf, arg, len) == -1) return -1;
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (idx < width) {
|
||||
if (__fmt_pad(out, arg, width - idx) == -1) return -1;
|
||||
if (len < width) {
|
||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned flags, const char *alphabet) {
|
||||
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned flags, const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
|
@ -130,7 +127,7 @@ int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
|||
flags);
|
||||
}
|
||||
|
||||
int __fmt_ntoa(int out(long, void *), void *arg, va_list va,
|
||||
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,
|
||||
unsigned char signbit, unsigned long log2base,
|
||||
unsigned long prec, unsigned long width, unsigned char flags,
|
||||
const char *lang) {
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
||||
int __fmt_pad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||
unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(" ", arg, 1);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/tinystrlen.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
|
@ -26,56 +29,50 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
|
||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
||||
typedef int (*out_f)(const char *, void *, size_t);
|
||||
typedef int (*emit_f)(out_f, void *, uint64_t);
|
||||
|
||||
static noinstrument int __fmt_stoa_byte(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return f(c, a);
|
||||
static int __fmt_stoa_byte(out_f out, void *a, uint64_t c) {
|
||||
char buf[1] = {c};
|
||||
return out(buf, a, 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_word(int f(long, void *), void *a,
|
||||
uint64_t w) {
|
||||
do {
|
||||
if (f(w & 0xff, a) == -1) {
|
||||
return -1;
|
||||
static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (!isascii(w)) w = tpenc(w);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (w <= 0x7F) {
|
||||
if (w < 0x20 || w == 0x7F) {
|
||||
w = cescapec(w);
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_wide(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return f(c, a);
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
w = tpenc(w);
|
||||
}
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_bing(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return __fmt_stoa_wide(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quoted(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return __fmt_stoa_word(f, a, cescapec(c));
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||
unsigned flags, char ch,
|
||||
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out('L', arg) == -1) return -1;
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out('u', arg) == -1) return -1;
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
if (out(ch, arg) == -1) return -1;
|
||||
if (out(&ch, arg, 1) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -89,23 +86,25 @@ static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
|||
*
|
||||
* @see __fmt()
|
||||
*/
|
||||
int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||
int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||
unsigned long flags, unsigned long precision,
|
||||
unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
char *p;
|
||||
wint_t wc;
|
||||
unsigned n;
|
||||
emit_f emit;
|
||||
char *p, buf[1];
|
||||
unsigned w, c, pad;
|
||||
bool justdobytes, ignorenul;
|
||||
|
||||
p = data;
|
||||
if (!p) {
|
||||
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
||||
flags &= ~FLAGS_PRECISION;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
signbit = 0;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
precision = min(strlen(p), precision);
|
||||
}
|
||||
} else {
|
||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
|
@ -215,7 +214,8 @@ int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
|||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
if (out(qchar, arg) == -1) return -1;
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
struct SprintfStr {
|
||||
|
@ -28,10 +28,13 @@ struct SprintfStr {
|
|||
size_t n;
|
||||
};
|
||||
|
||||
static noinstrument int vsnprintfputchar(unsigned char c,
|
||||
struct SprintfStr *str) {
|
||||
if (str->i < str->n) str->p[str->i] = c;
|
||||
str->i++;
|
||||
static int vsnprintfputchar(const char *s, struct SprintfStr *t, size_t n) {
|
||||
if (t->i + n <= t->n) {
|
||||
memcpy(t->p + t->i, s, n);
|
||||
} else if (t->i < t->n) {
|
||||
memcpy(t->p + t->i, s, t->n - t->i);
|
||||
}
|
||||
t->i += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,6 +54,6 @@ static noinstrument int vsnprintfputchar(unsigned char c,
|
|||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||
struct SprintfStr str = {buf, 0, size};
|
||||
__fmt(vsnprintfputchar, &str, fmt, va);
|
||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
||||
if (str.n) str.p[MIN(str.i, str.n - 1)] = '\0';
|
||||
return str.i;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
|
@ -43,17 +46,8 @@
|
|||
bool cancolor(void) {
|
||||
static bool once;
|
||||
static bool result;
|
||||
const char *term;
|
||||
if (!once) {
|
||||
if (!result) {
|
||||
if ((term = getenv("TERM"))) {
|
||||
/* anything but emacs basically */
|
||||
result = strcmp(term, "dumb") != 0;
|
||||
} else {
|
||||
/* TODO(jart): Why does Mac bash login shell exec nuke TERM? */
|
||||
result = IsXnu();
|
||||
}
|
||||
}
|
||||
result = !!strcmp(nulltoempty(getenv("DONTANSIMEBRO")), "1");
|
||||
once = true;
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Checks if we're probably running inside Emacs.
|
||||
*/
|
||||
bool IsTerminalInarticulate(void) {
|
||||
return strcmp(nulltoempty(getenv("TERM")), "dumb") == 0;
|
||||
return !strcmp(nulltoempty(getenv("TERM")), "dumb");
|
||||
}
|
||||
|
|
|
@ -29,26 +29,26 @@
|
|||
* @see xasprintf() for a better API
|
||||
*/
|
||||
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
||||
int wrote;
|
||||
char *p;
|
||||
size_t size;
|
||||
va_list va2;
|
||||
va_list vb;
|
||||
int wrote, rc = -1;
|
||||
if ((*strp = malloc((size = 512)))) {
|
||||
va_copy(va2, va);
|
||||
va_copy(vb, va);
|
||||
wrote = (vsnprintf)(*strp, size, fmt, va);
|
||||
if (wrote == -1) return -1;
|
||||
if (wrote < size) {
|
||||
if ((p = realloc(*strp, wrote + 1))) *strp = p;
|
||||
return wrote;
|
||||
rc = wrote;
|
||||
} else {
|
||||
size = wrote + 1;
|
||||
if ((p = realloc(*strp, size))) {
|
||||
*strp = p;
|
||||
wrote = (vsnprintf)(*strp, size, fmt, va2);
|
||||
wrote = (vsnprintf)(*strp, size, fmt, vb);
|
||||
assert(wrote == size - 1);
|
||||
return wrote;
|
||||
rc = wrote;
|
||||
}
|
||||
}
|
||||
va_end(vb);
|
||||
}
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
// @param dil contains byte to escape
|
||||
// @see libc/nexgen32e/cescapec.c
|
||||
cescapec:
|
||||
.leafprologue
|
||||
.profilable
|
||||
movzbl %dil,%edi
|
||||
lea -7(%rdi),%ecx
|
||||
cmp $85,%cl
|
||||
|
@ -36,28 +38,28 @@ cescapec:
|
|||
jmp *cescapectab(,%rcx,8)
|
||||
.Lanchorpoint:
|
||||
.LBEL: mov $'a',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LBS: mov $'b',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LHT: mov $'t',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LLF: mov $'n',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LVT: mov $'v',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LFF: mov $'f',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LCR: mov $'r',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LDQ: mov $'\"',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LSQ: mov $'\'',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LBSL: mov $'\\',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
#ifdef __STRICT_ANSI__
|
||||
.LQM: mov $'?',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
#else
|
||||
.LQM:
|
||||
#endif
|
||||
|
@ -65,7 +67,7 @@ cescapec:
|
|||
lea -0x20(%rax),%ecx
|
||||
cmp $0x5E,%ecx
|
||||
ja 2f
|
||||
ret
|
||||
.leafepilogue
|
||||
2: and $-64,%eax
|
||||
mov %edi,%ecx
|
||||
and $56,%ecx
|
||||
|
@ -75,7 +77,7 @@ cescapec:
|
|||
or %ecx,%edi
|
||||
lea (%rdi,%rax,4),%eax
|
||||
add $'0'<<030|'0'<<020|'0'<<010|'\\',%eax
|
||||
ret
|
||||
.leafepilogue
|
||||
.endfn cescapec,globl
|
||||
|
||||
.initro 300,_init_cescapec
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const uint32_t kCrc32cTab[256];
|
||||
|
||||
void crc32init(uint32_t[hasatleast 256], uint32_t);
|
||||
uint32_t crc32c(uint32_t, const void *, size_t);
|
||||
uint32_t crc32_z(uint32_t, const void *, size_t);
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
// @return rax is address of last %sil in %rdi, or NULL
|
||||
// @note AVX2 requires Haswell (2014+) or Excavator (2015+)
|
||||
// @asyncsignalsafe
|
||||
memrchr:.leafprologue
|
||||
memrchr:
|
||||
.leafprologue
|
||||
.profilable
|
||||
#if !IsTiny()
|
||||
cmp $32,%rdx
|
||||
|
|
|
@ -106,37 +106,7 @@ privileged noasan void ftrace(void) {
|
|||
noreentry = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables plaintext function tracing if `--ftrace` flag is passed.
|
||||
*
|
||||
* The `--ftrace` CLI arg is removed before main() is called. This code
|
||||
* is intended for diagnostic purposes and assumes binaries are
|
||||
* trustworthy and stack isn't corrupted. Logging plain text allows
|
||||
* program structure to easily be visualized and hotspots identified w/
|
||||
* `sed | sort | uniq -c | sort`. A compressed trace can be made by
|
||||
* appending `--ftrace 2>&1 | gzip -4 >trace.gz` to the CLI arguments.
|
||||
*
|
||||
* @see libc/runtime/_init.S for documentation
|
||||
*/
|
||||
textstartup int ftrace_init(int argc, char *argv[]) {
|
||||
int i;
|
||||
bool foundflag;
|
||||
foundflag = false;
|
||||
for (i = 1; i <= argc; ++i) {
|
||||
if (!foundflag) {
|
||||
if (argv[i]) {
|
||||
if (strcmp(argv[i], "--ftrace") == 0) {
|
||||
foundflag = true;
|
||||
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
||||
strcpy(argv[i], "--ftrace");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
argv[i - 1] = argv[i];
|
||||
}
|
||||
}
|
||||
if (foundflag) {
|
||||
--argc;
|
||||
textstartup void ftrace_install(void) {
|
||||
g_buf[0] = '+';
|
||||
g_buf[1] = ' ';
|
||||
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
|
||||
|
@ -144,6 +114,4 @@ textstartup int ftrace_init(int argc, char *argv[]) {
|
|||
} else {
|
||||
write(2, "error: --ftrace needs the concomitant .com.dbg binary\n", 54);
|
||||
}
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
|
56
libc/runtime/ftraceinit.c
Normal file
56
libc/runtime/ftraceinit.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Enables plaintext function tracing if `--ftrace` flag is passed.
|
||||
*
|
||||
* The `--ftrace` CLI arg is removed before main() is called. This code
|
||||
* is intended for diagnostic purposes and assumes binaries are
|
||||
* trustworthy and stack isn't corrupted. Logging plain text allows
|
||||
* program structure to easily be visualized and hotspots identified w/
|
||||
* `sed | sort | uniq -c | sort`. A compressed trace can be made by
|
||||
* appending `--ftrace 2>&1 | gzip -4 >trace.gz` to the CLI arguments.
|
||||
*
|
||||
* @see libc/runtime/_init.S for documentation
|
||||
*/
|
||||
textstartup int ftrace_init(int argc, char *argv[]) {
|
||||
int i;
|
||||
bool foundflag;
|
||||
foundflag = false;
|
||||
for (i = 1; i <= argc; ++i) {
|
||||
if (!foundflag) {
|
||||
if (argv[i]) {
|
||||
if (strcmp(argv[i], "--ftrace") == 0) {
|
||||
foundflag = true;
|
||||
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
||||
strcpy(argv[i], "--ftrace");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
argv[i - 1] = argv[i];
|
||||
}
|
||||
}
|
||||
if (foundflag) {
|
||||
--argc;
|
||||
ftrace_install();
|
||||
}
|
||||
return argc;
|
||||
}
|
|
@ -88,6 +88,7 @@ void _weakfree(void *);
|
|||
void free_s(void *) paramsnonnull() libcesque;
|
||||
int close_s(int *) paramsnonnull() libcesque;
|
||||
int OpenExecutable(void);
|
||||
void ftrace_install(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
|
@ -28,30 +29,6 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
do {
|
||||
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
||||
wrote = rc;
|
||||
do {
|
||||
if (wrote >= iov->iov_len) {
|
||||
wrote -= iov->iov_len;
|
||||
++iov;
|
||||
--iovlen;
|
||||
} else {
|
||||
iov->iov_base = (char *)iov->iov_base + wrote;
|
||||
iov->iov_len -= wrote;
|
||||
wrote = 0;
|
||||
}
|
||||
} while (wrote);
|
||||
} else if (errno != EINTR) {
|
||||
return -1;
|
||||
}
|
||||
} while (iovlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to stream.
|
||||
*
|
||||
|
@ -102,7 +79,7 @@ size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
|||
iov[1].iov_base = data;
|
||||
iov[1].iov_len = n;
|
||||
n += f->beg;
|
||||
if (WritevAll(f->fd, iov, 2) == -1) {
|
||||
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
|
||||
f->state = errno;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -26,9 +27,17 @@ struct state {
|
|||
int n;
|
||||
};
|
||||
|
||||
static noinstrument int vfprintfputchar(int c, struct state *st) {
|
||||
st->n++;
|
||||
return fputc(c, st->f);
|
||||
static int vfprintfputchar(const char *s, struct state *t, size_t n) {
|
||||
if (n) {
|
||||
if (n == 1 && *s != '\n' && t->f->beg < t->f->size &&
|
||||
t->f->bufmode != _IONBF) {
|
||||
t->f->buf[t->f->beg++] = *s;
|
||||
} else if (!fwrite(s, 1, n, t->f)) {
|
||||
return -1;
|
||||
}
|
||||
t->n += n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
|
||||
extern const uint32_t kCrc32cTab[256];
|
||||
|
||||
/**
|
||||
* Computes Castagnoli CRC-32 on old computers.
|
||||
*/
|
||||
uint32_t crc32c_pure(uint32_t init, const void *data, size_t size) {
|
||||
const unsigned char *p = data;
|
||||
uint32_t h = init ^ 0xffffffff;
|
||||
unsigned i;
|
||||
for (i = 0; i < size; i++) {
|
||||
h = h >> 8 ^ kCrc32cTab[(h & 0xff) ^ p[i]];
|
||||
}
|
||||
return h ^ 0xffffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
bench_crc32c_pure for #c per n where c ≈ 0.293ns
|
||||
N x1 x8 x64 mBps
|
||||
------------------------------------------------------------
|
||||
1 4305.000 91.375 44.203 74
|
||||
1 75.000 55.875 44.703 73
|
||||
2 46.500 35.188 24.617 132
|
||||
3 40.333 26.625 19.193 169
|
||||
4 32.250 19.969 16.215 200
|
||||
7 18.429 15.089 12.033 270
|
||||
8 20.625 13.547 11.607 280
|
||||
15 15.667 10.775 9.589 339
|
||||
16 17.562 10.695 9.419 345
|
||||
31 12.226 8.891 8.317 391
|
||||
32 13.219 8.480 8.078 402
|
||||
63 9.571 8.065 7.731 420
|
||||
64 9.672 7.955 7.633 426
|
||||
127 8.433 7.548 7.329 443
|
||||
128 8.492 7.528 7.352 442
|
||||
255 7.557 7.366 7.239 449
|
||||
256 7.699 7.342 7.305 445
|
||||
511 7.376 7.243 7.223 450
|
||||
512 7.408 7.233 7.225 450
|
||||
1023 7.188 7.192 7.098 458
|
||||
1024 7.171 7.194 7.097 458
|
||||
2047 7.130 7.172 7.085 459
|
||||
2048 7.117 7.170 7.169 453
|
||||
4095 7.063 7.076 7.085 459
|
||||
4096 7.078 7.161 7.081 459
|
||||
8191 7.041 7.095 7.055 461
|
||||
8192 7.051 7.098 7.087 459
|
||||
16383 7.039 7.114 7.067 460
|
||||
16384 6.876 6.931 7.133 456
|
||||
32767 7.055 7.108 7.290 446
|
||||
32768 6.868 6.887 6.974 466
|
||||
65535 6.984 6.885 6.967 467
|
||||
65536 6.877 6.924 10.994 296
|
||||
131071 7.166 7.141 7.011 464
|
||||
131072 6.853 6.971 7.694 422
|
||||
262143 6.853 7.213 7.406 439
|
||||
262144 6.852 6.968 7.290 446
|
||||
524287 7.398 7.389 7.166 454
|
||||
524288 6.851 7.094 7.159 454
|
||||
*/
|
|
@ -1,95 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/internal.h"
|
||||
|
||||
/**
|
||||
* Hashes data with hardware acceleration at 10GBps.
|
||||
* @note needs Nehalem+ c. 2008 or Bulldozer+ c. 2011
|
||||
*/
|
||||
optimizespeed uint32_t crc32c_sse42(uint32_t init, const void *data, size_t n) {
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
const unsigned char *pe = (const unsigned char *)data + n;
|
||||
uint32_t h = init ^ 0xffffffff;
|
||||
if (n >= 16 + 8) {
|
||||
while ((uintptr_t)p & 7) asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||
uint64_t hl = h;
|
||||
while (p < pe - 16ul) {
|
||||
asm("crc32q\t%1,%0" : "+r"(hl) : "rm"(*(const uint64_t *)p));
|
||||
p += 8;
|
||||
asm("crc32q\t%1,%0" : "+r"(hl) : "rm"(*(const uint64_t *)p));
|
||||
p += 8;
|
||||
}
|
||||
h = (uint32_t)hl;
|
||||
}
|
||||
while (p < pe) asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||
return h ^ 0xffffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
bench_crc32c_sse42 for #c per n where c ≈ 0.293ns
|
||||
N x1 x8 x64 mBps
|
||||
------------------------------------------------------------
|
||||
1 877.000 43.375 40.359 81
|
||||
1 45.000 39.625 40.484 80
|
||||
2 34.500 27.562 20.461 159
|
||||
3 23.000 16.708 14.245 228
|
||||
4 18.250 13.094 11.449 284
|
||||
7 10.429 8.339 8.185 397
|
||||
8 42.125 8.734 6.850 475
|
||||
15 9.400 5.375 4.884 665
|
||||
16 7.312 5.070 4.882 666
|
||||
31 5.258 2.923 2.680 1213
|
||||
32 3.969 2.676 2.562 1269
|
||||
63 3.095 1.581 1.428 2276
|
||||
64 2.234 1.623 1.478 2199
|
||||
127 1.205 0.901 0.900 3610
|
||||
128 1.164 0.960 0.915 3552
|
||||
255 0.922 0.651 0.618 5260
|
||||
256 0.715 0.650 0.609 5341
|
||||
511 0.558 0.482 0.477 6819
|
||||
512 0.529 0.475 0.469 6932
|
||||
1023 0.425 0.400 0.396 8204
|
||||
1024 0.417 0.392 0.388 8383
|
||||
2047 0.367 0.355 0.353 9199
|
||||
2048 0.374 0.366 0.364 8929
|
||||
4095 0.351 0.338 0.337 9644
|
||||
4096 0.353 0.338 0.338 9624
|
||||
8191 0.335 0.338 0.337 9641
|
||||
8192 0.335 0.329 0.329 9870
|
||||
16383 0.336 0.325 0.325 10011
|
||||
16384 0.336 0.326 0.375 8666
|
||||
32767 0.329 0.323 0.323 10070
|
||||
32768 0.327 0.324 0.323 10062
|
||||
65535 0.322 0.322 0.322 10103
|
||||
65536 0.321 0.322 0.322 10102
|
||||
131071 0.322 0.321 0.321 10125
|
||||
131072 0.321 0.321 0.321 10124
|
||||
262143 0.322 0.321 0.335 9699
|
||||
262144 0.321 0.321 0.321 10134
|
||||
524287 0.321 0.321 0.499 6516
|
||||
524288 0.321 0.321 0.339 9575
|
||||
1048575 0.322 0.321 0.322 10095
|
||||
1048576 0.320 1.001 0.323 10048
|
||||
2097151 0.325 0.321 0.322 10086
|
||||
2097152 0.330 0.320 0.323 10076
|
||||
4194303 0.331 0.322 0.321 10128
|
||||
4194304 0.332 0.321 0.325 10004
|
||||
8388607 0.334 0.332 0.331 9829
|
||||
8388608 0.334 0.329 0.327 9934
|
||||
*/
|
|
@ -22,16 +22,29 @@
|
|||
/**
|
||||
* Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
||||
*
|
||||
* @param h is the initial hash value (0 is fine)
|
||||
* @param p points to the data
|
||||
* @param n is the byte size of data
|
||||
* @param init is the initial hash value
|
||||
* @param data points to the data
|
||||
* @param size is the byte size of data
|
||||
* @return eax is the new hash value
|
||||
* @note Used by ISCSI, TensorFlow, etc.
|
||||
*/
|
||||
uint32_t crc32c(uint32_t h, const void *p, size_t n) {
|
||||
uint32_t crc32c(uint32_t init, const void *data, size_t size) {
|
||||
uint64_t h;
|
||||
const unsigned char *p, *pe;
|
||||
p = data;
|
||||
pe = p + size;
|
||||
h = init ^ 0xffffffff;
|
||||
if (X86_HAVE(SSE4_2)) {
|
||||
return crc32c_sse42(h, p, n);
|
||||
} else {
|
||||
return crc32c_pure(h, p, n);
|
||||
for (; p + 8 <= pe; p += 8) {
|
||||
asm("crc32q\t%1,%0" : "+r"(h) : "rm"(*(const uint64_t *)p));
|
||||
}
|
||||
while (p < pe) {
|
||||
asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||
}
|
||||
} else {
|
||||
while (p < pe) {
|
||||
h = h >> 8 ^ kCrc32cTab[(h & 0xff) ^ *p++];
|
||||
}
|
||||
}
|
||||
return h ^ 0xffffffff;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static noasan size_t stpcpy_sse2(char *d, const char *s, size_t i) {
|
||||
static inline noasan size_t stpcpy_sse2(char *d, const char *s, size_t i) {
|
||||
uint8_t v1[16], v2[16], vz[16];
|
||||
for (;;) {
|
||||
memset(vz, 0, 16);
|
||||
|
|
|
@ -26,11 +26,11 @@
|
|||
*/
|
||||
int CategorizeIp(uint32_t x) {
|
||||
int a;
|
||||
if (IsAnonymousIp(x)) return kIpAnonymous;
|
||||
if (IsMulticastIp(x)) return kIpMulticast;
|
||||
if (IsLoopbackIp(x)) return kIpLoopback;
|
||||
if (IsPrivateIp(x)) return kIpPrivate;
|
||||
if (IsTestnetIp(x)) return kIpTestnet;
|
||||
if (IsMulticastIp(x)) return kIpMulticast;
|
||||
if (IsAnonymousIp(x)) return kIpAnonymous; /* order matters */
|
||||
if (IsTestnetIp(x)) return kIpTestnet; /* order matters */
|
||||
if (IsAfrinicIp(x)) return kIpAfrinic;
|
||||
if (IsLacnicIp(x)) return kIpLacnic;
|
||||
if (IsApnicIp(x)) return kIpApnic;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* ANSI-C code produced by gperf version 3.1 */
|
||||
/* Command-line: gperf gethttpheader.gperf */
|
||||
/* Computed positions: -k'3-4,10' */
|
||||
/* clang-format off */
|
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
|
@ -71,7 +72,7 @@ static unsigned char gperf_downcase[256] =
|
|||
|
||||
#ifndef GPERF_CASE_STRNCMP
|
||||
#define GPERF_CASE_STRNCMP 1
|
||||
static int
|
||||
static inline int
|
||||
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
||||
{
|
||||
for (; n > 0;)
|
||||
|
@ -152,7 +153,7 @@ hash (register const char *str, register size_t len)
|
|||
return hval;
|
||||
}
|
||||
|
||||
const struct thatispacked HttpHeaderSlot *
|
||||
static inline const struct thatispacked HttpHeaderSlot *
|
||||
LookupHttpHeader (register const char *str, register size_t len)
|
||||
{
|
||||
static const struct thatispacked HttpHeaderSlot wordlist[] =
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* ANSI-C code produced by gperf version 3.1 */
|
||||
/* Command-line: gperf gethttpmethod.gperf */
|
||||
/* Computed positions: -k'1-2' */
|
||||
/* clang-format off */
|
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
|
@ -71,7 +72,7 @@ static unsigned char gperf_downcase[256] =
|
|||
|
||||
#ifndef GPERF_CASE_STRNCMP
|
||||
#define GPERF_CASE_STRNCMP 1
|
||||
static int
|
||||
static inline int
|
||||
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
||||
{
|
||||
for (; n > 0;)
|
||||
|
@ -131,7 +132,7 @@ hash (register const char *str, register size_t len)
|
|||
return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
|
||||
}
|
||||
|
||||
const struct HttpMethodSlot *
|
||||
static inline const struct HttpMethodSlot *
|
||||
LookupHttpMethod (register const char *str, register size_t len)
|
||||
{
|
||||
static const struct HttpMethodSlot wordlist[] =
|
||||
|
@ -153,7 +154,7 @@ LookupHttpMethod (register const char *str, register size_t len)
|
|||
{""},
|
||||
#line 27 "gethttpmethod.gperf"
|
||||
{"NOTIFY", kHttpNotify},
|
||||
#line 20 "gethttpmethod.gperf"
|
||||
#line 19 "gethttpmethod.gperf"
|
||||
{"OPTIONS", kHttpOptions},
|
||||
{""},
|
||||
#line 22 "gethttpmethod.gperf"
|
||||
|
@ -162,7 +163,7 @@ LookupHttpMethod (register const char *str, register size_t len)
|
|||
{"MERGE", kHttpMerge},
|
||||
#line 29 "gethttpmethod.gperf"
|
||||
{"REPORT", kHttpReport},
|
||||
#line 19 "gethttpmethod.gperf"
|
||||
#line 20 "gethttpmethod.gperf"
|
||||
{"CONNECT", kHttpConnect},
|
||||
{""},
|
||||
#line 26 "gethttpmethod.gperf"
|
||||
|
|
|
@ -19,6 +19,26 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
// -_0-9A-Za-z
|
||||
static const char kHostChars[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 0x20
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 0x30
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 0x50
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 0x70
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if host seems legit.
|
||||
*
|
||||
|
@ -49,18 +69,11 @@
|
|||
*/
|
||||
bool IsAcceptableHost(const char *s, size_t n) {
|
||||
size_t i;
|
||||
bool isip;
|
||||
int c, b, j;
|
||||
if (n == -1) n = s ? strlen(s) : 0;
|
||||
if (!n) return true;
|
||||
for (isip = true, b = j = i = 0; i < n; ++i) {
|
||||
for (b = j = i = 0; i < n; ++i) {
|
||||
c = s[i] & 255;
|
||||
if (c == '.' && (!i || s[i - 1] == '.')) {
|
||||
return false;
|
||||
} else if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) {
|
||||
return false;
|
||||
}
|
||||
if (isip) {
|
||||
if (isdigit(c)) {
|
||||
b *= 10;
|
||||
b += c - '0';
|
||||
|
@ -68,14 +81,23 @@ bool IsAcceptableHost(const char *s, size_t n) {
|
|||
return false;
|
||||
}
|
||||
} else if (c == '.') {
|
||||
if (!i || s[i - 1] == '.') return false;
|
||||
b = 0;
|
||||
++j;
|
||||
} else {
|
||||
isip = false;
|
||||
for (;;) {
|
||||
if (!kHostChars[c] && (c != '.' || (!i || s[i - 1] == '.'))) {
|
||||
return false;
|
||||
}
|
||||
if (++i < n) {
|
||||
c = s[i] & 255;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isip && j != 3) return false;
|
||||
}
|
||||
if (j != 3) return false;
|
||||
if (i && s[i - 1] == '.') return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
|
||||
/**
|
||||
* Returns true if IPv4 address can come from the Internet.
|
||||
*
|
||||
* We intentionally omit TEST-NET here which can be used to simulate
|
||||
* public Internet traffic using non-Internet IPs.
|
||||
*/
|
||||
bool IsPublicIp(uint32_t x) {
|
||||
return !IsLoopbackIp(x) && !IsPrivateIp(x) && !IsTestnetIp(x);
|
||||
return !IsLoopbackIp(x) && !IsPrivateIp(x);
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ void DestroyHttpRequest(struct HttpRequest *r) {
|
|||
* fragmented. If a message is valid but incomplete, this function will
|
||||
* return zero so that it can be resumed as soon as more data arrives.
|
||||
*
|
||||
* This parser takes about 500 nanoseconds to parse a 403 byte Chrome
|
||||
* This parser takes about 400 nanoseconds to parse a 403 byte Chrome
|
||||
* HTTP request under MODE=rel on a Core i9 which is about three cycles
|
||||
* per byte or a gigabyte per second of throughput per core.
|
||||
*
|
||||
|
|
|
@ -40,6 +40,8 @@ TEST(uint64toarray_radix10, test) {
|
|||
char buf[21];
|
||||
EXPECT_EQ(1, uint64toarray_radix10(0, buf));
|
||||
EXPECT_STREQ("0", buf);
|
||||
EXPECT_EQ(4, uint64toarray_radix10(1024, buf));
|
||||
EXPECT_STREQ("1024", buf);
|
||||
EXPECT_EQ(20, uint64toarray_radix10(UINT64_MAX, buf));
|
||||
EXPECT_STREQ("18446744073709551615", buf);
|
||||
EXPECT_EQ(19, uint64toarray_radix10(INT64_MIN, buf));
|
||||
|
|
|
@ -38,8 +38,9 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
static char buffer[128];
|
||||
#define Format(...) gc(xasprintf(__VA_ARGS__))
|
||||
char buffer[1000];
|
||||
/* #define Format(...) gc(xasprintf(__VA_ARGS__)) */
|
||||
#define Format(...) (snprintf(buffer, sizeof(buffer), __VA_ARGS__), buffer)
|
||||
|
||||
TEST(sprintf, test_space_flag) {
|
||||
EXPECT_STREQ(" 42", Format("% d", 42));
|
||||
|
@ -593,32 +594,14 @@ TEST(snprintf, testFixedWidthString_wontOverrunInput) {
|
|||
TEST(snprintf, testFixedWidthStringIsNull_wontOverrunBuffer) {
|
||||
int N = 3;
|
||||
char *buf = malloc(N + 1);
|
||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"(nu ", buf);
|
||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%#.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"(nu ", buf);
|
||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"NUL ", buf);
|
||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`#.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"NUL ", buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
TEST(snprintf, testFixedWidthStringIsNull_wontLeakMemory) {
|
||||
int N = 16;
|
||||
char *buf = malloc(N + 1);
|
||||
memset(buf, 0, N + 1);
|
||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"(null) ", buf);
|
||||
memset(buf, 0, N + 1);
|
||||
EXPECT_EQ(6, snprintf(buf, N + 1, "%#.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"(null) ", buf);
|
||||
memset(buf, 0, N + 1);
|
||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"NULL ", buf);
|
||||
memset(buf, 0, N + 1);
|
||||
EXPECT_EQ(4, snprintf(buf, N + 1, "%`#.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_BINEQ(u"NULL ", buf);
|
||||
EXPECT_EQ(3, snprintf(buf, N + 1, "%.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_STREQ("(nu", buf);
|
||||
EXPECT_EQ(3, snprintf(buf, N + 1, "%#.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_STREQ("(nu", buf);
|
||||
EXPECT_EQ(3, snprintf(buf, N + 1, "%`'.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_STREQ("NUL", buf);
|
||||
EXPECT_EQ(3, snprintf(buf, N + 1, "%`#.*s", pushpop(N), pushpop(NULL)));
|
||||
EXPECT_STREQ("NUL", buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
|
@ -640,7 +623,9 @@ TEST(palandprintf, precisionStillRespectsNulTerminatorIfNotEscOrRepr) {
|
|||
}
|
||||
|
||||
BENCH(palandprintf, bench) {
|
||||
EZBENCH2("ascii", donothing, Format(VEIL("r", "hiuhcreohucreo")));
|
||||
EZBENCH2("ascii %s", donothing, Format("%s", VEIL("r", "hiuhcreohucreo")));
|
||||
EZBENCH2("ascii %`'s", donothing, Format("%`'s", VEIL("r", "hiuhcreohucre")));
|
||||
EZBENCH2("utf8 %s", donothing, Format("%s", VEIL("r", "hi (╯°□°)╯")));
|
||||
EZBENCH2("snprintf %hs", donothing, Format("%hs", VEIL("r", u"hi (╯°□°)╯")));
|
||||
EZBENCH2("snprintf %ls", donothing, Format("%ls", VEIL("r", L"hi (╯°□°)╯")));
|
||||
|
@ -648,6 +633,8 @@ BENCH(palandprintf, bench) {
|
|||
EZBENCH2("23 %d", donothing, Format("%d", VEIL("r", 23)));
|
||||
EZBENCH2("INT_MIN %x", donothing, Format("%x", VEIL("r", INT_MIN)));
|
||||
EZBENCH2("INT_MIN %d", donothing, Format("%d", VEIL("r", INT_MIN)));
|
||||
EZBENCH2("LONG_MIN %x", donothing, Format("%lx", VEIL("r", LONG_MIN)));
|
||||
EZBENCH2("LONG_MIN %d", donothing, Format("%ld", VEIL("r", LONG_MIN)));
|
||||
EZBENCH2("23 int64toarray", donothing, int64toarray_radix10(23, buffer));
|
||||
EZBENCH2("INT_MIN int64toarray", donothing,
|
||||
int64toarray_radix10(INT_MIN, buffer));
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define FANATICS "Fanatics"
|
||||
|
@ -40,12 +42,6 @@ TEST(crc32c, test) {
|
|||
strlen(hyperion) - strlen(FANATICS)));
|
||||
}
|
||||
|
||||
TEST(crc32c_pure, test) {
|
||||
EXPECT_EQ(0, crc32c_pure(0, "", 0));
|
||||
EXPECT_EQ(crc32c_pure(0, "hello", 5), crc32c_pure(0, "hello", 5));
|
||||
EXPECT_EQ(0xe3069283, crc32c_pure(0, "123456789", 9));
|
||||
EXPECT_EQ(0x6d6eefba, crc32c_pure(0, hyperion, strlen(hyperion)));
|
||||
EXPECT_EQ(0x6d6eefba, crc32c_pure(crc32c_pure(0, FANATICS, strlen(FANATICS)),
|
||||
hyperion + strlen(FANATICS),
|
||||
strlen(hyperion) - strlen(FANATICS)));
|
||||
BENCH(crc32c, bench) {
|
||||
EZBENCH2("crc32c", donothing, crc32c(0, kHyperion, kHyperionSize));
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ TEST(IsAcceptableHost, test) {
|
|||
EXPECT_FALSE(IsAcceptableHost("hello.example\300\200", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost(".", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost(".e", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("e.", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("e.", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost(".hi.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("hi..example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("hi-there.example", -1));
|
||||
|
@ -126,4 +126,6 @@ BENCH(IsAcceptableHost, bench) {
|
|||
EZBENCH2("IsAcceptablePort 80", donothing, IsAcceptablePort("80", 2));
|
||||
EZBENCH2("ParseForwarded 80", donothing,
|
||||
ParseForwarded("203.0.113.42:31337", 20, &ip, &port));
|
||||
EZBENCH2("IsAcceptableHost foo.example", donothing,
|
||||
IsAcceptableHost("foo.example:31337", 17));
|
||||
}
|
||||
|
|
|
@ -80,8 +80,12 @@ o/$(MODE)/tool/net/redbean.com: \
|
|||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/.init.lua tool/net/.reload.lua tool/net/favicon.ico tool/net/redbean.png
|
||||
|
||||
o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
||||
o/$(MODE)/tool/net/redbean.com.dbg
|
||||
@$(COMPILE) -ACP -T$@ cp $< $@
|
||||
|
||||
o/$(MODE)/tool/net/redbean-demo.com: \
|
||||
o/$(MODE)/tool/net/redbean.com.dbg \
|
||||
o/$(MODE)/tool/net/redbean-demo.com.dbg \
|
||||
tool/net/net.mk \
|
||||
tool/net/.init.lua \
|
||||
tool/net/.reload.lua \
|
||||
|
@ -114,16 +118,6 @@ o/$(MODE)/tool/net/redbean-static.com: \
|
|||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/favicon.ico tool/net/redbean.png
|
||||
|
||||
o/$(MODE)/tool/net/redbean-bench.com.dbg: \
|
||||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean.o \
|
||||
o/$(MODE)/tool/net/index.html.zip.o \
|
||||
o/$(MODE)/tool/net/redbean.lua.zip.o \
|
||||
o/$(MODE)/tool/net/net.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/net/redbean-static.com.dbg: \
|
||||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean-static.o \
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
@ -71,7 +72,11 @@
|
|||
#define HASH_LOAD_FACTOR /* 1. / */ 4
|
||||
#define DEFAULT_PORT 8080
|
||||
|
||||
#define read(F, P, N) readv(F, &(struct iovec){P, N}, 1)
|
||||
#define Hash(P, N) max(1, crc32c(0, P, N));
|
||||
#define LockInc(P) asm volatile("lock inc%z0\t%0" : "=m"(*(P)))
|
||||
#define AppendCrlf(P) mempcpy(P, "\r\n", 2)
|
||||
#define HasHeader(H) (!!msg.headers[H].a)
|
||||
#define HeaderData(H) (inbuf.p + msg.headers[H].a)
|
||||
#define HeaderLength(H) (msg.headers[H].b - msg.headers[H].a)
|
||||
#define HeaderEqualCase(H, S) \
|
||||
|
@ -171,7 +176,7 @@ static const char kRegCode[][9] = {
|
|||
};
|
||||
|
||||
struct Buffer {
|
||||
size_t n;
|
||||
size_t n, c;
|
||||
char *p;
|
||||
};
|
||||
|
||||
|
@ -327,6 +332,7 @@ static bool istext;
|
|||
static bool zombied;
|
||||
static bool gzipped;
|
||||
static bool branded;
|
||||
static bool funtrace;
|
||||
static bool meltdown;
|
||||
static bool heartless;
|
||||
static bool printport;
|
||||
|
@ -385,6 +391,7 @@ static struct Buffer effectivepath;
|
|||
|
||||
static struct Url url;
|
||||
static struct HttpRequest msg;
|
||||
static char slashpath[PATH_MAX];
|
||||
|
||||
static long double startread;
|
||||
static long double lastrefresh;
|
||||
|
@ -399,7 +406,7 @@ static wontreturn void PrintUsage(FILE *f, int rc) {
|
|||
fprintf(f, "\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
%s [-hvduzmba] [-p PORT] [-- SCRIPTARGS...]\n\
|
||||
%s [-hvduzmbagf] [-p PORT] [-- SCRIPTARGS...]\n\
|
||||
\n\
|
||||
DESCRIPTION\n\
|
||||
\n\
|
||||
|
@ -415,8 +422,11 @@ FLAGS\n\
|
|||
-m log messages\n\
|
||||
-b log message body\n\
|
||||
-a log resource usage\n\
|
||||
-g log handler latency\n\
|
||||
-H K:V sets http header globally [repeat]\n\
|
||||
-g log handler latency\n"
|
||||
#ifndef TINY
|
||||
" -f log worker function calls\n"
|
||||
#endif
|
||||
" -H K:V sets http header globally [repeat]\n\
|
||||
-D DIR serve assets from local directory [repeat]\n\
|
||||
-t MS tunes read and write timeouts [default 30000]\n\
|
||||
-c SEC configures static asset cache-control headers\n\
|
||||
|
@ -545,8 +555,6 @@ USAGE\n\
|
|||
then puts the original back once the program loads. If you want\n\
|
||||
your redbean to follow the platform-local executable convention\n\
|
||||
then delete the /.ape file from zip.\n\
|
||||
\n\
|
||||
LEGAL\n\
|
||||
\n\
|
||||
redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib\n\
|
||||
which makes it a permissively licensed gift to anyone who might\n\
|
||||
|
@ -664,38 +672,53 @@ static void UseOutput(void) {
|
|||
contentlength = outbuf.n;
|
||||
outbuf.p = 0;
|
||||
outbuf.n = 0;
|
||||
outbuf.c = 0;
|
||||
}
|
||||
|
||||
static void DropOutput(void) {
|
||||
free(outbuf.p);
|
||||
outbuf.p = 0;
|
||||
outbuf.n = 0;
|
||||
outbuf.c = 0;
|
||||
}
|
||||
|
||||
static void ClearOutput(void) {
|
||||
outbuf.n = 0;
|
||||
}
|
||||
|
||||
static void Grow(size_t n) {
|
||||
do {
|
||||
if (outbuf.c) {
|
||||
outbuf.c += outbuf.c >> 1;
|
||||
} else {
|
||||
outbuf.c = 16 * 1024;
|
||||
}
|
||||
} while (n > outbuf.c);
|
||||
outbuf.p = xrealloc(outbuf.p, outbuf.c);
|
||||
}
|
||||
|
||||
static void AppendData(const char *data, size_t size) {
|
||||
outbuf.p = xrealloc(outbuf.p, outbuf.n + size);
|
||||
size_t n;
|
||||
n = outbuf.n + size;
|
||||
if (n > outbuf.c) Grow(n);
|
||||
memcpy(outbuf.p + outbuf.n, data, size);
|
||||
outbuf.n += size;
|
||||
outbuf.n = n;
|
||||
}
|
||||
|
||||
static void AppendString(const char *s) {
|
||||
AppendData(s, strlen(s));
|
||||
}
|
||||
|
||||
static void AppendFmt(const char *fmt, ...) {
|
||||
static void Append(const char *fmt, ...) {
|
||||
int n;
|
||||
char *p;
|
||||
va_list va;
|
||||
va_list va, vb;
|
||||
va_start(va, fmt);
|
||||
n = vasprintf(&p, fmt, va);
|
||||
va_copy(vb, va);
|
||||
n = vsnprintf(outbuf.p + outbuf.n, outbuf.c - outbuf.n, fmt, va);
|
||||
if (n >= outbuf.c - outbuf.n) {
|
||||
Grow(outbuf.n + n + 1);
|
||||
vsnprintf(outbuf.p + outbuf.n, outbuf.c - outbuf.n, fmt, vb);
|
||||
}
|
||||
va_end(vb);
|
||||
va_end(va);
|
||||
CHECK_NE(-1, n);
|
||||
AppendData(p, n);
|
||||
free(p);
|
||||
outbuf.n += n;
|
||||
}
|
||||
|
||||
static char *MergePaths(const char *p, size_t n, const char *q, size_t m,
|
||||
|
@ -833,10 +856,6 @@ static void DescribeAddress(char buf[32], uint32_t addr, uint16_t port) {
|
|||
*p++ = '\0';
|
||||
}
|
||||
|
||||
static bool HasHeader(int h) {
|
||||
return !!msg.headers[h].a;
|
||||
}
|
||||
|
||||
static void GetServerAddr(uint32_t *ip, uint16_t *port) {
|
||||
*ip = ntohl(serveraddr.sin_addr.s_addr);
|
||||
if (port) *port = ntohs(serveraddr.sin_port);
|
||||
|
@ -975,7 +994,7 @@ static void ProgramHeader(const char *s) {
|
|||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "azhdugvmbl:p:r:R:H:c:L:P:U:G:B:D:t:")) !=
|
||||
while ((opt = getopt(argc, argv, "azhdugvmbfl:p:r:R:H:c:L:P:U:G:B:D:t:")) !=
|
||||
-1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
|
@ -1002,6 +1021,9 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
case 'z':
|
||||
printport = true;
|
||||
break;
|
||||
case 'f':
|
||||
funtrace = true;
|
||||
break;
|
||||
case 'k':
|
||||
encouragekeepalive = true;
|
||||
break;
|
||||
|
@ -1097,53 +1119,53 @@ static void AppendResourceReport(struct rusage *ru, const char *nl) {
|
|||
long utime, stime;
|
||||
long double ticks;
|
||||
if (ru->ru_maxrss) {
|
||||
AppendFmt("ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
|
||||
Append("ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
|
||||
}
|
||||
if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) |
|
||||
(stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) {
|
||||
ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK));
|
||||
AppendFmt("needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
|
||||
Append("needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
|
||||
(int)((long double)stime / (utime + stime) * 100), nl);
|
||||
if (ru->ru_idrss) {
|
||||
AppendFmt("needed %,ldkb memory on average%s",
|
||||
lroundl(ru->ru_idrss / ticks), nl);
|
||||
Append("needed %,ldkb memory on average%s", lroundl(ru->ru_idrss / ticks),
|
||||
nl);
|
||||
}
|
||||
if (ru->ru_isrss) {
|
||||
AppendFmt("needed %,ldkb stack on average%s",
|
||||
lroundl(ru->ru_isrss / ticks), nl);
|
||||
Append("needed %,ldkb stack on average%s", lroundl(ru->ru_isrss / ticks),
|
||||
nl);
|
||||
}
|
||||
if (ru->ru_ixrss) {
|
||||
AppendFmt("mapped %,ldkb shared on average%s",
|
||||
lroundl(ru->ru_ixrss / ticks), nl);
|
||||
Append("mapped %,ldkb shared on average%s", lroundl(ru->ru_ixrss / ticks),
|
||||
nl);
|
||||
}
|
||||
}
|
||||
if (ru->ru_minflt || ru->ru_majflt) {
|
||||
AppendFmt("caused %,ld page faults (%d%% memcpy)%s",
|
||||
Append("caused %,ld page faults (%d%% memcpy)%s",
|
||||
ru->ru_minflt + ru->ru_majflt,
|
||||
(int)((long double)ru->ru_minflt /
|
||||
(ru->ru_minflt + ru->ru_majflt) * 100),
|
||||
(int)((long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) *
|
||||
100),
|
||||
nl);
|
||||
}
|
||||
if (ru->ru_nvcsw + ru->ru_nivcsw > 1) {
|
||||
AppendFmt(
|
||||
Append(
|
||||
"%,ld context switches (%d%% consensual)%s",
|
||||
ru->ru_nvcsw + ru->ru_nivcsw,
|
||||
(int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100),
|
||||
nl);
|
||||
}
|
||||
if (ru->ru_inblock || ru->ru_oublock) {
|
||||
AppendFmt("performed %,ld read and %,ld write i/o operations%s",
|
||||
Append("performed %,ld read and %,ld write i/o operations%s",
|
||||
ru->ru_inblock, ru->ru_oublock, nl);
|
||||
}
|
||||
if (ru->ru_msgrcv || ru->ru_msgsnd) {
|
||||
AppendFmt("received %,ld message and sent %,ld%s", ru->ru_msgrcv,
|
||||
Append("received %,ld message and sent %,ld%s", ru->ru_msgrcv,
|
||||
ru->ru_msgsnd, nl);
|
||||
}
|
||||
if (ru->ru_nsignals) {
|
||||
AppendFmt("received %,ld signals%s", ru->ru_nsignals, nl);
|
||||
Append("received %,ld signals%s", ru->ru_nsignals, nl);
|
||||
}
|
||||
if (ru->ru_nswap) {
|
||||
AppendFmt("got swapped %,ld times%s", ru->ru_nswap, nl);
|
||||
Append("got swapped %,ld times%s", ru->ru_nswap, nl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1237,7 +1259,7 @@ static void ReapZombies(void) {
|
|||
} while (!terminated);
|
||||
}
|
||||
|
||||
static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
||||
static inline ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
do {
|
||||
|
@ -1266,13 +1288,6 @@ static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t Hash(const void *data, size_t size) {
|
||||
uint32_t h;
|
||||
h = crc32c(0, data, size);
|
||||
if (!h) h = 1;
|
||||
return h;
|
||||
}
|
||||
|
||||
static bool ClientAcceptsGzip(void) {
|
||||
return msg.version >= 10 && /* RFC1945 § 3.5 */
|
||||
HeaderHas(&msg, inbuf.p, kHttpAcceptEncoding, "gzip", 4);
|
||||
|
@ -1453,23 +1468,16 @@ static struct Asset *GetAsset(const char *path, size_t pathlen) {
|
|||
struct Asset *a;
|
||||
if (!(a = GetAssetFile(path, pathlen))) {
|
||||
if (!(a = GetAssetZip(path, pathlen))) {
|
||||
if (pathlen > 1 && path[pathlen - 1] != '/') {
|
||||
path2 = xmalloc(pathlen + 1);
|
||||
memcpy(mempcpy(path2, path, pathlen), "/", 1);
|
||||
a = GetAssetZip(path2, pathlen + 1);
|
||||
free(path2);
|
||||
if (pathlen > 1 && path[pathlen - 1] != '/' &&
|
||||
pathlen + 1 <= sizeof(slashpath)) {
|
||||
memcpy(mempcpy(slashpath, path, pathlen), "/", 1);
|
||||
a = GetAssetZip(slashpath, pathlen + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static char *AppendCrlf(char *p) {
|
||||
p[0] = '\r';
|
||||
p[1] = '\n';
|
||||
return p + 2;
|
||||
}
|
||||
|
||||
static bool MustNotIncludeMessageBody(void) { /* RFC2616 § 4.4 */
|
||||
return msg.method == kHttpHead || (100 <= statuscode && statuscode <= 199) ||
|
||||
statuscode == 204 || statuscode == 304;
|
||||
|
@ -1523,19 +1531,9 @@ static char *AppendCache(char *p, int64_t seconds) {
|
|||
return AppendExpires(p, (int64_t)shared->nowish + seconds);
|
||||
}
|
||||
|
||||
static bool IsPublic(void) {
|
||||
uint32_t ip;
|
||||
GetRemoteAddr(&ip, 0);
|
||||
return IsPublicIp(ip);
|
||||
}
|
||||
|
||||
static char *AppendServer(char *p, const char *s) {
|
||||
p = stpcpy(p, "Server: ");
|
||||
if (IsPublic()) {
|
||||
p = mempcpy(p, s, strchrnul(s, '/') - s);
|
||||
} else {
|
||||
p = stpcpy(p, s);
|
||||
}
|
||||
return AppendCrlf(p);
|
||||
}
|
||||
|
||||
|
@ -1658,15 +1656,15 @@ static void AppendLogo(void) {
|
|||
struct Asset *a;
|
||||
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
||||
q = EncodeBase64(p, n, &n);
|
||||
AppendString("<img src=\"data:image/png;base64,");
|
||||
Append("<img src=\"data:image/png;base64,");
|
||||
AppendData(q, n);
|
||||
AppendString("\">\r\n");
|
||||
Append("\">\r\n");
|
||||
free(q);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t Send(struct iovec *iov, int iovlen) {
|
||||
static inline ssize_t Send(struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
if ((rc = WritevAll(client, iov, iovlen)) == -1) {
|
||||
if (errno == ECONNRESET) {
|
||||
|
@ -1711,11 +1709,11 @@ static char *CommitOutput(char *p) {
|
|||
static char *ServeDefaultErrorPage(char *p, unsigned code, const char *reason) {
|
||||
p = AppendContentType(p, "text/html; charset=ISO-8859-1");
|
||||
reason = FreeLater(EscapeHtml(reason, -1, 0));
|
||||
AppendString("\
|
||||
Append("\
|
||||
<!doctype html>\r\n\
|
||||
<title>");
|
||||
AppendFmt("%d %s", code, reason);
|
||||
AppendString("\
|
||||
Append("%d %s", code, reason);
|
||||
Append("\
|
||||
</title>\r\n\
|
||||
<style>\r\n\
|
||||
html { color: #111; font-family: sans-serif; }\r\n\
|
||||
|
@ -1723,8 +1721,8 @@ img { vertical-align: middle; }\r\n\
|
|||
</style>\r\n\
|
||||
<h1>\r\n");
|
||||
AppendLogo();
|
||||
AppendFmt("%d %s\r\n", code, reason);
|
||||
AppendString("</h1>\r\n");
|
||||
Append("%d %s\r\n", code, reason);
|
||||
Append("</h1>\r\n");
|
||||
UseOutput();
|
||||
return p;
|
||||
}
|
||||
|
@ -1734,7 +1732,7 @@ static char *ServeErrorImpl(unsigned code, const char *reason) {
|
|||
char *p, *s;
|
||||
struct Asset *a;
|
||||
LockInc(&shared->errors);
|
||||
DropOutput();
|
||||
ClearOutput();
|
||||
p = SetStatus(code, reason);
|
||||
s = xasprintf("/%d.html", code);
|
||||
a = GetAsset(s, strlen(s));
|
||||
|
@ -1877,8 +1875,16 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
|
|||
} else {
|
||||
LockInc(&shared->openfails);
|
||||
WARNF("open(%`'s) failed %s", a->file->path, strerror(errno));
|
||||
if (errno == ENFILE) {
|
||||
LockInc(&shared->enfiles);
|
||||
return ServeError(503, "Service Unavailable");
|
||||
} else if (errno == EMFILE) {
|
||||
LockInc(&shared->emfiles);
|
||||
return ServeError(503, "Service Unavailable");
|
||||
} else {
|
||||
return ServeError(500, "Internal Server Error");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
content = "";
|
||||
contentlength = 0;
|
||||
|
@ -3320,7 +3326,6 @@ static char *HandleRedirect(struct Redirect *r) {
|
|||
static void LogMessage(const char *d, const char *s, size_t n) {
|
||||
size_t n2, n3;
|
||||
char *s2, *s3;
|
||||
if (logmessages) {
|
||||
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
||||
if ((s2 = DecodeLatin1(s, n, &n2))) {
|
||||
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
||||
|
@ -3329,13 +3334,12 @@ static void LogMessage(const char *d, const char *s, size_t n) {
|
|||
}
|
||||
free(s2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LogBody(const char *d, const char *s, size_t n) {
|
||||
char *s2, *s3;
|
||||
size_t n2, n3;
|
||||
if (n && logbodies) {
|
||||
if (!n) return;
|
||||
while (n && (s[n - 1] == '\r' || s[n - 1] == '\n')) --n;
|
||||
if ((s2 = VisualizeControlCodes(s, n, &n2))) {
|
||||
if ((s3 = IndentLines(s2, n2, &n3, 1))) {
|
||||
|
@ -3344,14 +3348,13 @@ static void LogBody(const char *d, const char *s, size_t n) {
|
|||
}
|
||||
free(s2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t SendString(const char *s) {
|
||||
size_t n;
|
||||
ssize_t rc;
|
||||
n = strlen(s);
|
||||
LogMessage("sending", s, n);
|
||||
if (logmessages) LogMessage("sending", s, n);
|
||||
for (;;) {
|
||||
if ((rc = write(client, s, n)) != -1 || errno != EINTR) {
|
||||
return rc;
|
||||
|
@ -3522,11 +3525,11 @@ static const char *MergeNames(const char *a, const char *b) {
|
|||
}
|
||||
|
||||
static void AppendLong1(const char *a, long x) {
|
||||
if (x) AppendFmt("%s: %ld\r\n", a, x);
|
||||
if (x) Append("%s: %ld\r\n", a, x);
|
||||
}
|
||||
|
||||
static void AppendLong2(const char *a, const char *b, long x) {
|
||||
if (x) AppendFmt("%s.%s: %ld\r\n", a, b, x);
|
||||
if (x) Append("%s.%s: %ld\r\n", a, b, x);
|
||||
}
|
||||
|
||||
static void AppendTimeval(const char *a, struct timeval *tv) {
|
||||
|
@ -3681,7 +3684,7 @@ char *ServeListing(void) {
|
|||
char rb[8], tb[64], *rp[6];
|
||||
size_t i, n, pathlen, rn[6];
|
||||
if (msg.method != kHttpGet && msg.method != kHttpHead) return BadMethod();
|
||||
AppendString("\
|
||||
Append("\
|
||||
<!doctype html>\r\n\
|
||||
<meta charset=\"utf-8\">\r\n\
|
||||
<title>redbean zip listing</title>\r\n\
|
||||
|
@ -3698,7 +3701,7 @@ td { padding-right: 3em; }\r\n\
|
|||
rp[0] = EscapeHtml(brand, -1, &rn[0]);
|
||||
AppendData(rp[0], rn[0]);
|
||||
free(rp[0]);
|
||||
AppendString("</h1><hr></header><pre>\r\n");
|
||||
Append("</h1><hr></header><pre>\r\n");
|
||||
memset(w, 0, sizeof(w));
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
|
@ -3733,12 +3736,12 @@ td { padding-right: 3em; }\r\n\
|
|||
if (IsCompressionMethodSupported(
|
||||
ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf)) &&
|
||||
IsAcceptablePath(path, pathlen)) {
|
||||
AppendFmt("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
||||
Append("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
||||
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
||||
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, lf),
|
||||
w[2], GetZipLfileUncompressedSize(zmap + lf), rp[5]);
|
||||
} else {
|
||||
AppendFmt("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
||||
Append("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
||||
w[1], GetZipCfileMode(zmap + cf),
|
||||
DescribeCompressionRatio(rb, lf), w[2],
|
||||
GetZipLfileUncompressedSize(zmap + lf), rp[5]);
|
||||
|
@ -3752,38 +3755,38 @@ td { padding-right: 3em; }\r\n\
|
|||
}
|
||||
free(path);
|
||||
}
|
||||
AppendString("</pre><footer><hr>\r\n");
|
||||
AppendString("<table border=\"0\"><tr><td valign=\"top\">\r\n");
|
||||
AppendString("<a href=\"/statusz\">/statusz</a> says your redbean<br>\r\n");
|
||||
Append("</pre><footer><hr>\r\n");
|
||||
Append("<table border=\"0\"><tr><td valign=\"top\">\r\n");
|
||||
Append("<a href=\"/statusz\">/statusz</a> says your redbean<br>\r\n");
|
||||
AppendResourceReport(&shared->children, "<br>\r\n");
|
||||
AppendString("<td valign=\"top\">\r\n");
|
||||
Append("<td valign=\"top\">\r\n");
|
||||
and = "";
|
||||
x = nowl() - startserver;
|
||||
y = ldiv(x, 24L * 60 * 60);
|
||||
if (y.quot) {
|
||||
AppendFmt("%,ld day%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||
Append("%,ld day%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||
and = "and ";
|
||||
}
|
||||
y = ldiv(y.rem, 60 * 60);
|
||||
if (y.quot) {
|
||||
AppendFmt("%,ld hour%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||
Append("%,ld hour%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||
and = "and ";
|
||||
}
|
||||
y = ldiv(y.rem, 60);
|
||||
if (y.quot) {
|
||||
AppendFmt("%,ld minute%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||
Append("%,ld minute%s ", y.quot, y.quot == 1 ? "" : "s");
|
||||
and = "and ";
|
||||
}
|
||||
AppendFmt("%s%,ld second%s of operation<br>\r\n", and, y.rem,
|
||||
Append("%s%,ld second%s of operation<br>\r\n", and, y.rem,
|
||||
y.rem == 1 ? "" : "s");
|
||||
x = shared->messageshandled;
|
||||
AppendFmt("%,ld message%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
||||
Append("%,ld message%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
||||
x = shared->connectionshandled;
|
||||
AppendFmt("%,ld connection%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
||||
Append("%,ld connection%s handled<br>\r\n", x, x == 1 ? "" : "s");
|
||||
x = shared->workers;
|
||||
AppendFmt("%,ld connection%s active<br>\r\n", x, x == 1 ? "" : "s");
|
||||
AppendString("</table>\r\n");
|
||||
AppendString("</footer>\r\n");
|
||||
Append("%,ld connection%s active<br>\r\n", x, x == 1 ? "" : "s");
|
||||
Append("</table>\r\n");
|
||||
Append("</footer>\r\n");
|
||||
p = SetStatus(200, "OK");
|
||||
p = AppendContentType(p, "text/html");
|
||||
p = AppendCache(p, 0);
|
||||
|
@ -4014,7 +4017,7 @@ static char *HandleRequest(void) {
|
|||
return ServeFailure(505, "HTTP Version Not Supported");
|
||||
}
|
||||
if ((p = SynchronizeStream())) return p;
|
||||
LogBody("received", inbuf.p + hdrsize, msgsize - hdrsize);
|
||||
if (logbodies) LogBody("received", inbuf.p + hdrsize, msgsize - hdrsize);
|
||||
if (msg.version < 11 || HeaderEqualCase(kHttpConnection, "close")) {
|
||||
connectionclose = true;
|
||||
}
|
||||
|
@ -4072,10 +4075,11 @@ static bool HandleMessage(void) {
|
|||
char *p, *s;
|
||||
struct iovec iov[4];
|
||||
long actualcontentlength;
|
||||
g_syscount = 0;
|
||||
if ((rc = ParseHttpRequest(&msg, inbuf.p, amtread)) != -1) {
|
||||
if (!rc) return false;
|
||||
hdrsize = rc;
|
||||
LogMessage("received", inbuf.p, hdrsize);
|
||||
if (logmessages) LogMessage("received", inbuf.p, hdrsize);
|
||||
RecordNetworkOrigin();
|
||||
p = HandleRequest();
|
||||
} else {
|
||||
|
@ -4091,12 +4095,12 @@ static bool HandleMessage(void) {
|
|||
LockInc(&shared->synchronizationfailures);
|
||||
DEBUGF("could not synchronize message stream");
|
||||
}
|
||||
if (connectionclose) {
|
||||
if (0 && connectionclose) {
|
||||
LockInc(&shared->shutdowns);
|
||||
shutdown(client, SHUT_RD);
|
||||
}
|
||||
if (msg.version >= 10) {
|
||||
p = AppendHeader(p, "Date", shared->currentdate);
|
||||
p = AppendCrlf(stpcpy(stpcpy(p, "Date: "), shared->currentdate));
|
||||
if (!branded) p = AppendServer(p, serverheader);
|
||||
if (extrahdrs) p = stpcpy(p, extrahdrs);
|
||||
if (connectionclose) {
|
||||
|
@ -4112,7 +4116,7 @@ static bool HandleMessage(void) {
|
|||
p = AppendContentLength(p, actualcontentlength);
|
||||
p = AppendCrlf(p);
|
||||
CHECK_LE(p - hdrbuf.p, hdrbuf.n);
|
||||
LogMessage("sending", hdrbuf.p, p - hdrbuf.p);
|
||||
if (logmessages) LogMessage("sending", hdrbuf.p, p - hdrbuf.p);
|
||||
iov[0].iov_base = hdrbuf.p;
|
||||
iov[0].iov_len = p - hdrbuf.p;
|
||||
iovlen = 1;
|
||||
|
@ -4137,7 +4141,7 @@ static bool HandleMessage(void) {
|
|||
iovlen = 1;
|
||||
}
|
||||
if (loglatency || LOGGABLE(kLogDebug)) {
|
||||
flogf(kLogDebug, __FILE__, __LINE__, NULL, "%`'.*s handled in %,ldµs",
|
||||
flogf(kLogDebug, __FILE__, __LINE__, NULL, "%`'.*s latency %,ldµs",
|
||||
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a,
|
||||
(long)((nowl() - startrequest) * 1e6L));
|
||||
}
|
||||
|
@ -4150,6 +4154,7 @@ static bool HandleMessage(void) {
|
|||
static void InitRequest(void) {
|
||||
frags = 0;
|
||||
msgsize = 0;
|
||||
outbuf.n = 0;
|
||||
content = NULL;
|
||||
gzipped = false;
|
||||
branded = false;
|
||||
|
@ -4272,10 +4277,13 @@ static void HandleConnection(void) {
|
|||
case 0:
|
||||
meltdown = false;
|
||||
connectionclose = false;
|
||||
if (funtrace && !IsTiny()) {
|
||||
ftrace_install();
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
FATALF("%s too many processes %s", DescribeServer(), strerror(errno));
|
||||
LockInc(&shared->forkerrors);
|
||||
++shared->forkerrors;
|
||||
LockInc(&shared->dropped);
|
||||
EnterMeltdownMode();
|
||||
SendServiceUnavailable();
|
||||
|
@ -4292,8 +4300,7 @@ static void HandleConnection(void) {
|
|||
HandleMessages();
|
||||
DEBUGF("%s closing after %,ldµs", DescribeClient(),
|
||||
(long)((nowl() - startconnection) * 1e6L));
|
||||
if (close(client) != -1) {
|
||||
} else {
|
||||
if (close(client) == -1) {
|
||||
LockInc(&shared->closeerrors);
|
||||
WARNF("%s close failed", DescribeClient());
|
||||
}
|
||||
|
@ -4303,7 +4310,7 @@ static void HandleConnection(void) {
|
|||
CollectGarbage();
|
||||
}
|
||||
} else if (errno == EINTR || errno == EAGAIN) {
|
||||
LockInc(&shared->acceptinterrupts);
|
||||
++shared->acceptinterrupts;
|
||||
} else if (errno == ENFILE) {
|
||||
LockInc(&shared->enfiles);
|
||||
WARNF("%s too many open files", DescribeServer());
|
||||
|
@ -4321,19 +4328,19 @@ static void HandleConnection(void) {
|
|||
WARNF("%s ran out of buffer");
|
||||
EnterMeltdownMode();
|
||||
} else if (errno == ENONET) {
|
||||
LockInc(&shared->enonets);
|
||||
++shared->enonets;
|
||||
WARNF("%s network gone", DescribeServer());
|
||||
sleep(1);
|
||||
} else if (errno == ENETDOWN) {
|
||||
LockInc(&shared->enetdowns);
|
||||
++shared->enetdowns;
|
||||
WARNF("%s network down", DescribeServer());
|
||||
sleep(1);
|
||||
} else if (errno == ECONNABORTED) {
|
||||
LockInc(&shared->acceptresets);
|
||||
++shared->acceptresets;
|
||||
WARNF("%s connection reset before accept");
|
||||
} else if (errno == ENETUNREACH || errno == EHOSTUNREACH ||
|
||||
errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) {
|
||||
LockInc(&shared->accepterrors);
|
||||
++shared->accepterrors;
|
||||
WARNF("%s ephemeral accept error %s", DescribeServer(), strerror(errno));
|
||||
} else {
|
||||
FATALF("%s accept error %s", DescribeServer(), strerror(errno));
|
||||
|
@ -4408,8 +4415,8 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
|||
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
||||
heartless = true;
|
||||
}
|
||||
CHECK_NE(-1,
|
||||
(server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)));
|
||||
server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
||||
CHECK_NE(-1, server);
|
||||
TuneSockets();
|
||||
if (bind(server, &serveraddr, sizeof(serveraddr)) == -1) {
|
||||
if (errno == EADDRINUSE) {
|
||||
|
@ -4473,7 +4480,7 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
|||
|
||||
int main(int argc, char *argv[]) {
|
||||
setenv("GDB", "", true);
|
||||
showcrashreports();
|
||||
if (!IsTiny()) showcrashreports();
|
||||
RedBean(argc, argv, (const char *)getauxval(AT_EXECFN));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -262,7 +262,7 @@ local function main()
|
|||
pat = re.compile([[([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})]])
|
||||
m,a,b,c,d = pat:search(s) -- m and rest are nil if match not found
|
||||
Write('<pre>\r\n')
|
||||
Write([[pat = re.compile('([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})', re.EXTENDED)]])
|
||||
Write([[pat = re.compile('([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})')]])
|
||||
Write(string.format('\r\nm,a,b,c,d = pat:search(%q)\r\n', s))
|
||||
Write('</pre>\r\n')
|
||||
Write('<dl>\r\n')
|
||||
|
|
Loading…
Reference in a new issue