Make improvements

- Emulator can now test the αcτµαlly pδrταblε εxεcµταblε bootloader

- Whipped up a webserver named redbean. It services 150k requests per
  second on a single core. Bundling assets inside zip enables extremely
  fast serving for two reasons. The first is that zip central directory
  lookups go faster than stat() system calls. The second is that both
  zip and gzip content-encoding use DEFLATE, therefore, compressed
  responses can be served via the sendfile() system call which does an
  in-kernel copy directly from the zip executable structure. Also note
  that red bean zip executables can be deployed easily to all platforms,
  since these native executables work on Linux, Mac, BSD, and Windows.

- Address sanitizer now works very well
main
Justine Tunney 2020-09-06 21:39:00 -07:00
parent 7327c345f9
commit 416fd86676
230 changed files with 9835 additions and 5682 deletions

View File

@ -236,9 +236,6 @@ pc: cld
ljmp $0,$REAL(realmodeloader)
.endfn pc,globl,hidden
/ Be gentler on Unix line buffer impls.
.byte 0x0a
/ Determines disk geometry.
/
/ We use imperial measurements for storage systems so the software
@ -1055,9 +1052,9 @@ realmodeloader:
call rlinit
call sinit4
mov $VIDYA_MODE,%di
call vinit
mov %es,XLM(VIDEO_POSITION_FAR_POINTER)
mov %ax,XLM(VIDEO_POSITION_FAR_POINTER)+2
call vinit
mov $REAL(.Lstr.ape),%di
call rvputs
.optfn _start16
@ -1370,8 +1367,8 @@ vtput: push %bp
mov %di,%dx
bband VIDYA_REWIND,%dh,%dl
bbadd VIDYA_SIZE,%dh,%dl
bbmov VIDYA_COLUMNS*2,%bx,%bh,%bl
0: cmp %di,%dx
bbmov VIDYA_COLUMNS*2-2,%bx,%bh,%bl
0: cmp %dx,%di
je 6f
ja 3f
lodsb # todo: utf8 cp437
@ -1523,12 +1520,12 @@ longmodeloader:
/ Long Mode Hardware Check
lcheck: push %bp
mov %sp,%bp
pushfw # check for i8086 / i8088 / i80186
pushf # check for i8086 / i8088 / i80186
pop %ax
and $0b111<<12,%ax # see intel manual volume 1 §19.1.2
jnz 9f
pushfl # now check for later model of 80486
pop %eax # test ability to *change* cpuid bit
test $0x80,%ah # see intel manual volume 1 20.1.2
jnz 9f # we now assume 32bit is supported
pushfl # now check for i386 or early i486
pop %eax # test ability to change cpuid bit
mov %eax,%ecx
mov $1<<21,%ebx
xor %ebx,%eax
@ -1537,8 +1534,8 @@ lcheck: push %bp
pushfl
pop %eax
cmp %eax,%ecx
je 12f
and %ebx,%eax # puts cpuid bit in the on position
je 12f # we assume cpuid inst is available
or %ebx,%eax # puts cpuid bit in the on position
push %eax
popfl
mov $0x80000000,%edi # get amd ext cpuid thingy length
@ -1549,7 +1546,7 @@ lcheck: push %bp
jl 10f
mov %edi,%eax
cpuid
mov $1<<29/*LM*/,%edi # check for nexgen32e support
mov $1<<29,%edi # need nexgen32e long mode support
and %edi,%edx
cmp %edi,%edx
jne 10f

View File

@ -41,7 +41,7 @@
* @see ape/lib/vidya.h
*/
#ifndef VIDYA_MODE
#define VIDYA_MODE VIDYA_MODE_MDA
#define VIDYA_MODE VIDYA_MODE_CGA
#endif
/* FPU Control Word (x87) Exception Masks

View File

@ -58,6 +58,12 @@ o/$(MODE)/dsp/core/det3.o: \
OVERRIDE_CFLAGS += \
-ffast-math
ifeq (,$(MODE))
$(DSP_CORE_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
DSP_CORE_LIBS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)))
DSP_CORE_SRCS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_SRCS))
DSP_CORE_HDRS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_HDRS))

View File

@ -102,7 +102,7 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
if (!dar) dar = sn, dar /= dn;
if (!off) off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 1;
s = 3 * f + 4;
fweights = gc(xcalloc(s, sizeof(double)));
res = NewSamplingSolution(dn, s);
weights = res->weights;
@ -147,9 +147,9 @@ static int Sharpen(int ax, int bx, int cx) {
static void GyaradosImpl(long dyw, long dxw, int dst[dyw][dxw], long syw,
long sxw, const int src[syw][sxw], long dyn, long dxn,
long syn, long sxn, short tmp0[restrict dyn][sxn],
short tmp1[restrict dyn][sxn],
short tmp2[restrict dyn][dxn], long yfn, long xfn,
long syn, long sxn, int tmp0[restrict dyn][sxn],
int tmp1[restrict dyn][sxn],
int tmp2[restrict dyn][dxn], long yfn, long xfn,
const short fyi[dyn][yfn], const short fyw[dyn][yfn],
const short fxi[dxn][xfn], const short fxw[dxn][xfn],
bool sharpen) {
@ -216,9 +216,9 @@ void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw,
CHECK_LE(syn, 0x7fff);
CHECK_LE(sxn, 0x7fff);
GyaradosImpl(dyw, dxw, dst, syw, sxw, src, dyn, dxn, syn, sxn,
gc(xmemalign(64, sizeof(short) * dyn * sxn)),
gc(xmemalign(64, sizeof(short) * dyn * sxn)),
gc(xmemalign(64, sizeof(short) * dyn * dxn)), cy->s, cx->s,
gc(xmemalign(64, sizeof(int) * dyn * sxn)),
gc(xmemalign(64, sizeof(int) * dyn * sxn)),
gc(xmemalign(64, sizeof(int) * dyn * dxn)), cy->s, cx->s,
cy->indices, cy->weights, cx->indices, cx->weights, sharpen);
} else {
ZeroMatrix(dyw, dxw, dst, dyn, dxn);

View File

@ -59,6 +59,12 @@ o/$(MODE)/dsp/tty/ttyraster.o: \
OVERRIDE_CFLAGS += \
$(MATHEMATICAL)
ifeq (,$(MODE))
$(DSP_TTY_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)))
DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS))
DSP_TTY_HDRS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_HDRS))

View File

@ -35,7 +35,7 @@ void dobin(const char *op, long double x, FILE *f) {
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 % 19.19Lf\n", hi, lo, op, x);
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) {
@ -45,7 +45,7 @@ void dohex(const char *op, long double x, FILE *f) {
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 % 19.19Lf\n", hi, lo, op, x);
fprintf(f, "/\t%04" PRIx16 "%016" PRIx64 " %-8s % 17.14Lf\n", hi, lo, op, x);
}
#define DOBIN(OP) \
@ -65,7 +65,6 @@ int main(int argc, char *argv[]) {
DOBIN(fldlg2);
DOBIN(fldln2);
DOBIN(fldl2e);
DOBIN(finit);
fputc('\n', stdout);
fputs(kHeaderHex, stdout);
DOHEX(fldz);
@ -75,7 +74,6 @@ int main(int argc, char *argv[]) {
DOHEX(fldlg2);
DOHEX(fldln2);
DOHEX(fldl2e);
DOHEX(finit);
return 0;
}

82
examples/ls.c 100644
View File

@ -0,0 +1,82 @@
#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/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/log/check.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/x/x.h"
struct stat st;
const char *TypeToString(uint8_t type) {
switch (type) {
case DT_UNKNOWN:
return "DT_UNKNOWN";
case DT_FIFO:
return "DT_FIFO";
case DT_CHR:
return "DT_CHR";
case DT_DIR:
return "DT_DIR";
case DT_BLK:
return "DT_BLK";
case DT_REG:
return "DT_REG";
case DT_LNK:
return "DT_LNK";
case DT_SOCK:
return "DT_SOCK";
default:
return "UNKNOWN";
}
}
void List(const char *path) {
DIR *d;
struct dirent *e;
const char *vpath;
if (strcmp(path, ".") == 0) {
vpath = "";
} else if (!endswith(path, "/")) {
vpath = gc(xasprintf("%s/", path));
} else {
vpath = path;
}
if (stat(path, &st) != -1) {
if (S_ISDIR(st.st_mode)) {
CHECK((d = opendir(path)));
while ((e = readdir(d))) {
printf("0x%016x 0x%016x %-10s %s%s\n", e->d_ino, e->d_off,
TypeToString(e->d_type), vpath, e->d_name);
}
closedir(d);
} else {
printf("%s\n", path);
}
} else {
fprintf(stderr, "not found: %s\n", path);
}
}
int main(int argc, char *argv[]) {
int i;
if (argc == 1) {
List(".");
} else {
for (i = 1; i < argc; ++i) {
List(argv[i]);
}
}
return 0;
}

View File

@ -58,3 +58,6 @@ _start: mov $12,%rdx # arg no. 3 is length
jmp 0b
.endfn _start,globl
.source __FILE__
.rodata.cst4
1: .float -1.5

View File

@ -23,6 +23,8 @@
#include "libc/calls/struct/dirent.h"
#include "libc/dce.h"
#include "libc/mem/mem.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/win32finddata.h"
@ -31,9 +33,18 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
struct dirent$freebsd {
uint32_t d_fileno;
uint16_t d_reclen;
uint8_t d_type;
uint8_t d_namlen;
char d_name[256];
};
struct dirstream {
int64_t tell;
int64_t fd;
struct dirent ent;
union {
struct {
unsigned buf_pos;
@ -41,8 +52,6 @@ struct dirstream {
char buf[BUFSIZ];
};
struct {
struct dirent winent;
char __d_name[PATH_MAX];
bool isdone;
struct NtWin32FindData windata;
};
@ -71,17 +80,60 @@ static textwindows noinline DIR *opendir$nt(const char *name) {
}
}
static textwindows noinline struct dirent *readdir$nt(DIR *dir) {
if (!dir->isdone) {
memset(&dir->ent, 0, sizeof(dir->ent));
dir->ent.d_ino = 0;
dir->ent.d_off = dir->tell++;
dir->ent.d_reclen = sizeof(dir->ent) +
tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name),
dir->windata.cFileName) +
1;
switch (dir->windata.dwFileType) {
case kNtFileTypeDisk:
dir->ent.d_type = DT_BLK;
break;
case kNtFileTypeChar:
dir->ent.d_type = DT_CHR;
break;
case kNtFileTypePipe:
dir->ent.d_type = DT_FIFO;
break;
default:
if (dir->windata.dwFileAttributes & kNtFileAttributeDirectory) {
dir->ent.d_type = DT_DIR;
} else {
dir->ent.d_type = DT_REG;
}
break;
}
dir->isdone = !FindNextFile(dir->fd, &dir->windata);
return &dir->ent;
} else {
return NULL;
}
}
/**
* Opens directory so readdir() and closedir() may be called.
* Opens directory, e.g.
*
* DIR *d;
* struct dirent *e;
* CHECK((d = opendir(path)));
* while ((e = readdir(d))) {
* printf("%s/%s\n", path, e->d_name);
* }
* LOGIFNEG1(closedir(d));
*
* @returns newly allocated DIR object, or NULL w/ errno
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
* @see glob()
*/
DIR *opendir(const char *name) {
if (!IsWindows() && !IsXnu()) {
int fd;
DIR *res = NULL;
DIR *res;
if (!IsWindows() && !IsXnu()) {
res = NULL;
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) {
if (!(res = fdopendir(fd))) close(fd);
}
@ -103,8 +155,8 @@ DIR *opendir(const char *name) {
* @errors ENOMEM and fd is closed
*/
DIR *fdopendir(int fd) {
if (!IsWindows() && !IsXnu()) {
DIR *dir;
if (!IsWindows() && !IsXnu()) {
if ((dir = calloc(1, sizeof(*dir)))) {
dir->fd = fd;
return dir;
@ -125,35 +177,36 @@ DIR *fdopendir(int fd) {
* differentiated by setting errno to 0 beforehand
*/
struct dirent *readdir(DIR *dir) {
int rc;
struct dirent *ent;
struct dirent$freebsd *freebsd;
if (!IsWindows()) {
if (dir->buf_pos >= dir->buf_end) {
int rc;
if (!(rc = getdents(dir->fd, dir->buf, BUFSIZ)) || rc == -1) {
if (!(rc = getdents(dir->fd, dir->buf,
sizeof(dir->buf) - sizeof(dir->ent.d_name))) ||
rc == -1) {
return NULL;
}
dir->buf_pos = 0;
dir->buf_end = rc;
}
/* TODO(jart): Check FreeBSD and OpenBSD again regarding this */
char *record = dir->buf + dir->buf_pos;
char *name = record + 8 + 8 + 2;
size_t namelen = strlen(name);
unsigned char dtype = name[namelen + 1];
memmove(name + 1, name, namelen + 1); /* shove forward one byte */
*name = dtype; /* is dirent d_type field */
struct dirent *ent = (void *)record;
if (IsLinux()) {
ent = (struct dirent *)(dir->buf + dir->buf_pos);
dir->buf_pos += ent->d_reclen;
dir->tell = ent->d_off;
} else {
freebsd = (struct dirent$freebsd *)(dir->buf + dir->buf_pos);
dir->buf_pos += freebsd->d_reclen;
ent = &dir->ent;
ent->d_ino = freebsd->d_fileno;
ent->d_off = dir->tell++;
ent->d_reclen = freebsd->d_reclen;
ent->d_type = freebsd->d_type;
memcpy(ent->d_name, freebsd->d_name, freebsd->d_namlen + 1);
}
return ent;
} else {
if (dir->isdone) return NULL;
struct dirent *ent = &dir->winent;
memset(ent, 0, sizeof(*ent));
ent->d_reclen =
sizeof(*ent) +
tprecode16to8(ent->d_name, PATH_MAX, dir->windata.cFileName) + 1;
dir->isdone = FindNextFile(dir->fd, &dir->windata);
return ent;
return readdir$nt(dir);
}
}
@ -177,7 +230,7 @@ int closedir(DIR *dir) {
}
/**
* Returns current byte offset into directory data.
* Returns offset into directory data.
*/
long telldir(DIR *dir) {
return dir->tell;

View File

@ -21,6 +21,9 @@
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#ifndef __STRICT_ANSI__
#include "libc/calls/calls.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/macros.h"
@ -28,6 +31,8 @@
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/systeminfo.h"
#include "libc/runtime/runtime.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/struct/utimbuf.h"
#define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */
@ -41,14 +46,6 @@ struct NtWin32FileAttributeData;
struct ZiposHandle;
struct __darwin_siginfo;
struct __darwin_ucontext;
struct itimerval;
struct rlimit;
struct rusage;
struct sigset;
struct sysinfo;
struct timeval;
struct timezone;
struct utimbuf;
struct IoctlPtmGet {
int theduxfd;

View File

@ -28,6 +28,8 @@
/**
* Returns information about thing.
*
* @see S_ISDIR(st.st_mode), S_ISREG(), etc.
* @asyncsignalsafe
*/
int stat(const char *pathname, struct stat *st) {

View File

@ -2,12 +2,12 @@
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_DIRENT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
struct dirent {
struct dirent { /* linux getdents64 abi */
uint64_t d_ino; /* inode number */
int64_t d_off; /* implementation-dependent location number */
uint16_t d_reclen; /* byte length of this whole struct and string */
uint8_t d_type; /* DT_UNKNOWN, DT_BLK, DT_DIR, etc. it's flaky */
char d_name[1]; /* NUL-terminated basename */
uint8_t d_type; /* DT_UNKNOWN, DT_BLK, DT_DIR, etc. */
char d_name[256]; /* NUL-terminated basename */
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View File

@ -58,9 +58,13 @@ o/$(MODE)/libc/conv/filetimetotime.o \
o/$(MODE)/libc/conv/timespectofiletime.o \
o/$(MODE)/libc/conv/filetimetotimespec.o \
o/$(MODE)/libc/conv/filetimetotimeval.o: \
OVERRIDE_COPTS += \
OVERRIDE_CFLAGS += \
-O3
$(LIBC_CONV_A_OBJS): \
OVERRIDE_CFLAGS += \
$(NO_MAGIC)
LIBC_CONV_LIBS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)))
LIBC_CONV_SRCS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_SRCS))
LIBC_CONV_HDRS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_HDRS))

View File

@ -17,22 +17,14 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/reverse.h"
#include "libc/assert.h"
#include "libc/conv/itoa.h"
size_t uint64toarray_fixed16(uint64_t i, char a[hasatleast 17], uint8_t b) {
size_t j;
assert(b <= 64);
assert(b % 4 == 0);
j = 0;
if (b) {
do {
a[j++] = "0123456789abcdef"[i & 15];
i >>= 4;
} while (b -= 4);
}
a[j] = '\0';
reverse(a, j);
return j;
size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) {
int i;
char *p;
assert(k <= 64 && !(k & 3));
for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0';
return p - b;
}

View File

@ -17,17 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/reverse.h"
#include "libc/conv/conv.h"
#include "libc/conv/itoa.h"
#include "libc/macros.h"
#include "libc/nexgen32e/bsr.h"
size_t uint64toarray_radix16(uint64_t i, char a[hasatleast 17]) {
size_t j;
j = 0;
do {
a[j++] = "0123456789abcdef"[i % 16];
i /= 16;
} while (i > 0);
a[j] = '\0';
reverse(a, j);
return j;
size_t uint64toarray_radix16(uint64_t x, char b[hasatleast 17]) {
return uint64toarray_fixed16(x, b, ROUNDUP(x ? bsrl(x) + 1 : 1, 4));
}

View File

@ -39,7 +39,7 @@ _start: test %rdi,%rdi
lea 8(%rsp),%rsi # argv
lea 24(%rsp,%rbx,8),%rdx # envp
.frame0
bofram 9f
/ bofram 9f
.weak idata.iat,idata.iatend
ezlea missingno,ax # make win32 imps noop
ezlea idata.iat,di

View File

@ -23,6 +23,7 @@ Elf64_Ehdr *mapelfread(const char *, struct MappedFile *);
char *getelfstringtable(const Elf64_Ehdr *, size_t);
Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *, size_t, void *);
bool iself64binary(const Elf64_Ehdr *, size_t);
forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize,
intptr_t addr, size_t addrsize) {
@ -33,13 +34,6 @@ forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize,
#endif
}
static inline bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) {
return mapsize >= sizeof(Elf64_Ehdr) &&
memcmp(elf->e_ident, ELFMAG, 4) == 0 &&
(elf->e_ident[EI_CLASS] == ELFCLASSNONE ||
elf->e_ident[EI_CLASS] == ELFCLASS64);
}
static inline bool iselfsymbolcontent(const Elf64_Sym *sym) {
return sym->st_size > 0 && (ELF64_ST_TYPE(sym->st_info) == STT_FUNC ||
ELF64_ST_TYPE(sym->st_info) == STT_OBJECT);

View File

@ -17,9 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
#include "libc/elf/elf.h"
TEST(flattenhighmemory, test) {
/* EXPECT_EQ(0, flattenhighmemory()); */
/* EXPECT_STREQ("", flattenhighmemory()); */
bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) {
if (mapsize < sizeof(Elf64_Ehdr)) return false;
if (memcmp(elf->e_ident, ELFMAG, 4)) return false;
return (elf->e_ident[EI_CLASS] == ELFCLASSNONE ||
elf->e_ident[EI_CLASS] == ELFCLASS64);
}

View File

@ -34,16 +34,13 @@
#include "libc/fmt/palandprintf.h"
#include "libc/math.h"
static const int kPow10[] = {1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000, 1000000000};
/**
* Formats floating point number.
*
* @see xdtoa() for higher precision at the cost of bloat
* @see palandprintf() which is intended caller
*/
int ftoa(int out(int, void *), void *arg, long double value, unsigned long prec,
int ftoa(int out(int, void *), void *arg, long double value, int prec,
unsigned long width, unsigned long flags) {
long whole, frac;
long double tmp, diff;
@ -72,32 +69,31 @@ int ftoa(int out(int, void *), void *arg, long double value, unsigned long prec,
prec = 6;
}
/* limit precision to 9, cause a prec >= 10 can lead to overflow errors */
while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 9) {
while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 14) {
buf[len++] = '0';
prec--;
}
whole = truncl(fabsl(value));
tmp = (fabsl(value) - whole) * kPow10[prec];
tmp = (fabsl(value) - whole) * exp10l(prec);
frac = tmp;
diff = tmp - frac;
if (diff > 0.5) {
if (diff > .5) {
++frac; /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
if (frac >= kPow10[prec]) {
if (frac >= exp10l(prec)) {
frac = 0;
++whole;
}
} else if (diff < 0.5) {
} else if (diff < .5) {
} else if (!frac || (frac & 1)) {
++frac; /* if halfway, round up if odd OR if last digit is 0 */
}
if (!prec) {
diff = fabsl(value) - whole;
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
/* exactly 0.5 and ODD, then round up */
if ((!(diff < .5) || (diff > .5)) && (whole & 1)) {
/* exactly .5 and ODD, then round up */
/* 1.5 -> 2, but 2.5 -> 2 */
++whole;
}

View File

@ -8,7 +8,7 @@
COSMOPOLITAN_C_START_
int spacepad(int(int, void *), void *, unsigned long) hidden;
int ftoa(int(int, void *), void *, long double, unsigned long, unsigned long,
int ftoa(int(int, void *), void *, long double, int, unsigned long,
unsigned long) hidden;
int stoa(int(int, void *), void *, void *, unsigned long, unsigned long,
unsigned long, unsigned char, unsigned char) hidden;

View File

@ -179,7 +179,7 @@ typedef struct axdx_t {
#undef __SIZEOF_INTMAX__
#endif
#if !defined(__STRICT_ANSI__) && __SIZEOF_POINTER__ == 8 && \
(__GNUC__ * 100 + __GNUC_MINOR__ >= 406 || defined(__llvm__))
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406 || defined(__llvm__))
#define __SIZEOF_INTMAX__ 16
#else
#define __SIZEOF_INTMAX__ __SIZEOF_POINTER__
@ -279,7 +279,7 @@ typedef uint64_t uintmax_t;
#ifndef noinstrument
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__no_instrument_function__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 204)
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 204)
#define noinstrument __attribute__((__no_instrument_function__))
#else
#define noinstrument
@ -288,7 +288,8 @@ typedef uint64_t uintmax_t;
#ifndef noreturn
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__noreturn__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 208)
(__has_attribute(__noreturn__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 208)
#define noreturn __attribute__((__noreturn__))
#else
#define noreturn
@ -302,7 +303,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef nosideeffect
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__pure__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 296)
(__has_attribute(__pure__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 296)
#define nosideeffect __attribute__((__pure__))
#else
#define nosideeffect
@ -311,7 +313,8 @@ typedef uint64_t uintmax_t;
#ifndef noinline
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__noinline__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 301)
(__has_attribute(__noinline__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301)
#define noinline __attribute__((__noinline__))
#else
#define noinline
@ -320,7 +323,8 @@ typedef uint64_t uintmax_t;
#ifndef noclone
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__noclone__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 405)
(__has_attribute(__noclone__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405)
#define noclone __attribute__((__noclone__))
#else
#define noclone
@ -343,8 +347,10 @@ typedef uint64_t uintmax_t;
#ifdef __cplusplus
#define forceinline inline
#else
#if !defined(__STRICT_ANSI__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 302
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 403 || !defined(__cplusplus) || \
#if !defined(__STRICT_ANSI__) && \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 302
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \
!defined(__cplusplus) || \
(defined(__clang__) && \
(defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__)))
#if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus)
@ -380,7 +386,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef mayalias
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__may_alias__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 303)
(__has_attribute(__may_alias__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 303)
#define mayalias __attribute__((__may_alias__))
#else
#define mayalias
@ -393,7 +400,8 @@ typedef uint64_t uintmax_t;
* @see gc(), free(), close(), etc.
*/
#ifndef nodiscard
#if !defined(__STRICT_ANSI__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304 || \
#if !defined(__STRICT_ANSI__) && \
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \
__has_attribute(__warn_unused_result__))
#define nodiscard __attribute__((__warn_unused_result__))
#else
@ -416,7 +424,7 @@ typedef uint64_t uintmax_t;
#ifndef flattenout
#if __has_attribute(__flatten__) || \
(__GNUC__ * 100 + __GNUC_MINOR__ >= 401 && !defined(__llvm__))
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 401 && !defined(__llvm__))
#define flattenout __attribute__((__flatten__))
#else
#define flattenout
@ -425,7 +433,8 @@ typedef uint64_t uintmax_t;
#ifndef externinline
#if !defined(__STRICT_ANSI__) && \
(!defined(__cplusplus) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403 || \
(!defined(__cplusplus) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \
(defined(__clang__) && \
(defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__))))
#if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus)
@ -444,7 +453,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef relegated
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__cold__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403)
(__has_attribute(__cold__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403)
#define relegated __attribute__((__cold__))
#else
#define relegated
@ -452,7 +462,8 @@ typedef uint64_t uintmax_t;
#endif
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__warning__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403)
(__has_attribute(__warning__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403)
#define warnifused(s) __attribute__((__warning__(s)))
#else
#define warnifused(s)
@ -465,7 +476,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef firstclass
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__hot__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403)
(__has_attribute(__hot__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403)
#define firstclass __attribute__((__hot__))
#else
#define firstclass
@ -480,7 +492,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef paramsnonnull
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__nonnull__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403)
(__has_attribute(__nonnull__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403)
#define paramsnonnull(opt_1idxs) __attribute__((__nonnull__ opt_1idxs))
#else
#define paramsnonnull(opt_1idxs)
@ -505,7 +518,7 @@ typedef uint64_t uintmax_t;
*/
#if __STDC_VERSION__ + 0 < 199901L && !defined(restrict)
#if !defined(__STRICT_ANSI__) && !defined(__cplusplus) && \
(__GNUC__ * 100 + __GNUC_MINOR__ >= 301 || defined(_MSC_VER))
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301 || defined(_MSC_VER))
#define restrict __restrict__
#else
#define restrict
@ -520,7 +533,8 @@ typedef uint64_t uintmax_t;
#ifndef nocallback
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__leaf__) || \
(!defined(__llvm__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 406))
(!defined(__llvm__) && \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406))
#define nocallback __attribute__((__leaf__))
#else
#define nocallback
@ -529,7 +543,8 @@ typedef uint64_t uintmax_t;
#ifndef nothrow
#if defined(__cplusplus) && !defined(__STRICT_ANSI__) && \
(__has_attribute(nothrow) || __GNUC__ * 100 + __GNUC_MINOR__ >= 303)
(__has_attribute(nothrow) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 303)
#define nothrow __attribute__((__nothrow__))
#elif defined(_MSC_VER)
#define nothrow __declspec(nothrow)
@ -545,7 +560,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef nooptimize
#ifndef __STRICT_ANSI__
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 407 || __has_attribute(__optimize__)
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \
__has_attribute(__optimize__)
#define nooptimize __attribute__((__optimize__(1)))
#elif defined(__llvm__) || __has_attribute(__optnone__)
#define nooptimize __attribute__((__optnone__))
@ -564,7 +580,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef optimizesize
#ifndef __STRICT_ANSI__
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 407 || __has_attribute(__optimize__)
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \
__has_attribute(__optimize__)
#define optimizesize __attribute__((__optimize__("s")))
#elif defined(__llvm__) || __has_attribute(__optnone__)
#define optimizesize __attribute__((__optnone__))
@ -585,7 +602,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef optimizespeed
#if !defined(__STRICT_ANSI__) && \
(__GNUC__ * 100 + __GNUC_MINOR__ >= 407 || __has_attribute(__optimize__))
((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \
__has_attribute(__optimize__))
#define optimizespeed __attribute__((__optimize__(3)))
#else
#define optimizespeed
@ -596,8 +614,9 @@ typedef uint64_t uintmax_t;
* Declares prototype that behaves similar to setjmp() or vfork().
*/
#ifndef returnstwice
#if !defined(__STRICT_ANSI__) && (__has_attribute(__returns_twice__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 402)
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__returns_twice__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 402)
#define returnstwice __attribute__((__returns_twice__))
#else
#define returnstwice
@ -622,8 +641,9 @@ typedef uint64_t uintmax_t;
* @see nodebuginfo
*/
#ifndef artificial
#if !defined(__STRICT_ANSI__) && (__has_attribute(__artificial__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__artificial__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403)
#define artificial __attribute__((__artificial__))
#else
#define artificial
@ -637,7 +657,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef microarchitecture
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__target__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 404)
(__has_attribute(__target__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 404)
#define microarchitecture(march) __attribute__((__target__(march)))
#else
#define microarchitecture(march)
@ -661,7 +682,7 @@ typedef uint64_t uintmax_t;
* Defines function with prologue that fixes misaligned stack.
* @see nocallersavedregisters and consider assembly
*/
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 408 || \
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
__has_attribute(__force_align_arg_pointer__)
#define forcealignargpointer __attribute__((__force_align_arg_pointer__))
#else
@ -675,8 +696,9 @@ typedef uint64_t uintmax_t;
* runtime too by synthetic code, only in MODE=dbg mode.
*/
#ifndef returnsnonnull
#if !defined(__STRICT_ANSI__) && (__has_attribute(__returns_nonnull__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__returns_nonnull__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define returnsnonnull __attribute__((__returns_nonnull__))
#else
#define returnsnonnull
@ -690,8 +712,9 @@ typedef uint64_t uintmax_t;
* @param (alignment, misalignment)
* @see attributeallocalign(), returnspointerwithnoaliases, mallocesque
*/
#if !defined(__STRICT_ANSI__) && (__has_attribute(__assume_aligned__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__assume_aligned__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define returnsaligned(x) __attribute__((__assume_aligned__ x))
#else
#define returnsaligned(x)
@ -703,7 +726,8 @@ typedef uint64_t uintmax_t;
*/
#ifndef returnspointerwithnoaliases
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__malloc__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 409)
(__has_attribute(__malloc__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define returnspointerwithnoaliases __attribute__((__malloc__))
#elif defined(_MSC_VER)
#define returnspointerwithnoaliases __declspec(allocator)
@ -713,8 +737,9 @@ typedef uint64_t uintmax_t;
#endif
#ifndef attributeallocsize
#if !defined(__STRICT_ANSI__) && (__has_attribute(__alloc_size__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__alloc_size__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define attributeallocsize(x) __attribute__((__alloc_size__ x))
#else
#define attributeallocsize(x)
@ -722,8 +747,9 @@ typedef uint64_t uintmax_t;
#endif
#ifndef attributeallocalign
#if !defined(__STRICT_ANSI__) && (__has_attribute(__alloc_align__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
#if !defined(__STRICT_ANSI__) && \
(__has_attribute(__alloc_align__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define attributeallocalign(x) __attribute__((__alloc_align__ x))
#else
#define attributeallocalign(x)
@ -747,7 +773,7 @@ typedef uint64_t uintmax_t;
#if __cplusplus + 0 >= 201103L
#define autotype(x) auto
#elif (__has_builtin(auto_type) || defined(__llvm__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define autotype(x) __auto_type
#else
#define autotype(x) typeof(x)

View File

@ -75,7 +75,7 @@
#define ENV_MAX 0x7fff /* b/c windows */
#define ARG_MAX 0x3fff /* b/c windows */
#define CMD_MAX 0x4000 /* b/c windows */
#define PATH_MAX 248 /* b/c windows */
#define PATH_MAX 248 /* b/c win32 apis limit ~248..260 */
#define NAME_MAX 63 /* b/c dns */
#define CHILD_MAX 25 /* only if malloc isn't linked */
#define OPEN_MAX 16 /* only if malloc isn't linked */

View File

@ -0,0 +1,45 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/intrin/mpsadbw.h"
#include "libc/macros.h"
#include "libc/str/str.h"
/**
* Computes multiple sum of absolute differences.
*
* This appears to be intended for video encoding motion estimation. It
* can be combined with phminposuw. That allows us to search for an int
* overlapping inside 𝑏 that's nearest to an aligned int in 𝑎.
*
* @note goes fast w/ sse4 cf. core c. 2006 cf. bulldozer c. 2011
* @mayalias
*/
void(mpsadbw)(uint16_t c[8], const uint8_t b[16], const uint8_t a[16],
uint8_t control) {
unsigned i, j;
uint16_t r[8];
for (i = 0; i < 8; ++i) {
r[i] = 0;
for (j = 0; j < 4; ++j) {
r[i] += ABS(b[(control & 4) + i + j] - a[(control & 3) * 4 + j]);
}
}
memcpy(c, r, 16);
}

View File

@ -0,0 +1,41 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_MPSADBW_H_
#define COSMOPOLITAN_LIBC_INTRIN_MPSADBW_H_
#include "libc/intrin/macros.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void mpsadbw(uint16_t[8], const uint8_t[16], const uint8_t[16], uint8_t);
#ifndef __STRICT_ANSI__
__intrin_xmm_t __mpsadbws(__intrin_xmm_t, __intrin_xmm_t);
#define mpsadbw(C, B, A, I) \
do { \
if (likely(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE4_1))) { \
__intrin_xmm_t *Xmm0 = (void *)(C); \
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
const __intrin_xmm_t *Xmm2 = (const __intrin_xmm_t *)(A); \
if (isconstant(I)) { \
if (!X86_NEED(AVX)) { \
asm("mpsadbw\t%2,%1,%0" \
: "=x"(*Xmm0) \
: "x"(*Xmm2), "i"(I), "0"(*Xmm1)); \
} else { \
asm("vmpsadbw\t%3,%2,%1,%0" \
: "=x"(*Xmm0) \
: "x"(*Xmm1), "x"(*Xmm2), "i"(I)); \
} \
} else { \
unsigned long Vimm = (I); \
typeof(__mpsadbws) *Fn; \
Fn = (typeof(__mpsadbws) *)((uintptr_t)&__mpsadbws + (Vimm & 7) * 8); \
*Xmm0 = Fn(*Xmm1, *Xmm2); \
} \
} else { \
mpsadbw(C, B, A, I); \
} \
} while (0)
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_MPSADBW_H_ */

View File

@ -19,24 +19,17 @@
*/
#include "libc/macros.h"
/ Phil Katz CRC-32 Polynomial
/ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
/ 0b100000100110000010001110110110111
/ bitreverse32(0x104c11db7)
#define kZipCrc32Polynomial 0xedb88320
.initbss 300,_init_kCrc32Tab
kCrc32Tab:
.rept 256
.long 0
/ Jump table for mpsadbw() with non-constexpr immediate parameter.
/
/ @note needs sse4 cf. core c. 2006 cf. bulldozer c. 2011
/ @see mpsadbw()
.align 8
__mpsadbws:
i = 0
.rept 8
mpsadbw $i,%xmm1,%xmm0
ret
nop
i = i + 1
.endr
.endobj kCrc32Tab,globl,hidden
.previous
.init.start 300,_init_kCrc32Tab
push %rsi
mov $kZipCrc32Polynomial,%esi
call crc32init
pop %rsi
.init.end 300,_init_kCrc32Tab
.source __FILE__
.endfn __mpsadbws,globl

View File

@ -14,7 +14,7 @@ forceinline void *repstosb(void *dest, unsigned char al, size_t cx) {
void *Di = (DI); \
size_t Cx = (CX); \
unsigned char Al = (AL); \
asm("rep stosb" \
asm("rep stosb %b5,(%0)" \
: "=D"(Di), "=c"(Cx), "=m"(*(char(*)[Cx])Di) \
: "0"(Di), "1"(Cx), "a"(Al)); \
Di; \

View File

@ -102,6 +102,111 @@ struct AsanGlobal {
char *odr_indicator;
};
struct AsanMorgue {
unsigned i;
void *p[16];
};
static struct AsanMorgue __asan_morgue;
static const char *__asan_dscribe_free_poison(int c) {
switch (c) {
case kAsanHeapFree:
return "heap double free";
case kAsanRelocated:
return "free after relocate";
case kAsanStackFree:
return "stack double free";
default:
return "invalid pointer";
}
}
static const char *__asan_describe_access_poison(int c) {
switch (c) {
case kAsanHeapFree:
return "heap use after free";
case kAsanStackFree:
return "stack use after release";
case kAsanRelocated:
return "heap use after relocate";
case kAsanHeapUnderrun:
return "heap underrun";
case kAsanHeapOverrun:
return "heap overrun";
case kAsanGlobalOverrun:
return "global overrun";
case kAsanGlobalUnregistered:
return "global unregistered";
case kAsanStackUnderrun:
return "stack underflow";
case kAsanStackOverrun:
return "stack overflow";
case kAsanAllocaOverrun:
return "alloca overflow";
case kAsanUnscoped:
return "unscoped";
default:
return "poisoned";
}
}
static noreturn void __asan_die(const char *msg, size_t size) {
__print(msg, size);
PrintBacktraceUsingSymbols(stderr, __builtin_frame_address(0),
getsymboltable());
DebugBreak();
_Exit(66);
}
static noreturn void __asan_report_deallocate_fault(void *addr, int c) {
char *p, ibuf[21], buf[256];
p = buf;
p = stpcpy(p, "error: ");
p = stpcpy(p, __asan_dscribe_free_poison(c));
p = stpcpy(p, " ");
p = mempcpy(p, ibuf, int64toarray_radix10(c, ibuf));
p = stpcpy(p, " at 0x");
p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)addr, ibuf, 48));
p = stpcpy(p, "\n");
__asan_die(buf, p - buf);
}
static noreturn void __asan_report_memory_fault(uint8_t *addr, int size,
const char *kind) {
char *p, ibuf[21], buf[256];
p = buf;
p = stpcpy(p, "error: ");
p = stpcpy(p, __asan_describe_access_poison(*(char *)SHADOW((intptr_t)addr)));
p = stpcpy(p, " ");
p = mempcpy(p, ibuf, uint64toarray_radix10(size, ibuf));
p = stpcpy(p, "-byte ");
p = stpcpy(p, kind);
p = stpcpy(p, " at 0x");
p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)addr, ibuf, 48));
p = stpcpy(p, "\n");
__asan_die(buf, p - buf);
}
static const void *__asan_morgue_add(void *p) {
void *r;
r = __asan_morgue.p[__asan_morgue.i];
__asan_morgue.p[__asan_morgue.i] = p;
__asan_morgue.i += 1;
__asan_morgue.i &= ARRAYLEN(__asan_morgue.p) - 1;
return r;
}
static void __asan_morgue_flush(void) {
void *p;
unsigned i;
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
p = __asan_morgue.p[i];
__asan_morgue.p[i] = NULL;
dlfree(p);
}
}
static bool __asan_is_mapped(void *p) {
int x, i;
x = (intptr_t)p >> 16;
@ -109,41 +214,8 @@ static bool __asan_is_mapped(void *p) {
return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y;
}
void __asan_map_shadow(void *addr, size_t size) {
int i, n, x;
char *a, *b;
struct DirectMap sm;
a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE);
b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE);
for (; a <= b; a += FRAMESIZE) {
if (!__asan_is_mapped(a)) {
sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (sm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16,
sm.maphandle) == -1) {
abort();
}
}
}
}
size_t __asan_malloc_usable_size(const void *vp) {
char *s;
size_t n;
for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) {
if (!*s) {
n += 8;
} else if (*s > 0) {
n += *s & 7;
} else {
break;
}
}
return n;
}
void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) {
static void *__asan_allocate(size_t align, size_t size, int underrun,
int overrun) {
char *p, *s;
size_t q, r, i;
if (!(p = dlmemalign(align, ROUNDUP(size, 8) + 16))) return NULL;
@ -160,29 +232,59 @@ void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) {
return p;
}
void __asan_deallocate(char *p, int kind) {
static void __asan_deallocate(char *p, int kind) {
char *s;
s = (char *)SHADOW((intptr_t)p);
if ((*s < 0 && *s != kAsanHeapOverrun) || *s >= 8) {
__asan_report_deallocate_fault(p, *s);
}
for (; *s >= 0; ++s) *s = kind;
dlfree(__asan_morgue_add(p));
}
static void __asan_poison_redzone(intptr_t addr, size_t size, size_t redsize,
int kind) {
char *s;
intptr_t p;
size_t a, b, w;
w = (intptr_t)addr & 7;
p = (intptr_t)addr - w;
a = w + size;
b = w + redsize;
s = (char *)SHADOW(p + a);
if (a & 7) *s++ = a & 7;
memset(s, kind, (b - ROUNDUP(a, 8)) >> 3);
}
static size_t __asan_malloc_usable_size(const void *vp) {
char *s;
size_t n;
s = (char *)SHADOW((intptr_t)p);
n = dlmalloc_usable_size(p);
n /= 8;
memset(s, kind, n);
dlfree(p);
for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) {
if (!*s) {
n += 8;
} else if (*s > 0) {
n += *s & 7;
} else {
break;
}
}
return n;
}
void __asan_free(void *vp) {
__asan_deallocate(vp, kAsanHeapFree);
static void __asan_free(void *p) {
if (!p) return;
__asan_deallocate(p, kAsanHeapFree);
}
void *__asan_memalign(size_t align, size_t size) {
static void *__asan_memalign(size_t align, size_t size) {
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun);
}
void *__asan_malloc(size_t size) {
static void *__asan_malloc(size_t size) {
return __asan_memalign(16, size);
}
void *__asan_calloc(size_t n, size_t m) {
static void *__asan_calloc(size_t n, size_t m) {
char *p;
size_t size;
if (__builtin_mul_overflow(n, m, &size)) size = -1;
@ -190,7 +292,7 @@ void *__asan_calloc(size_t n, size_t m) {
return p;
}
void *__asan_realloc(void *p, size_t n) {
static void *__asan_realloc(void *p, size_t n) {
char *p2;
if (p) {
if (n) {
@ -208,86 +310,32 @@ void *__asan_realloc(void *p, size_t n) {
return p2;
}
void *__asan_valloc(size_t n) {
static void *__asan_valloc(size_t n) {
return __asan_memalign(PAGESIZE, n);
}
void *__asan_pvalloc(size_t n) {
static void *__asan_pvalloc(size_t n) {
return __asan_valloc(ROUNDUP(n, PAGESIZE));
}
void __asan_poison(intptr_t addr, size_t size, size_t redsize, int kind) {
char *s;
intptr_t p;
size_t a, b, w;
w = (intptr_t)addr & 7;
p = (intptr_t)addr - w;
a = w + size;
b = w + redsize;
s = (char *)SHADOW(p + a);
if (a & 7) *s++ = a & 7;
memset(s, kind, (b - ROUNDUP(a, 8)) >> 3);
}
void __asan_register_globals(struct AsanGlobal g[], int n) {
size_t i;
unsigned i;
for (i = 0; i < n; ++i) {
__asan_poison((intptr_t)g[i].addr, g[i].size, g[i].size_with_redzone,
kAsanGlobalOverrun);
__asan_poison_redzone((intptr_t)g[i].addr, g[i].size,
g[i].size_with_redzone, kAsanGlobalOverrun);
}
}
void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) {
char *p, *s, ibuf[21], buf[256];
switch (*(char *)SHADOW((intptr_t)addr)) {
case kAsanStackFree:
s = "stack use after release";
break;
case kAsanHeapFree:
s = "heap use after free";
break;
case kAsanRelocated:
s = "heap use after relocate";
break;
case kAsanHeapUnderrun:
s = "heap underrun";
break;
case kAsanHeapOverrun:
s = "heap overrun";
break;
case kAsanStackUnderrun:
s = "stack underflow";
break;
case kAsanStackOverrun:
s = "stack overflow";
break;
case kAsanAllocaOverrun:
s = "alloca overflow";
break;
case kAsanUnscoped:
s = "unscoped";
break;
default:
s = "poisoned";
break;
void __asan_unregister_globals(struct AsanGlobal g[], int n) {
unsigned i;
intptr_t a, b;
for (i = 0; i < n; ++i) {
a = ROUNDUP((intptr_t)g[i].addr, 8);
b = ROUNDDOWN((intptr_t)g[i].addr + g[i].size_with_redzone, 8);
if (b > a) {
memset((char *)SHADOW(a), kAsanGlobalUnregistered, (b - a) >> 3);
}
}
p = buf;
p = stpcpy(p, "error: ");
p = stpcpy(p, s);
p = stpcpy(p, " ");
uint64toarray_radix10(size, ibuf);
p = stpcpy(p, ibuf);
p = stpcpy(p, "-byte ");
p = stpcpy(p, kind);
p = stpcpy(p, " at 0x");
uint64toarray_fixed16((intptr_t)addr, ibuf, 48);
p = stpcpy(p, ibuf);
p = stpcpy(p, "\n");
__print(buf, p - buf);
PrintBacktraceUsingSymbols(stderr, __builtin_frame_address(0),
getsymboltable());
DebugBreak();
_Exit(66);
}
void *__asan_stack_malloc(size_t size, int classid) {
@ -295,7 +343,7 @@ void *__asan_stack_malloc(size_t size, int classid) {
}
void __asan_stack_free(char *p, size_t size, int classid) {
return __asan_deallocate(p, kAsanStackFree);
dlfree(p);
}
void __asan_report_load_n(uint8_t *addr, int size) {
@ -316,16 +364,8 @@ void __asan_unpoison_stack_memory(uintptr_t p, size_t n) {
if (n & 7) *(char *)SHADOW(p + n) = n & 7;
}
void __asan_loadN(intptr_t ptr, size_t size) {
DebugBreak();
}
void __asan_storeN(intptr_t ptr, size_t size) {
DebugBreak();
}
void __asan_alloca_poison(intptr_t addr, size_t size) {
__asan_poison(addr, size, size + 32, kAsanAllocaOverrun);
__asan_poison_redzone(addr, size, size + 32, kAsanAllocaOverrun);
}
void __asan_allocas_unpoison(uintptr_t top, uintptr_t bottom) {
@ -352,7 +392,27 @@ void __asan_install_malloc_hooks(void) {
HOOK(hook$malloc_usable_size, __asan_malloc_usable_size);
}
void __asan_init(int argc, char *argv[], char **envp, intptr_t *auxv) {
void __asan_map_shadow(void *addr, size_t size) {
int i, n, x;
char *a, *b;
struct DirectMap sm;
a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE);
b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE);
for (; a <= b; a += FRAMESIZE) {
if (!__asan_is_mapped(a)) {
sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (sm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16,
sm.maphandle) == -1) {
abort();
}
}
}
}
textstartup void __asan_init(int argc, char *argv[], char **envp,
intptr_t *auxv) {
int i;
static bool once;
register intptr_t rsp asm("rsp");
@ -367,4 +427,9 @@ void __asan_init(int argc, char *argv[], char **envp, intptr_t *auxv) {
}
}
const void *const g_asan_ctor[] initarray = {getsymboltable};
static textstartup void __asan_ctor(void) {
/* __cxa_atexit(__asan_morgue_flush, NULL, NULL); */
getsymboltable();
}
const void *const g_asan_ctor[] initarray = {__asan_ctor};

View File

@ -9,10 +9,11 @@
#define kAsanHeapUnderrun -4
#define kAsanHeapOverrun -5
#define kAsanGlobalOverrun -6
#define kAsanStackUnderrun -7
#define kAsanStackOverrun -8
#define kAsanAllocaOverrun -9
#define kAsanUnscoped -10
#define kAsanGlobalUnregistered -7
#define kAsanStackUnderrun -8
#define kAsanStackOverrun -9
#define kAsanAllocaOverrun -10
#define kAsanUnscoped -11
#define SHADOW(x) (((x) >> kAsanScale) + kAsanMagic)

View File

@ -18,41 +18,29 @@
02110-1301 USA
*/
#include "libc/alg/bisectcarleft.h"
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/conv/itoa.h"
#include "libc/fmt/fmt.h"
#include "libc/log/backtrace.h"
#include "libc/macros.h"
#include "libc/nexgen32e/gc.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h"
static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr,
char *out, unsigned size, bool symbolic) {
int64_t addend;
const char *name;
const struct Symbol *symbol;
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end && symbolic)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
addend = addr - st->addr_base - symbol->addr_rva;
name = &st->name_base[symbol->name_rva];
snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', ABS(addend));
} else {
snprintf(out, size, "%p", addr);
}
return out;
}
#include "libc/str/str.h"
int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
struct SymbolTable *symbols) {
struct SymbolTable *st) {
size_t gi;
char buf[256];
intptr_t addr;
int64_t addend;
struct Garbages *garbage;
char *p, buf[256], ibuf[21];
const struct Symbol *symbol;
const struct StackFrame *frame;
if (!symbols) return -1;
if (!st) return -1;
garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) {
@ -62,8 +50,25 @@ int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
}
fprintf(f, "%p %p %s\n", frame, addr,
FormatAddress(f, symbols, addr, buf, sizeof(buf), true));
p = buf;
p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)frame, ibuf, 48));
*p++ = ' ';
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
*p++ = ' ';
if (st->count && ((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
p = stpcpy(p, &st->name_base[symbol->name_rva]);
addend = addr - st->addr_base - symbol->addr_rva;
*p++ = addend >= 0 ? '+' : '-';
if (addend) *p++ = '0', *p++ = 'x';
p = mempcpy(p, ibuf, uint64toarray_radix16(ABS(addend), ibuf));
} else {
p = stpcpy(p, "UNKNOWN");
}
*p++ = '\n';
__print(buf, p - buf);
}
return 0;
}

View File

@ -17,11 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/itoa.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
#include "libc/runtime/missioncritical.h"
/**
* Handles failure of CHECK_xx() macros in -DNDEBUG mode.
@ -35,8 +35,17 @@
*/
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) {
int lasterr = errno;
char bx[21];
int lasterr;
lasterr = errno;
startfatal_ndebug();
fprintf(stderr, "%s: %#lx %s %#lx (%s)\n", "check failed", want, opchar, got,
strerror(lasterr));
__print_string("check failed: 0x");
__print(bx, uint64toarray_radix16(want, bx));
__print_string(" ");
__print_string(opchar);
__print_string(" 0x");
__print(bx, uint64toarray_radix16(got, bx));
__print_string(" (");
__print(bx, int64toarray_radix10(lasterr, bx));
__print_string(")\n");
}

View File

@ -20,6 +20,7 @@
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/ok.h"
@ -31,12 +32,12 @@ nodiscard char *commandvenv(const char *var, const char *cmd) {
char pathbuf[PATH_MAX];
if ((exepath = getenv(var))) {
if (!isempty(exepath) && access(exepath, X_OK) != -1) {
return exepath;
return strdup(exepath);
} else {
return NULL;
}
} else if ((exepath = commandv(cmd, pathbuf))) {
return exepath;
return strdup(exepath);
} else {
return NULL;
}

View File

@ -24,7 +24,7 @@
STATIC_YOINK("ntoa");
void malloc_stats(void) {
struct MallocStats res = dlmalloc_stats(gm);
struct MallocStats res = dlmalloc_stats(g_dlmalloc);
(fprintf)(stderr, "max system bytes = %'10zu\n", res.maxfp);
(fprintf)(stderr, "system bytes = %'10zu\n", res.fp);
(fprintf)(stderr, "in use bytes = %'10zu\n", res.used);

View File

@ -27,64 +27,6 @@
/ since ASAN has the same stylistic hugeness as UBSAN.
/ We also guard all the functions, against reentrancy.
__asan_load1:
push $1
jmp OnLoad
.endfn __asan_load1,globl
__asan_load2:
push $2
jmp OnLoad
.endfn __asan_load2,globl
__asan_load4:
push $4
jmp OnLoad
.endfn __asan_load4,globl
__asan_load8:
push $8
jmp OnLoad
.endfn __asan_load8,globl
__asan_load16:
push $16
jmp OnLoad
.endfn __asan_load16,globl
__asan_load32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_load32,globl
OnLoad: pop %rsi
ezlea __asan_loadN,ax
jmp __asan_report_noreentry
.endfn OnStore
__asan_store1:
push $1
jmp OnStore
.endfn __asan_store1,globl
__asan_store2:
push $2
jmp OnStore
.endfn __asan_store2,globl
__asan_store4:
push $4
jmp OnStore
.endfn __asan_store4,globl
__asan_store8:
push $8
jmp OnStore
.endfn __asan_store8,globl
__asan_store16:
push $16
jmp OnStore
.endfn __asan_store16,globl
__asan_store32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_store32,globl
OnStore:pop %rsi
ezlea __asan_storeN,ax
jmp __asan_report_noreentry
.endfn OnStore
__asan_report_load1:
push $1
jmp OnReportLoad
@ -264,10 +206,6 @@ __asan_after_dynamic_init:
ret
.endfn __asan_after_dynamic_init,globl
__asan_unregister_globals:
ret
.endfn __asan_unregister_globals,globl
__asan_version_mismatch_check_v8:
ret
.endfn __asan_version_mismatch_check_v8,globl
@ -287,7 +225,7 @@ __asan_version_mismatch_check_v8:
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 1
.long 0
.endobj __asan_option_detect_stack_use_after_return,globl
.previous

View File

@ -17,10 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/log/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/missioncritical.h"
#include "libc/stdio/stdio.h"
#include "libc/calls/calls.h"
/**
* Prints initial part of fatal message.
@ -31,7 +29,7 @@
relegated void startfatal_ndebug(void) {
fflush(stdout);
fflush(stderr);
stderr->bufmode = _IOFBF;
fprintf(stderr, "%s%s%s:%s%s: ", RED, "error", BLUE1, program_invocation_name,
RESET);
__print_string("error:");
__print_string(program_invocation_name);
__print_string(": ");
}

View File

@ -32,17 +32,18 @@
static char __ubsan_buf[256];
static const char kUbsanTypeCheckKinds[] = "load of\0"
"store to\0"
"reference binding to\0"
"member access within\0"
"member call on\0"
"constructor call on\0"
"downcast of\0"
"downcast of\0"
"upcast of\0"
"cast to virtual base of\0"
"\0";
static const char kUbsanTypeCheckKinds[] = "\
load of\0\
store to\0\
reference binding to\0\
member access within\0\
member call on\0\
constructor call on\0\
downcast of\0\
downcast of\0\
upcast of\0\
cast to virtual base of\0\
\0";
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {

View File

@ -312,30 +312,6 @@ void sincosl(long double, long double *, long double *);
#define __X87_CONST(OP, VALUE) VALUE
#endif
#define fnstsw() __X87_FPU_STATUS("fnstsw")
#define fstsw() __X87_FPU_STATUS("fstsw")
#define __X87_FPU_STATUS(OP) \
({ \
unsigned short fpsr; \
asm volatile(OP "\t%0" : "=am"(fpsr)); \
fpsr; \
})
#define finit() __X87_INIT("finit")
#define fninit() __X87_INIT("fninit")
#define __X87_INIT(OP) \
({ \
long double st0, stm; \
asm volatile(OP \
: "=t"(st0) \
: /* no inputs */ \
: "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", \
"st(7)", "fpsr"); \
/* assume(!fpsr && fpcr == FPU_DEFAULT); */ \
asm("fst\t%0" : "=m"(stm) : "t"(st0)); \
st0; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_MATH_H_ */

View File

@ -3,8 +3,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const uint32_t kCrc32Tab[256];
void crc32init(uint32_t[hasatleast 256], uint32_t);
uint32_t crc32_z(uint32_t, const void *, size_t);
extern uint32_t (*const crc32c)(uint32_t, const void *, size_t) paramsnonnull();

View File

@ -18,7 +18,6 @@
02110-1301 USA
*/
#include "libc/macros.h"
.text.startup
/ Generates lookup table for computing CRC-32 byte-by-byte.
/

View File

@ -21,12 +21,25 @@
#include "libc/nexgen32e/crc32.h"
#include "libc/nexgen32e/x86feature.h"
static uint32_t kCrc32Tab[256];
/**
* Computes Phil Katz CRC-32 used by zip/zlib/gzip/etc.
*
* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
* 0b100000100110000010001110110110111
* bitreverse32(0x104c11db7)
*
* @param h is initial value
*/
uint32_t crc32_z(uint32_t h, const void *data, size_t size) {
const unsigned char *p, *pe;
static bool once;
size_t skip;
if (!once) {
crc32init(kCrc32Tab, 0xedb88320);
once = true;
}
if (data) {
h ^= 0xffffffff;
if (size >= 64 && X86_HAVE(PCLMUL)) {

View File

@ -12,8 +12,11 @@ struct NtWin32FindData {
uint32_t nFileSizeLow;
uint32_t dwReserved0;
uint32_t dwReserved1;
char16_t cFileName[PATH_MAX];
char16_t cFileName[260];
char16_t cAlternateFileName[14];
uint32_t dwFileType;
uint32_t dwCreatorType;
uint16_t wFinderFlags;
};
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View File

@ -0,0 +1,45 @@
/*-*- 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
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.text.exit
.source __FILE__
/ Calls linker registered finalization functions.
/ @note functions are called in reverse order
_destruct:
push %rbp
mov %rsp,%rbp
ezlea __fini_array_start,cx
.weak __fini_array_start
ezlea __fini_array_end,ax
.weak __fini_array_end
cmp %rax,%rcx
je 2f
1: sub $8,%rax
push %rax
push %rcx
call *(%rax)
pop %rcx
pop %rax
cmp %rax,%rcx
jne 1b
2: pop %rbp
ret
.endfn _destruct,globl

View File

@ -31,6 +31,7 @@ exit: push %rbp
push %rdi
xor %edi,%edi
call __cxa_finalize
call _destruct
pop %rdi
pop %rdi
call _Exit

View File

@ -136,7 +136,8 @@
} \
while (0)
interruptfn void __print(const void *, size_t);
void __print(const void *, size_t);
void __print_string(const char *);
#define LOAD_DEFAULT_RBX() /* disabled for now b/c clang */
#define RESTORE_RBX() /* disabled for now b/c clang */

View File

@ -49,9 +49,8 @@ static privileged void __print$nt(const void *data, size_t len) {
* @clob nothing except flags
* @see PRINT()
*/
privileged interruptfn void __print(const void *data, size_t len) {
privileged void __print(const void *data, size_t len) {
int64_t ax, ordinal;
LOAD_DEFAULT_RBX();
if (NT_HAVE_IMPORT(__imp_WriteFile)) {
__print$nt(data, len);
} else {
@ -69,3 +68,9 @@ privileged interruptfn void __print(const void *data, size_t len) {
}
RESTORE_RBX();
}
privileged void __print_string(const char *s) {
size_t n = 0;
while (s[n]) ++n;
__print(s, n);
}

View File

@ -34,6 +34,8 @@
* @return client fd which needs close(), or -1 w/ errno
*/
int accept4(int fd, void *out_addr, uint32_t *inout_addrsize, int flags) {
if (!out_addr) return efault();
if (!inout_addrsize) return efault();
if (!IsWindows()) {
return accept4$sysv(fd, out_addr, inout_addrsize, flags);
} else if (isfdkind(fd, kFdSocket)) {

View File

@ -35,6 +35,7 @@
* @asyncsignalsafe
*/
int bind(int fd, const void *addr, uint32_t addrsize) {
if (!addr) return efault();
if (addrsize == sizeof(struct sockaddr_in)) {
if (!IsWindows()) {
if (!IsBsd()) {

View File

@ -34,6 +34,7 @@
* @asyncsignalsafe
*/
int connect(int fd, const void *addr, uint32_t addrsize) {
if (!addr) return efault();
if (!IsWindows()) {
return connect$sysv(fd, addr, addrsize);
} else if (isfdkind(fd, kFdSocket)) {

View File

@ -108,7 +108,7 @@ int socket$nt(int, int, int) hidden;
size_t iovec2nt(struct iovec$nt[hasatleast 16], const struct iovec *,
size_t) hidden;
ssize_t sendto$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *,
uint32_t *) hidden;
uint32_t) hidden;
ssize_t recvfrom$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *,
uint32_t *) hidden;

View File

@ -18,8 +18,11 @@
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/fileno.h"
/**
* Performs send(), sendto(), or writev() on Windows NT.
@ -29,11 +32,11 @@
*/
textwindows ssize_t sendto$nt(struct Fd *fd, const struct iovec *iov,
size_t iovlen, uint32_t flags, void *opt_in_addr,
uint32_t *in_addrsize) {
uint32_t in_addrsize) {
uint32_t sent;
struct iovec$nt iovnt[16];
if (WSASendTo(fd->handle, iovnt, iovec2nt(iovnt, iov, iovlen), &sent, flags,
opt_in_addr, *in_addrsize, NULL, NULL) != -1) {
opt_in_addr, in_addrsize, NULL, NULL) != -1) {
return sent;
} else {
return winsockerr();

View File

@ -60,7 +60,7 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
}
} else if (isfdkind(fd, kFdSocket)) {
return sendto$nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags,
opt_addr, &addrsize);
opt_addr, addrsize);
} else {
return ebadf();
}

View File

@ -51,7 +51,7 @@ static textwindows int setsockopt$nt(struct Fd *fd, int level, int optname,
* int yes = 1;
* setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes));
*
* @param level can be SOL_SOCKET, IPPROTO_TCP, etc.
* @param level can be SOL_SOCKET, SOL_IP, SOL_TCP, etc.
* @param optname can be SO_{REUSE{PORT,ADDR},KEEPALIVE,etc.} etc.
* @return 0 on success, or -1 w/ errno
* @error ENOPROTOOPT for unknown (level,optname)
@ -60,6 +60,7 @@ static textwindows int setsockopt$nt(struct Fd *fd, int level, int optname,
*/
int setsockopt(int fd, int level, int optname, const void *optval,
uint32_t optlen) {
if (!optval) return efault();
if (!level || !optname) return enoprotoopt(); /* our sysvconsts definition */
if (optname == -1) return 0; /* our sysvconsts definition */
if (!IsWindows()) {

View File

@ -61,10 +61,10 @@ int inet_pton(int af, const char *, void *);
int parseport(const char *);
int socket(int, int, int) nodiscard;
int accept(int, void *, uint32_t *) paramsnonnull() nodiscard;
int accept4(int, void *, uint32_t *, int) paramsnonnull() nodiscard;
int bind(int, const void *, uint32_t) paramsnonnull();
int connect(int, const void *, uint32_t) paramsnonnull();
int accept(int, void *, uint32_t *) nodiscard;
int accept4(int, void *, uint32_t *, int) nodiscard;
int bind(int, const void *, uint32_t);
int connect(int, const void *, uint32_t);
int socketconnect(const struct addrinfo *, int);
int listen(int, int);
int shutdown(int, int);
@ -79,7 +79,7 @@ ssize_t readv(int, const struct iovec *, int);
ssize_t writev(int, const struct iovec *, int);
ssize_t sendfile(int, int, int64_t *, size_t);
int getsockopt(int, int, int, void *, uint32_t *) paramsnonnull((5));
int setsockopt(int, int, int, const void *, uint32_t) paramsnonnull();
int setsockopt(int, int, int, const void *, uint32_t);
int socketpair(int, int, int, int64_t[2]) paramsnonnull();
int poll(struct pollfd *, uint64_t, int32_t) paramsnonnull();
int ppoll(struct pollfd *, uint64_t, const struct timespec *,

View File

@ -17,16 +17,20 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/limits.h"
#include "libc/str/str.h"
/**
* Copies string, returning pointer to where copying ended.
*
* @see strcpy(), mempcpy()
* Copies string and advances destination pointer.
* @asyncsignalsafe
*/
char *stpcpy(char *dst, const char *src) {
dst = memccpy(dst, src, '\0', SIZE_MAX);
return dst - 1;
char c;
for (;;) {
c = *src;
*dst = c;
if (!c) break;
++src;
++dst;
}
return dst;
}

View File

@ -471,8 +471,6 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque;
#else /* hosted/sse2/unbloat */
#define memmove(DEST, SRC, SIZE) __memcpy((DEST), (SRC), (SIZE))
#define mempcpy(DEST, SRC, SIZE) \
({ \
void *Rdi, *Dest = (DEST); \
@ -513,21 +511,6 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque;
#endif /* hosted/sse2/unbloat */
#if __STDC_VERSION__ + 0 >= 201112
#define strlen(s) \
chooseexpr((typescompatible(typeof(s), const char[]) && \
isconstant(((const char *)(s))[0])), \
sizeof(s) - 1, \
_Generic(*(s), wchar_t \
: wcslen, char16_t \
: strlen16, default \
: _strlen)(s))
#else
#define strlen(s) \
chooseexpr(isconstant(s) && typescompatible(typeof(s), const char[]), \
__builtin_strlen(s), _strlen(s))
#endif /* C11+ */
#define pututf16(BUF, SIZE, CH, AWESOME) __pututf16(BUF, SIZE, CH, AWESOME)
#define getutf16(BUF, CHPTR) __getutf16(BUF, CHPTR)
size_t _strlen(const char *s) asm("strlen") strlenesque;

View File

@ -42,10 +42,6 @@ $(LIBC_STR_A).pkg: \
$(LIBC_STR_A_OBJS) \
$(foreach x,$(LIBC_STR_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/str/lz4cpy.o: \
OVERRIDE_CFLAGS += \
$(NO_MAGIC)
LIBC_STR_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)))
LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS))
LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS))

View File

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.inc"
.scall getdents 0x00630110ffff004e globl hidden
.scall getdents 0x00630110ffff00d9 globl hidden

View File

@ -1313,6 +1313,18 @@ syscon ex EX_CONFIG 78 78 78 78 78 # unix consensus & force NT
syscon ex EX__BASE 64 64 64 64 64 # unix consensus & force NT
syscon ex EX__MAX 78 78 78 78 78 # unix consensus & force NT
# getdents() constants
#
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
syscon dt DT_UNKNOWN 0 0 0 0 0 # consensus
syscon dt DT_FIFO 1 1 1 1 1 # unix consensus & faked nt
syscon dt DT_CHR 2 2 2 2 2 # unix consensus & faked nt
syscon dt DT_DIR 4 4 4 4 4 # unix consensus & faked nt
syscon dt DT_BLK 6 6 6 6 6 # unix consensus & faked nt
syscon dt DT_REG 8 8 8 8 8 # unix consensus & faked nt
syscon dt DT_LNK 10 10 10 10 10 # unix consensus & faked nt
syscon dt DT_SOCK 12 12 12 12 12 # unix consensus & faked nt
# msync() flags
#
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary
@ -1382,6 +1394,10 @@ syscon msg MSG_SYN 0x0400 0 0 0 0
syscon sol SOL_IP 0 0 0 0 0 # consensus
syscon sol SOL_SOCKET 1 0xffff 0xffff 0xffff 0xffff # bsd+nt consensus
syscon sol SOL_TCP 6 6 6 6 6
syscon sol SOL_UDP 17 17 17 17 17
syscon sol SOL_IPV6 41 41 41 41 41
syscon sol SOL_ICMPV6 58 58 58 58 0
syscon sol SOL_AAL 265 0 0 0 0
syscon sol SOL_ALG 279 0 0 0 0
syscon sol SOL_ATM 264 0 0 0 0
@ -1389,8 +1405,6 @@ syscon sol SOL_BLUETOOTH 274 0 0 0 0
syscon sol SOL_CAIF 278 0 0 0 0
syscon sol SOL_DCCP 269 0 0 0 0
syscon sol SOL_DECNET 261 0 0 0 0
syscon sol SOL_ICMPV6 58 0 0 0 0
syscon sol SOL_IPV6 41 0 0 0 0
syscon sol SOL_IRDA 266 0 0 0 0
syscon sol SOL_IUCV 277 0 0 0 0
syscon sol SOL_KCM 281 0 0 0 0
@ -1404,9 +1418,7 @@ syscon sol SOL_PPPOL2TP 273 0 0 0 0
syscon sol SOL_RAW 255 0 0 0 0
syscon sol SOL_RDS 276 0 0 0 0
syscon sol SOL_RXRPC 272 0 0 0 0
syscon sol SOL_TCP 6 0 0 0 0
syscon sol SOL_TIPC 271 0 0 0 0
syscon sol SOL_UDP 17 0 0 0 0
syscon sol SOL_X25 262 0 0 0 0
syscon in IN_LOOPBACKNET 127 127 127 127 0 # unix consensus
@ -1656,15 +1668,6 @@ syscon misc BLKSECTGET 0x1267 0 0 0 0
syscon misc BLKSECTSET 0x1266 0 0 0 0
syscon misc BLKSSZGET 0x1268 0 0 0 0
syscon misc DT_UNKNOWN 0 0 0 0 0 # consensus
syscon misc DT_BLK 6 6 6 6 0 # unix consensus
syscon misc DT_CHR 2 2 2 2 0 # unix consensus
syscon misc DT_DIR 4 4 4 4 0 # unix consensus
syscon misc DT_FIFO 1 1 1 1 0 # unix consensus
syscon misc DT_LNK 10 10 10 10 0 # unix consensus
syscon misc DT_REG 8 8 8 8 0 # unix consensus
syscon misc DT_SOCK 12 12 12 12 0 # unix consensus
syscon misc TH_FIN 1 1 1 1 1 # consensus
syscon misc TH_SYN 2 2 2 2 2 # consensus
syscon misc TH_RST 4 4 4 4 4 # consensus

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_BLK 6 6 6 6 0
.syscon dt DT_BLK 6 6 6 6 6

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_CHR 2 2 2 2 0
.syscon dt DT_CHR 2 2 2 2 2

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_DIR 4 4 4 4 0
.syscon dt DT_DIR 4 4 4 4 4

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_FIFO 1 1 1 1 0
.syscon dt DT_FIFO 1 1 1 1 1

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_LNK 10 10 10 10 0
.syscon dt DT_LNK 10 10 10 10 10

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_REG 8 8 8 8 0
.syscon dt DT_REG 8 8 8 8 8

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_SOCK 12 12 12 12 0
.syscon dt DT_SOCK 12 12 12 12 12

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon misc DT_UNKNOWN 0 0 0 0 0
.syscon dt DT_UNKNOWN 0 0 0 0 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon sol SOL_ICMPV6 58 0 0 0 0
.syscon sol SOL_ICMPV6 58 58 58 58 0

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon sol SOL_IPV6 41 0 0 0 0
.syscon sol SOL_IPV6 41 41 41 41 41

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon sol SOL_TCP 6 0 0 0 0
.syscon sol SOL_TCP 6 6 6 6 6

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon sol SOL_UDP 17 0 0 0 0
.syscon sol SOL_UDP 17 17 17 17 17

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc"
.syscon ioctl TIOCOUTQ 0x5411 0x40047473 0x40047473 0x40047473 -1
.syscon termios TIOCOUTQ 0x5411 0x40047473 0x40047473 0x40047473 -1

View File

@ -1,28 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_
#include "libc/runtime/symbolic.h"
#define DT_BLK SYMBOLIC(DT_BLK)
#define DT_CHR SYMBOLIC(DT_CHR)
#define DT_DIR SYMBOLIC(DT_DIR)
#define DT_FIFO SYMBOLIC(DT_FIFO)
#define DT_LNK SYMBOLIC(DT_LNK)
#define DT_REG SYMBOLIC(DT_REG)
#define DT_SOCK SYMBOLIC(DT_SOCK)
#define DT_UNKNOWN SYMBOLIC(DT_UNKNOWN)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
hidden extern const long DT_BLK;
hidden extern const long DT_UNKNOWN;
hidden extern const long DT_FIFO;
hidden extern const long DT_CHR;
hidden extern const long DT_DIR;
hidden extern const long DT_FIFO;
hidden extern const long DT_LNK;
hidden extern const long DT_BLK;
hidden extern const long DT_REG;
hidden extern const long DT_LNK;
hidden extern const long DT_SOCK;
hidden extern const long DT_UNKNOWN;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#define DT_UNKNOWN LITERALLY(0)
#define DT_FIFO LITERALLY(1)
#define DT_CHR LITERALLY(2)
#define DT_DIR LITERALLY(4)
#define DT_BLK LITERALLY(6)
#define DT_REG LITERALLY(8)
#define DT_LNK LITERALLY(10)
#define DT_SOCK LITERALLY(12)
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_ */

View File

@ -243,7 +243,7 @@ scall lookup_dcookie 0xffffffffffff00d4 globl
scall epoll_create 0xffffffffffff00d5 globl
scall epoll_wait 0xffffffffffff00e8 globl
scall epoll_ctl 0xffffffffffff00e9 globl
scall getdents 0x00630110ffff004e globl hidden
scall getdents 0x00630110ffff00d9 globl hidden # getdents64 on linux
scall set_tid_address 0xffffffffffff00da globl
scall restart_syscall 0xffffffffffff00db globl
scall semtimedop 0xffffffffffff00dc globl

View File

@ -24,7 +24,7 @@
testonly void testlib_formatbinaryasglyphs(const char16_t *want,
const void *got, size_t n,
char **out_v1, char **out_v2) {
if (n == -1ul) n = strlen(want);
if (n == -1ul) n = strlen16(want);
*out_v1 = xasprintf("%`#.*hs", n, want);
*out_v2 = xasprintf(" %`'#.*s", n, got);
}

View File

@ -28,7 +28,7 @@ static unsigned clip(unsigned index, unsigned count) {
return index < count ? index : 0;
}
char *asctime_r(const struct tm *date, char *buf /*[64]*/) {
char *asctime_r(const struct tm *date, char buf[hasatleast 64]) {
(snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
kWeekdayNameShort[clip(date->tm_wday, 7)],
kMonthNameShort[clip(date->tm_mon, 12)], date->tm_mday,

View File

@ -20,7 +20,7 @@
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
char *ctime_r(const int64_t *timep, char *buf /*[64]*/) {
char *ctime_r(const int64_t *timep, char buf[hasatleast 64]) {
struct tm date[1];
return asctime_r(localtime_r(timep, date), buf);
}

View File

@ -18,7 +18,9 @@
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/time.h"
/**

View File

@ -1,3 +1,6 @@
/*-*- mode:c; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
*/
#include "libc/bits/initializer.h"
#include "libc/calls/calls.h"
#include "libc/macros.h"
@ -13,7 +16,6 @@
#define ALL_STATE
#define P(x) x
#define time_t int64_t
#define int_fast64_t int64_t
#define int_fast32_t int32_t
@ -25,13 +27,6 @@
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
#define TM_ZONE tm_zone
#define INITIALIZE(x) x = 0
static int is_digit(int c) {
return isdigit(c);
}
asm(".ident\t\"\\n\\n\
localtime (Public Domain)\\n\
Credit: Arthur David Olson\"");
STATIC_YOINK("usr/share/zoneinfo/GST");
@ -157,48 +152,37 @@ struct rule {
** Prototypes for static functions.
*/
static int32_t detzcode P((const char * codep));
static time_t detzcode64 P((const char * codep));
static int differ_by_repeat P((time_t t1, time_t t0));
static const char * getzname P((const char * strp));
static const char * getqzname P((const char * strp, const int delim));
static const char * getnum P((const char * strp, int * nump, int min,
int max));
static const char * getsecs P((const char * strp, int32_t * secsp));
static const char * getoffset P((const char * strp, int32_t * offsetp));
static const char * getrule P((const char * strp, struct rule * rulep));
static void gmtload P((struct state * sp));
static struct tm * gmtsub P((const time_t * timep, int32_t offset,
struct tm * tmp));
static struct tm * localsub P((const time_t * timep, int32_t offset,
struct tm * tmp));
static int increment_overflow P((int * number, int delta));
static int leaps_thru_end_of P((int y));
static int normalize_overflow P((int * tensptr, int * unitsptr,
int base));
static void settzname P((void));
static time_t time1 P((struct tm * tmp,
struct tm * (*funcp) P((const time_t *,
int32_t, struct tm *)),
int32_t offset));
static time_t time2 P((struct tm *tmp,
struct tm * (*funcp) P((const time_t *,
int32_t, struct tm*)),
int32_t offset, int * okayp));
static time_t time2sub P((struct tm *tmp,
struct tm * (*funcp) P((const time_t *,
int32_t, struct tm*)),
int32_t offset, int * okayp, int do_norm_secs));
static struct tm * timesub P((const time_t * timep, int32_t offset,
const struct state * sp, struct tm * tmp));
static int tmcomp P((const struct tm * atmp,
const struct tm * btmp));
static time_t transtime P((time_t janfirst, int year,
const struct rule * rulep, int32_t offset));
static int tzload P((const char * name, struct state * sp,
int doextend));
static int tzparse P((const char * name, struct state * sp,
int lastditch));
static int32_t detzcode(const char *);
static time_t detzcode64(const char *);
static int differ_by_repeat(time_t, time_t);
static const char * getzname(const char *);
static const char * getqzname(const char *, const int);
static const char * getnum(const char *, int *, int, int);
static const char * getsecs(const char *, int32_t *);
static const char * getoffset(const char *, int32_t *);
static const char * getrule(const char *, struct rule *);
static void gmtload(struct state *);
static struct tm * gmtsub(const time_t *, int32_t, struct tm *);
static struct tm * localsub(const time_t *, int32_t, struct tm *);
static int increment_overflow(int *, int);
static int leaps_thru_end_of(int);
static int normalize_overflow(int *, int *, int);
static void settzname(void);
static time_t time1(struct tm *, struct tm * (*)(const time_t *,
int32_t, struct tm *),
int32_t);
static time_t time2(struct tm *, struct tm *(*)(const time_t *,
int32_t, struct tm *),
int32_t, int *);
static time_t time2sub(struct tm *, struct tm *(*)(const time_t *,
int32_t, struct tm*),
int32_t, int *, int);
static struct tm * timesub(const time_t *, int32_t,
const struct state *, struct tm *);
static int tmcomp(const struct tm *, const struct tm *);
static time_t transtime(time_t, int, const struct rule *, int32_t);
static int tzload(const char *, struct state *, int);
static int tzparse(const char *, struct state *, int);
#ifdef ALL_STATE
static struct state * lclptr;
@ -242,21 +226,20 @@ INITIALIZER(400, _init_localtime, {
static struct tm tm;
#ifdef USG_COMPAT
time_t timezone = 0;
int daylight = 0;
time_t timezone;
int daylight;
#endif /* defined USG_COMPAT */
#ifdef ALTZONE
time_t altzone = 0;
time_t altzone;
#endif /* defined ALTZONE */
static int32_t
detzcode(codep)
const char * const codep;
const char * const codep;
{
register int32_t result;
register int i;
result = (codep[0] & 0x80) ? ~0L : 0;
for (i = 0; i < 4; ++i)
result = ((unsigned)result << 8) | (codep[i] & 0xff);
@ -265,11 +248,10 @@ const char * const codep;
static time_t
detzcode64(codep)
const char * const codep;
const char * const codep;
{
register time_t result;
register int i;
result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
for (i = 0; i < 8; ++i)
result = result * 256 + (codep[i] & 0xff);
@ -277,11 +259,11 @@ const char * const codep;
}
static void
settzname P((void))
settzname(void)
{
register struct state * const sp = lclptr;
register struct state * sp;
register int i;
sp = lclptr;
tzname[0] = wildabbr2;
tzname[1] = wildabbr2;
#ifdef USG_COMPAT
@ -299,7 +281,6 @@ settzname P((void))
#endif /* defined ALL_STATE */
for (i = 0; i < sp->typecnt; ++i) {
register const struct ttinfo * const ttisp = &sp->ttis[i];
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
#ifdef USG_COMPAT
@ -320,7 +301,6 @@ settzname P((void))
register const struct ttinfo * const ttisp =
&sp->ttis[
sp->types[i]];
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
}
@ -337,7 +317,6 @@ settzname P((void))
for (i = 0; i < sp->typecnt; ++i) {
register const struct ttinfo * const ttisp = &sp->ttis[i];
register char * cp = &sp->chars[ttisp->tt_abbrind];
if (strlen(cp) > TZ_ABBR_MAX_LEN &&
strcmp(cp, GRANDPARENTED) != 0)
*(cp + TZ_ABBR_MAX_LEN) = '\0';
@ -346,8 +325,8 @@ settzname P((void))
forceinline int
differ_by_repeat(t1, t0)
const time_t t1;
const time_t t0;
const time_t t1;
const time_t t0;
{
if (TYPE_INTEGRAL(time_t) &&
TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
@ -355,9 +334,14 @@ const time_t t0;
return (t1 - t0) == SECSPERREPEAT;
}
/* static int toint(unsigned char *s) { */
/* return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; */
/* } */
forceinline int
cmpstr(l, r)
const char *l, *r;
{
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 0xff) - (r[i] & 0xff);
}
static int
typesequiv(sp, a, b)
@ -376,7 +360,7 @@ typesequiv(sp, a, b)
ap->tt_isdst == bp->tt_isdst &&
ap->tt_ttisstd == bp->tt_ttisstd &&
ap->tt_ttisgmt == bp->tt_ttisgmt &&
strcmp(&sp->chars[ap->tt_abbrind],
cmpstr(&sp->chars[ap->tt_abbrind],
&sp->chars[bp->tt_abbrind]) == 0;
}
return result;
@ -384,9 +368,9 @@ typesequiv(sp, a, b)
static int
tzload(name, sp, doextend)
register const char * name;
register struct state * const sp;
register const int doextend;
register const char * name;
register struct state * const sp;
register const int doextend;
{
register const char * p;
register int i;
@ -612,12 +596,12 @@ oops:
return -1;
}
static const int mon_lengths[2][MONSPERYEAR] = {
static const unsigned char kMonthLengths[2][MONSPERYEAR] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static const int year_lengths[2] = {
static const int kYearLengths[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
@ -629,13 +613,13 @@ static const int year_lengths[2] = {
static const char *
getzname(strp)
register const char * strp;
const char * strp;
{
register char c;
while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
c != '+')
char c;
while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
c != '+') {
++strp;
}
return strp;
}
@ -649,7 +633,9 @@ register const char * strp;
*/
static const char *
getqzname(register const char *strp, const int delim)
getqzname(strp, delim)
register const char * strp;
const int delim;
{
register int c;
@ -667,15 +653,15 @@ getqzname(register const char *strp, const int delim)
static const char *
getnum(strp, nump, min, max)
register const char * strp;
int * const nump;
const int min;
const int max;
register const char * strp;
int * const nump;
const int min;
const int max;
{
register char c;
register int num;
if (strp == NULL || !is_digit(c = *strp))
if (strp == NULL || !isdigit(c = *strp))
return NULL;
num = 0;
do {
@ -683,7 +669,7 @@ const int max;
if (num > max)
return NULL; /* illegal value */
c = *++strp;
} while (is_digit(c));
} while (isdigit(c));
if (num < min)
return NULL; /* illegal value */
*nump = num;
@ -700,11 +686,10 @@ const int max;
static const char *
getsecs(strp, secsp)
register const char * strp;
int32_t * const secsp;
register const char * strp;
int32_t * const secsp;
{
int num;
/*
** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
** "M10.4.6/26", which does not conform to Posix,
@ -742,11 +727,10 @@ int32_t * const secsp;
static const char *
getoffset(strp, offsetp)
register const char * strp;
int32_t * const offsetp;
register const char * strp;
int32_t * const offsetp;
{
register int neg = 0;
if (*strp == '-') {
neg = 1;
++strp;
@ -769,8 +753,8 @@ int32_t * const offsetp;
static const char *
getrule(strp, rulep)
const char * strp;
register struct rule * const rulep;
const char * strp;
register struct rule * const rulep;
{
if (*strp == 'J') {
/*
@ -796,7 +780,7 @@ register struct rule * const rulep;
if (*strp++ != '.')
return NULL;
strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
} else if (is_digit(*strp)) {
} else if (isdigit(*strp)) {
/*
** Day of year.
*/
@ -865,7 +849,7 @@ const int32_t offset;
*/
value = janfirst;
for (i = 0; i < rulep->r_mon - 1; ++i)
value += mon_lengths[leapyear][i] * SECSPERDAY;
value += kMonthLengths[leapyear][i] * SECSPERDAY;
/*
** Use Zeller's Congruence to get day-of-week of first day of
@ -890,7 +874,7 @@ const int32_t offset;
d += DAYSPERWEEK;
for (i = 1; i < rulep->r_week; ++i) {
if (d + DAYSPERWEEK >=
mon_lengths[leapyear][rulep->r_mon - 1])
kMonthLengths[leapyear][rulep->r_mon - 1])
break;
d += DAYSPERWEEK;
}
@ -1036,7 +1020,7 @@ tzparse(name, sp, lastditch)
}
sp->timecnt += 2;
newfirst = janfirst;
newfirst += year_lengths[isleap(year)] *
newfirst += kYearLengths[isleap(year)] *
SECSPERDAY;
if (newfirst <= janfirst)
break;
@ -1153,7 +1137,7 @@ tzparse(name, sp, lastditch)
static void
gmtload(sp)
struct state * const sp;
struct state * const sp;
{
if (tzload(gmt, sp, TRUE) != 0)
(void) tzparse(gmt, sp, TRUE);
@ -1167,7 +1151,7 @@ struct state * const sp;
static
#endif /* !defined STD_INSPIRED */
void
tzsetwall P((void))
tzsetwall(void)
{
if (lcl_is_set < 0)
return;
@ -1188,7 +1172,7 @@ tzsetwall P((void))
}
void
tzset P((void))
tzset(void)
{
register const char * name = NULL;
/* static char buf[PROP_VALUE_MAX]; */
@ -1248,9 +1232,9 @@ tzset P((void))
/*ARGSUSED*/
static struct tm *
localsub(timep, offset, tmp)
const time_t * const timep;
const int32_t offset;
struct tm * const tmp;
const time_t * const timep;
const int32_t offset;
struct tm * const tmp;
{
register struct state * sp;
register const struct ttinfo * ttisp;
@ -1340,7 +1324,7 @@ struct tm * const tmp;
struct tm *
localtime(timep)
const time_t * const timep;
const time_t * const timep;
{
tzset();
return localsub(timep, 0L, &tm);
@ -1352,8 +1336,8 @@ const time_t * const timep;
struct tm *
localtime_r(timep, tmp)
const time_t * const timep;
struct tm * tmp;
const time_t * const timep;
struct tm * tmp;
{
tzset();
return localsub(timep, 0L, tmp);
@ -1365,12 +1349,11 @@ struct tm * tmp;
static struct tm *
gmtsub(timep, offset, tmp)
const time_t * const timep;
const int32_t offset;
struct tm * const tmp;
const time_t * const timep;
const int32_t offset;
struct tm * const tmp;
{
register struct tm * result;
if (!gmt_is_set) {
gmt_is_set = TRUE;
#ifdef ALL_STATE
@ -1404,7 +1387,7 @@ struct tm * const tmp;
struct tm *
gmtime(timep)
const time_t * const timep;
const time_t * const timep;
{
return gmtsub(timep, 0L, &tm);
}
@ -1415,8 +1398,8 @@ const time_t * const timep;
struct tm *
gmtime_r(timep, tmp)
const time_t * const timep;
struct tm * tmp;
const time_t * const timep;
struct tm * tmp;
{
return gmtsub(timep, 0L, tmp);
}
@ -1425,8 +1408,8 @@ struct tm * tmp;
struct tm *
offtime(timep, offset)
const time_t * const timep;
const int32_t offset;
const time_t * const timep;
const int32_t offset;
{
return gmtsub(timep, offset, &tm);
}
@ -1440,7 +1423,7 @@ const int32_t offset;
pureconst static int
leaps_thru_end_of(y)
register const int y;
register const int y;
{
return (y >= 0) ? (y / 4 - div100int64(y) + y / 400) :
-(leaps_thru_end_of(-(y + 1)) + 1);
@ -1448,20 +1431,20 @@ register const int y;
static struct tm *
timesub(timep, offset, sp, tmp)
const time_t * const timep;
const int32_t offset;
register const struct state * const sp;
register struct tm * const tmp;
const time_t * const timep;
const int32_t offset;
const struct state * const sp;
struct tm * const tmp;
{
register const struct lsinfo * lp;
register time_t tdays;
register int idays; /* unsigned would be so 2003 */
register long rem; /* ^wut */
const struct lsinfo * lp;
time_t tdays;
int idays; /* unsigned would be so 2003 */
long rem; /* ^wut */
int y;
register const int * ip;
register long corr;
register int hit;
register int i;
int leap;
long corr;
int hit;
int i;
corr = 0;
hit = 0;
@ -1494,7 +1477,7 @@ register struct tm * const tmp;
y = EPOCH_YEAR;
tdays = *timep / SECSPERDAY;
rem = *timep - tdays * SECSPERDAY;
while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
while (tdays < 0 || tdays >= kYearLengths[isleap(y)]) {
int newy;
register time_t tdelta;
register int idelta;
@ -1538,10 +1521,10 @@ register struct tm * const tmp;
while (idays < 0) {
if (increment_overflow(&y, -1))
return NULL;
idays += year_lengths[isleap(y)];
idays += kYearLengths[isleap(y)];
}
while (idays >= year_lengths[isleap(y)]) {
idays -= year_lengths[isleap(y)];
while (idays >= kYearLengths[isleap(y)]) {
idays -= kYearLengths[isleap(y)];
if (increment_overflow(&y, 1))
return NULL;
}
@ -1569,9 +1552,12 @@ register struct tm * const tmp;
** representation. This uses "... ??:59:60" et seq.
*/
tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
ip = mon_lengths[isleap(y)];
for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
idays -= ip[tmp->tm_mon];
leap = isleap(y);
for (tmp->tm_mon = 0;
idays >= kMonthLengths[leap][tmp->tm_mon];
++(tmp->tm_mon)) {
idays -= kMonthLengths[leap][tmp->tm_mon];
}
tmp->tm_mday = (int) (idays + 1);
tmp->tm_isdst = 0;
#ifdef TM_GMTOFF
@ -1621,11 +1607,10 @@ register struct tm * const tmp;
static int
increment_overflow(number, delta)
int * number;
int delta;
int * number;
int delta;
{
int number0;
number0 = *number;
*number += delta;
return (*number < number0) != (delta < 0);
@ -1633,12 +1618,11 @@ int delta;
static int
normalize_overflow(tensptr, unitsptr, base)
int * const tensptr;
int * const unitsptr;
const int base;
int * const tensptr;
int * const unitsptr;
const int base;
{
register int tensdelta;
tensdelta = (*unitsptr >= 0) ?
(*unitsptr / base) :
(-1 - (-1 - *unitsptr) / base);
@ -1648,11 +1632,10 @@ const int base;
static int
tmcomp(atmp, btmp)
register const struct tm * const atmp;
register const struct tm * const btmp;
register const struct tm * const atmp;
register const struct tm * const btmp;
{
register int result;
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
@ -1664,11 +1647,11 @@ register const struct tm * const btmp;
static time_t
time2sub(tmp, funcp, offset, okayp, do_norm_secs)
struct tm * const tmp;
struct tm * (* const funcp) P((const time_t*, int32_t, struct tm*));
const int32_t offset;
int * const okayp;
const int do_norm_secs;
struct tm * const tmp;
struct tm * (* const funcp)(const time_t*, int32_t, struct tm*);
const int32_t offset;
int * const okayp;
const int do_norm_secs;
{
register const struct state * sp;
register int dir;
@ -1681,7 +1664,6 @@ const int do_norm_secs;
time_t newt;
time_t t;
struct tm yourtm, mytm;
*okayp = FALSE;
yourtm = *tmp;
if (do_norm_secs) {
@ -1706,16 +1688,16 @@ const int do_norm_secs;
if (increment_overflow(&y, -1))
return WRONG;
li = y + (1 < yourtm.tm_mon);
yourtm.tm_mday += year_lengths[isleap(li)];
yourtm.tm_mday += kYearLengths[isleap(li)];
}
while (yourtm.tm_mday > DAYSPERLYEAR) {
li = y + (1 < yourtm.tm_mon);
yourtm.tm_mday -= year_lengths[isleap(li)];
yourtm.tm_mday -= kYearLengths[isleap(li)];
if (increment_overflow(&y, 1))
return WRONG;
}
for ( ; ; ) {
i = mon_lengths[isleap(y)][yourtm.tm_mon];
i = kMonthLengths[isleap(y)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
break;
yourtm.tm_mday -= i;
@ -1852,13 +1834,12 @@ label:
static time_t
time2(tmp, funcp, offset, okayp)
struct tm * const tmp;
struct tm * (* const funcp) P((const time_t*, int32_t, struct tm*));
const int32_t offset;
int * const okayp;
struct tm * const tmp;
struct tm * (* const funcp)(const time_t*, int32_t, struct tm*);
const int32_t offset;
int * const okayp;
{
time_t t;
/*
** First try without normalization of seconds
** (in case tm_sec contains a value associated with a leap second).
@ -1870,9 +1851,9 @@ int * const okayp;
static time_t
time1(tmp, funcp, offset)
struct tm * const tmp;
struct tm * (* const funcp) P((const time_t *, int32_t, struct tm *));
const int32_t offset;
struct tm * const tmp;
struct tm * (* const funcp)(const time_t *, int32_t, struct tm *);
const int32_t offset;
{
register time_t t;
register const struct state * sp;
@ -1883,7 +1864,6 @@ const int32_t offset;
int seen[TZ_MAX_TYPES];
int types[TZ_MAX_TYPES];
int okay;
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
t = time2(tmp, funcp, offset, &okay);
@ -1947,7 +1927,7 @@ const int32_t offset;
time_t
mktime(tmp)
struct tm * const tmp;
struct tm * const tmp;
{
tzset();
return time1(tmp, localsub, 0L);
@ -1955,7 +1935,7 @@ struct tm * const tmp;
time_t
timelocal(tmp)
struct tm * const tmp;
struct tm * const tmp;
{
tmp->tm_isdst = -1; /* in case it wasn't initialized */
return mktime(tmp);
@ -1963,7 +1943,7 @@ struct tm * const tmp;
time_t
timegm(tmp)
struct tm * const tmp;
struct tm * const tmp;
{
tmp->tm_isdst = 0;
return time1(tmp, gmtsub, 0L);
@ -1971,8 +1951,8 @@ struct tm * const tmp;
time_t
timeoff(tmp, offset)
struct tm * const tmp;
const long offset;
struct tm * const tmp;
const long offset;
{
tmp->tm_isdst = 0;
return time1(tmp, gmtsub, offset);
@ -1988,7 +1968,7 @@ const long offset;
static long
leapcorr(timep)
time_t * timep;
time_t * timep;
{
register struct state * sp;
register struct lsinfo * lp;
@ -2006,7 +1986,7 @@ time_t * timep;
pureconst time_t
time2posix(t)
time_t t;
time_t t;
{
tzset();
return t - leapcorr(&t);
@ -2014,7 +1994,7 @@ time_t t;
pureconst time_t
posix2time(t)
time_t t;
time_t t;
{
time_t x;
time_t y;

View File

@ -31,29 +31,28 @@ strftime (BSD-3)\\n\
Copyright 1989 The Regents of the University of California\"");
asm(".include \"libc/disclaimer.inc\"");
static char *strftime_add(char *pt, const char *ptlim, const char *str) {
while (pt < ptlim && (*pt = *str++) != '\0') ++pt;
return pt;
static char *strftime_add(char *p, const char *pe, const char *str) {
while (p < pe && (*p = *str++) != '\0') ++p;
return p;
}
static char *strftime_conv(char *pt, const char *ptlim, int n,
const char *format) {
static char *strftime_conv(char *p, const char *pe, int n, const char *format) {
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(snprintf)(buf, sizeof(buf), format, n);
return strftime_add(pt, ptlim, buf);
return strftime_add(p, pe, buf);
}
static char *strftime_secs(char *pt, const char *ptlim, const struct tm *t) {
static char *strftime_secs(char *p, const char *pe, const struct tm *t) {
static char buf[INT_STRLEN_MAXIMUM(int) + 1];
struct tm tmp;
int64_t s;
tmp = *t; /* Make a copy, mktime(3) modifies the tm struct. */
s = mktime(&tmp);
(snprintf)(buf, sizeof(buf), "%ld", s);
return strftime_add(pt, ptlim, buf);
return strftime_add(p, pe, buf);
}
static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
static char *strftime_timefmt(char *p, const char *pe, const char *format,
const struct tm *t) {
int i;
long diff;
@ -67,31 +66,31 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
--format;
break;
case 'A':
pt = strftime_add(pt, ptlim,
p = strftime_add(p, pe,
(t->tm_wday < 0 || t->tm_wday > 6)
? "?"
: kWeekdayName[t->tm_wday]);
continue;
case 'a':
pt = strftime_add(pt, ptlim,
p = strftime_add(p, pe,
(t->tm_wday < 0 || t->tm_wday > 6)
? "?"
: kWeekdayNameShort[t->tm_wday]);
continue;
case 'B':
pt = strftime_add(
pt, ptlim,
p = strftime_add(
p, pe,
(t->tm_mon < 0 || t->tm_mon > 11) ? "?" : kMonthName[t->tm_mon]);
continue;
case 'b':
case 'h':
pt = strftime_add(pt, ptlim,
p = strftime_add(p, pe,
(t->tm_mon < 0 || t->tm_mon > 11)
? "?"
: kMonthNameShort[t->tm_mon]);
continue;
case 'c':
pt = strftime_timefmt(pt, ptlim, "%D %X", t);
p = strftime_timefmt(p, pe, "%D %X", t);
continue;
case 'C':
/*
@ -101,11 +100,11 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
** something completely different.
** (ado, 5/24/93)
*/
pt = strftime_conv(pt, ptlim, div100int64(t->tm_year + TM_YEAR_BASE),
p = strftime_conv(p, pe, div100int64(t->tm_year + TM_YEAR_BASE),
"%02d");
continue;
case 'D':
pt = strftime_timefmt(pt, ptlim, "%m/%d/%y", t);
p = strftime_timefmt(p, pe, "%m/%d/%y", t);
continue;
case 'x':
/*
@ -125,10 +124,10 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
** ftp.uni-erlangen.de.
** (ado, 5/30/93)
*/
pt = strftime_timefmt(pt, ptlim, "%m/%d/%y", t);
p = strftime_timefmt(p, pe, "%m/%d/%y", t);
continue;
case 'd':
pt = strftime_conv(pt, ptlim, t->tm_mday, "%02d");
p = strftime_conv(p, pe, t->tm_mday, "%02d");
continue;
case 'E':
case 'O':
@ -145,17 +144,17 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
*/
goto label;
case 'e':
pt = strftime_conv(pt, ptlim, t->tm_mday, "%2d");
p = strftime_conv(p, pe, t->tm_mday, "%2d");
continue;
case 'H':
pt = strftime_conv(pt, ptlim, t->tm_hour, "%02d");
p = strftime_conv(p, pe, t->tm_hour, "%02d");
continue;
case 'I':
pt = strftime_conv(
pt, ptlim, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12, "%02d");
p = strftime_conv(p, pe, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12,
"%02d");
continue;
case 'j':
pt = strftime_conv(pt, ptlim, t->tm_yday + 1, "%03d");
p = strftime_conv(p, pe, t->tm_yday + 1, "%03d");
continue;
case 'k':
/*
@ -168,14 +167,14 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
** "%l" have been swapped.
** (ado, 5/24/93)
*/
pt = strftime_conv(pt, ptlim, t->tm_hour, "%2d");
p = strftime_conv(p, pe, t->tm_hour, "%2d");
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
pt = strftime_add(pt, ptlim, "kitchen sink");
p = strftime_add(p, pe, "kitchen sink");
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
@ -188,43 +187,42 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
** "%l" have been swapped.
** (ado, 5/24/93)
*/
pt = strftime_conv(pt, ptlim,
(t->tm_hour % 12) ? (t->tm_hour % 12) : 12, "%2d");
p = strftime_conv(p, pe, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12,
"%2d");
continue;
case 'M':
pt = strftime_conv(pt, ptlim, t->tm_min, "%02d");
p = strftime_conv(p, pe, t->tm_min, "%02d");
continue;
case 'm':
pt = strftime_conv(pt, ptlim, t->tm_mon + 1, "%02d");
p = strftime_conv(p, pe, t->tm_mon + 1, "%02d");
continue;
case 'n':
pt = strftime_add(pt, ptlim, "\n");
p = strftime_add(p, pe, "\n");
continue;
case 'p':
pt = strftime_add(pt, ptlim, t->tm_hour >= 12 ? "PM" : "AM");
p = strftime_add(p, pe, t->tm_hour >= 12 ? "PM" : "AM");
continue;
case 'R':
pt = strftime_timefmt(pt, ptlim, "%H:%M", t);
p = strftime_timefmt(p, pe, "%H:%M", t);
continue;
case 'r':
pt = strftime_timefmt(pt, ptlim, "%I:%M:%S %p", t);
p = strftime_timefmt(p, pe, "%I:%M:%S %p", t);
continue;
case 'S':
pt = strftime_conv(pt, ptlim, t->tm_sec, "%02d");
p = strftime_conv(p, pe, t->tm_sec, "%02d");
continue;
case 's':
pt = strftime_secs(pt, ptlim, t);
p = strftime_secs(p, pe, t);
continue;
case 'T':
case 'X':
pt = strftime_timefmt(pt, ptlim, "%H:%M:%S", t);
p = strftime_timefmt(p, pe, "%H:%M:%S", t);
continue;
case 't':
pt = strftime_add(pt, ptlim, "\t");
p = strftime_add(p, pe, "\t");
continue;
case 'U':
pt = strftime_conv(pt, ptlim, (t->tm_yday + 7 - t->tm_wday) / 7,
"%02d");
p = strftime_conv(p, pe, (t->tm_yday + 7 - t->tm_wday) / 7, "%02d");
continue;
case 'u':
/*
@ -233,8 +231,7 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
** [1 (Monday) - 7]"
** (ado, 5/24/93)
*/
pt = strftime_conv(pt, ptlim, (t->tm_wday == 0) ? 7 : t->tm_wday,
"%d");
p = strftime_conv(p, pe, (t->tm_wday == 0) ? 7 : t->tm_wday, "%d");
continue;
case 'V':
/*
@ -289,7 +286,7 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
i = 53;
#endif /* defined XPG4_1994_04_09 */
}
pt = strftime_conv(pt, ptlim, i, "%02d");
p = strftime_conv(p, pe, i, "%02d");
continue;
case 'v':
/*
@ -297,32 +294,30 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
** "date as dd-bbb-YYYY"
** (ado, 5/24/93)
*/
pt = strftime_timefmt(pt, ptlim, "%e-%b-%Y", t);
p = strftime_timefmt(p, pe, "%e-%b-%Y", t);
continue;
case 'W':
pt = strftime_conv(
pt, ptlim,
(t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7,
p = strftime_conv(
p, pe, (t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7,
"%02d");
continue;
case 'w':
pt = strftime_conv(pt, ptlim, t->tm_wday, "%d");
p = strftime_conv(p, pe, t->tm_wday, "%d");
continue;
case 'y':
pt = strftime_conv(pt, ptlim, (t->tm_year + TM_YEAR_BASE) % 100,
"%02d");
p = strftime_conv(p, pe, (t->tm_year + TM_YEAR_BASE) % 100, "%02d");
continue;
case 'Y':
pt = strftime_conv(pt, ptlim, t->tm_year + TM_YEAR_BASE, "%04d");
p = strftime_conv(p, pe, t->tm_year + TM_YEAR_BASE, "%04d");
continue;
case 'Z':
if (t->tm_zone) {
pt = strftime_add(pt, ptlim, t->tm_zone);
p = strftime_add(p, pe, t->tm_zone);
} else {
if (t->tm_isdst == 0 || t->tm_isdst == 1) {
pt = strftime_add(pt, ptlim, tzname[t->tm_isdst]);
p = strftime_add(p, pe, tzname[t->tm_isdst]);
} else {
pt = strftime_add(pt, ptlim, "?");
p = strftime_add(p, pe, "?");
}
}
continue;
@ -350,10 +345,10 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
} else {
sign = "+";
}
pt = strftime_add(pt, ptlim, sign);
p = strftime_add(p, pe, sign);
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR);
pt = strftime_conv(pt, ptlim, diff, "%04d");
p = strftime_conv(p, pe, diff, "%04d");
continue;
case '%':
/*
@ -365,17 +360,33 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format,
break;
}
}
if (pt == ptlim) break;
*pt++ = *format;
if (p >= pe) break;
*p++ = *format;
}
return pt;
return p;
}
size_t strftime(char *s, size_t maxsize, const char *format,
const struct tm *t) {
/**
* Converts time to string, e.g.
*
* char b[64];
* int64_t sec;
* struct tm tm;
* time(&sec);
* localtime_r(&sec, &tm);
* strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S%z", &tm); // ISO8601
* strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123
*
* @return bytes copied excluding nul, or 0 on error
*/
size_t strftime(char *s, size_t size, const char *f, const struct tm *t) {
char *p;
p = strftime_timefmt(s, s + maxsize, format, t);
if (p == s + maxsize) return 0;
p = strftime_timefmt(s, s + size, f, t);
if (p < s + size) {
*p = '\0';
return p - s;
} else {
s[size - 1] = '\0';
return 0;
}
}

View File

@ -1,15 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_
#define COSMOPOLITAN_LIBC_TIME_TIME_H_
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/struct/utimbuf.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct itimerval;
struct timezone;
struct tm;
struct utimbuf;
extern const char kWeekdayNameShort[7][4];
extern const char kWeekdayName[7][10];
extern const char kMonthNameShort[12][4];
@ -48,9 +46,9 @@ char *strptime(const char *, const char *, struct tm *);
size_t strftime(char *, size_t, const char *, const struct tm *)
strftimeesque(3);
char *asctime(const struct tm *);
char *asctime_r(const struct tm *, char * /*[64]*/);
char *ctime(const int64_t *);
char *ctime_r(const int64_t *, char * /*[64]*/);
char *ctime_r(const int64_t *, char[hasatleast 64]);
char *asctime_r(const struct tm *, char[hasatleast 64]);
int futimens(int, const struct timespec[2]);
int utimensat(int, const char *, const struct timespec[2], int);

View File

@ -25,8 +25,7 @@ LIBC_TIME_A = o/$(MODE)/libc/time/time.a
LIBC_TIME_A_FILES := \
$(wildcard libc/time/struct/*) \
$(wildcard libc/time/*)
LIBC_TIME_A_FILES := $(wildcard libc/time/*)
LIBC_TIME_A_HDRS = $(filter %.h,$(LIBC_TIME_A_FILES))
LIBC_TIME_A_HDRS := $(filter %.h,$(LIBC_TIME_A_FILES))
LIBC_TIME_A_SRCS_S = $(filter %.S,$(LIBC_TIME_A_FILES))
LIBC_TIME_A_SRCS_C = $(filter %.c,$(LIBC_TIME_A_FILES))

View File

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "ape/lib/pc.h"
#include "libc/macros.h"
.source __FILE__
@ -29,7 +30,7 @@ tinymath_copysignl:
fnstsw
fstp %st
fldt 16(%rbp)
testb $2,%ah
test $FPU_C1>>8,%ah
fabs
je 1f
fchs

View File

@ -26,22 +26,14 @@ tinymath_lroundl:
mov %rsp,%rbp
.profilable
push %rax
push %rax
fldt 16(%rbp)
fnstcw -8(%rbp)
movzwl -8(%rbp),%edx
and $0b11110011,%dh # RC (Rounding Control)
or $0b00000100,%dh # -
mov %dx,-4(%rbp)
fxam
fnstsw
fabs
test $FPU_C1>>8,%ah
fadds .Lhalf(%rip)
fldcw -4(%rbp)
fistpq -16(%rbp)
fldcw -8(%rbp)
mov -16(%rbp),%rax
fisttpq -8(%rbp)
mov -8(%rbp),%rax
je 1f
neg %rax
1: leave

View File

@ -26,7 +26,7 @@
/
/ @param 𝑥 is double scalar in low half of %xmm0
/ @return double scalar in low half of %xmm0
/ @define round(𝑥) = copysign(floor(fabs(𝑥)+.5),𝑥)
/ @define round(𝑥) = copysign(trunc(fabs(𝑥)+.5),𝑥)
/ round(𝑥) = trunc(𝑥+copysign(.5,𝑥))
tinymath_round:
#if !X86_NEED(SSE4_2)

View File

@ -30,19 +30,17 @@ tinymath_roundl:
.profilable
push %rax
fldt 16(%rbp)
fnstcw -6(%rbp)
fnstcw -8(%rbp)
movzwl -8(%rbp),%edx
and $0b11110011,%dh # RC (Rounding Control)
or $0b00000100,%dh # - a.k.a. floor()
mov %dx,-4(%rbp)
orb $0b00001100,-7(%rbp) # RC = 0
fxam # C1 is set to sign bit
fnstsw
fabs
test $FPU_C1>>8,%ah
fadds .Lhalf(%rip)
fldcw -4(%rbp)
frndint
fldcw -8(%rbp)
frndint
fldcw -6(%rbp)
je 1f
fchs
1: leave

View File

@ -21,13 +21,13 @@
#include "net/http/http.h"
/**
* Returns small number for HTTP header, or 0 if not found.
* Returns small number for HTTP header, or -1 if not found.
*/
enum HttpHeader gethttpheader(const char *str, unsigned int len) {
int GetHttpHeader(const char *str, size_t len) {
const struct HttpHeaderSlot *slot;
if ((slot = in_word_set(str, len))) {
if ((slot = LookupHttpHeader(str, len))) {
return slot->code;
} else {
return 0;
return -1;
}
}

View File

@ -6,10 +6,10 @@
%compare-strncmp
%ignore-case
%language=ANSI-C
%pic
%readonly-tables
%struct-type
struct HttpHeaderSlot { unsigned char name; unsigned char code; };
%define lookup-function-name LookupHttpHeader
struct HttpHeaderSlot { char *name; char code; };
%%
Accept, kHttpAccept
Accept-Charset, kHttpAcceptCharset

View File

@ -1,5 +1,5 @@
/* ANSI-C code produced by gperf version 3.0.4 */
/* Command-line: gperf net/http/gethttpheader.gperf */
/* ANSI-C code produced by gperf version 3.1 */
/* Command-line: gperf gethttpheader.gperf */
/* Computed positions: -k'1,9,$' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@ -26,16 +26,16 @@
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
/* The character set is not based on ISO-646. */
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
#line 1 "net/http/gethttpheader.gperf"
#line 1 "gethttpheader.gperf"
#include "libc/str/str.h"
#include "net/http/http.h"
#define GPERF_DOWNCASE
#line 12 "net/http/gethttpheader.gperf"
struct HttpHeaderSlot { unsigned char name; unsigned char code; };
#line 12 "gethttpheader.gperf"
struct HttpHeaderSlot { char *name; char code; };
#define TOTAL_KEYWORDS 49
#define MIN_WORD_LENGTH 3
@ -72,7 +72,7 @@ static unsigned char gperf_downcase[256] =
#ifndef GPERF_CASE_STRNCMP
#define GPERF_CASE_STRNCMP 1
static int
gperf_case_strncmp (register const char *s1, register const char *s2, register unsigned int n)
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
{
for (; n > 0;)
{
@ -97,7 +97,7 @@ inline
#endif
#endif
static unsigned int
hash (register const char *str, register unsigned int len)
hash (register const char *str, register size_t len)
{
static const unsigned char asso_values[] =
{
@ -128,7 +128,7 @@ hash (register const char *str, register unsigned int len)
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73
};
register int hval = len;
register unsigned int hval = len;
switch (hval)
{
@ -149,249 +149,134 @@ hash (register const char *str, register unsigned int len)
return hval + asso_values[(unsigned char)str[len - 1]];
}
struct stringpool_t
{
char stringpool_str5[sizeof("Close")];
char stringpool_str7[sizeof("Upgrade")];
char stringpool_str8[sizeof("Age")];
char stringpool_str9[sizeof("From")];
char stringpool_str10[sizeof("Range")];
char stringpool_str11[sizeof("Accept")];
char stringpool_str12[sizeof("Content-Type")];
char stringpool_str13[sizeof("If-Range")];
char stringpool_str15[sizeof("User-Agent")];
char stringpool_str16[sizeof("Content-Md5")];
char stringpool_str17[sizeof("Referer")];
char stringpool_str18[sizeof("Content-Range")];
char stringpool_str19[sizeof("Date")];
char stringpool_str20[sizeof("Connection")];
char stringpool_str21[sizeof("Retry-After")];
char stringpool_str22[sizeof("Chunked")];
char stringpool_str23[sizeof("Via")];
char stringpool_str24[sizeof("Host")];
char stringpool_str25[sizeof("Accept-Language")];
char stringpool_str26[sizeof("Public")];
char stringpool_str27[sizeof("If-Modified-Since")];
char stringpool_str28[sizeof("Authorization")];
char stringpool_str29[sizeof("If-Unmodified-Since")];
char stringpool_str30[sizeof("Allow")];
char stringpool_str31[sizeof("Pragma")];
char stringpool_str32[sizeof("Content-Base")];
char stringpool_str33[sizeof("If-Match")];
char stringpool_str34[sizeof("Vary")];
char stringpool_str35[sizeof("Keep-Alive")];
char stringpool_str36[sizeof("WWW-Authenticate")];
char stringpool_str37[sizeof("Expires")];
char stringpool_str38[sizeof("Proxy-Authenticate")];
char stringpool_str39[sizeof("Accept-Charset")];
char stringpool_str41[sizeof("Server")];
char stringpool_str43[sizeof("If-None-Match")];
char stringpool_str44[sizeof("Proxy-Authorization")];
char stringpool_str46[sizeof("Proxy-Connection")];
char stringpool_str48[sizeof("Location")];
char stringpool_str49[sizeof("Etag")];
char stringpool_str51[sizeof("Content-Language")];
char stringpool_str52[sizeof("Max-Forwards")];
char stringpool_str53[sizeof("Cache-Control")];
char stringpool_str56[sizeof("Content-Location")];
char stringpool_str61[sizeof("Content-Encoding")];
char stringpool_str62[sizeof("Transfer-Encoding")];
char stringpool_str68[sizeof("Last-Modified")];
char stringpool_str69[sizeof("Content-Length")];
char stringpool_str70[sizeof("Accept-Encoding")];
char stringpool_str72[sizeof("Warning")];
};
static const struct stringpool_t stringpool_contents =
{
"Close",
"Upgrade",
"Age",
"From",
"Range",
"Accept",
"Content-Type",
"If-Range",
"User-Agent",
"Content-Md5",
"Referer",
"Content-Range",
"Date",
"Connection",
"Retry-After",
"Chunked",
"Via",
"Host",
"Accept-Language",
"Public",
"If-Modified-Since",
"Authorization",
"If-Unmodified-Since",
"Allow",
"Pragma",
"Content-Base",
"If-Match",
"Vary",
"Keep-Alive",
"WWW-Authenticate",
"Expires",
"Proxy-Authenticate",
"Accept-Charset",
"Server",
"If-None-Match",
"Proxy-Authorization",
"Proxy-Connection",
"Location",
"Etag",
"Content-Language",
"Max-Forwards",
"Cache-Control",
"Content-Location",
"Content-Encoding",
"Transfer-Encoding",
"Last-Modified",
"Content-Length",
"Accept-Encoding",
"Warning"
};
#define stringpool ((const char *) &stringpool_contents)
#ifdef __GNUC__
__inline
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
__attribute__ ((__gnu_inline__))
#endif
#endif
const struct HttpHeaderSlot *
in_word_set (register const char *str, register unsigned int len)
LookupHttpHeader (register const char *str, register size_t len)
{
static const struct HttpHeaderSlot wordlist[] =
{
{-1}, {-1}, {-1}, {-1}, {-1},
#line 23 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str5, kHttpClose },
{-1},
#line 52 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str7, kHttpUpgrade },
#line 18 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str8, kHttpAge },
#line 36 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str9, kHttpFrom },
#line 49 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str10, kHttpRange },
#line 14 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str11, kHttpAccept },
#line 32 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str12, kHttpContentType },
#line 41 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str13, kHttpIfRange },
{-1},
#line 53 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str15, kHttpUserAgent },
#line 30 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str16, kHttpContentMd5 },
#line 50 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str17, kHttpReferer },
#line 31 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str18, kHttpContentRange },
#line 33 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str19, kHttpDate },
#line 24 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str20, kHttpConnection },
#line 57 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str21, kHttpRetryAfter },
#line 22 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str22, kHttpChunked },
#line 54 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str23, kHttpVia },
#line 37 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str24, kHttpHost },
#line 17 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str25, kHttpAcceptLanguage },
#line 56 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str26, kHttpPublic },
#line 39 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str27, kHttpIfModifiedSince },
#line 20 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str28, kHttpAuthorization },
#line 42 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str29, kHttpIfUnmodifiedSince },
#line 19 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str30, kHttpAllow },
#line 45 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str31, kHttpPragma },
#line 25 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str32, kHttpContentBase },
#line 38 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str33, kHttpIfMatch },
#line 59 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str34, kHttpVary },
#line 43 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str35, kHttpKeepAlive },
#line 61 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str36, kHttpWwwAuthenticate },
#line 35 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str37, kHttpExpires },
#line 46 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str38, kHttpProxyAuthenticate },
#line 15 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str39, kHttpAcceptCharset },
{-1},
#line 58 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str41, kHttpServer },
{-1},
#line 40 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str43, kHttpIfNoneMatch },
#line 47 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str44, kHttpProxyAuthorization },
{-1},
#line 48 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str46, kHttpProxyConnection },
{-1},
#line 55 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str48, kHttpLocation },
#line 34 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str49, kHttpEtag },
{-1},
#line 27 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str51, kHttpContentLanguage },
#line 44 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str52, kHttpMaxForwards },
#line 21 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str53, kHttpCacheControl },
{-1}, {-1},
#line 29 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str56, kHttpContentLocation },
{-1}, {-1}, {-1}, {-1},
#line 26 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str61, kHttpContentEncoding },
#line 51 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str62, kHttpTransferEncoding },
{-1}, {-1}, {-1}, {-1}, {-1},
#line 62 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str68, kHttpLastModified },
#line 28 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str69, kHttpContentLength },
#line 16 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str70, kHttpAcceptEncoding },
{-1},
#line 60 "net/http/gethttpheader.gperf"
{(int)(long)&((struct stringpool_t *)0)->stringpool_str72, kHttpWarning }
{""}, {""}, {""}, {""}, {""},
#line 23 "gethttpheader.gperf"
{"Close", kHttpClose},
{""},
#line 52 "gethttpheader.gperf"
{"Upgrade", kHttpUpgrade},
#line 18 "gethttpheader.gperf"
{"Age", kHttpAge},
#line 36 "gethttpheader.gperf"
{"From", kHttpFrom},
#line 49 "gethttpheader.gperf"
{"Range", kHttpRange},
#line 14 "gethttpheader.gperf"
{"Accept", kHttpAccept},
#line 32 "gethttpheader.gperf"
{"Content-Type", kHttpContentType},
#line 41 "gethttpheader.gperf"
{"If-Range", kHttpIfRange},
{""},
#line 53 "gethttpheader.gperf"
{"User-Agent", kHttpUserAgent},
#line 30 "gethttpheader.gperf"
{"Content-Md5", kHttpContentMd5},
#line 50 "gethttpheader.gperf"
{"Referer", kHttpReferer},
#line 31 "gethttpheader.gperf"
{"Content-Range", kHttpContentRange},
#line 33 "gethttpheader.gperf"
{"Date", kHttpDate},
#line 24 "gethttpheader.gperf"
{"Connection", kHttpConnection},
#line 57 "gethttpheader.gperf"
{"Retry-After", kHttpRetryAfter},
#line 22 "gethttpheader.gperf"
{"Chunked", kHttpChunked},
#line 54 "gethttpheader.gperf"
{"Via", kHttpVia},
#line 37 "gethttpheader.gperf"
{"Host", kHttpHost},
#line 17 "gethttpheader.gperf"
{"Accept-Language", kHttpAcceptLanguage},
#line 56 "gethttpheader.gperf"
{"Public", kHttpPublic},
#line 39 "gethttpheader.gperf"
{"If-Modified-Since", kHttpIfModifiedSince},
#line 20 "gethttpheader.gperf"
{"Authorization", kHttpAuthorization},
#line 42 "gethttpheader.gperf"
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
#line 19 "gethttpheader.gperf"
{"Allow", kHttpAllow},
#line 45 "gethttpheader.gperf"
{"Pragma", kHttpPragma},
#line 25 "gethttpheader.gperf"
{"Content-Base", kHttpContentBase},
#line 38 "gethttpheader.gperf"
{"If-Match", kHttpIfMatch},
#line 59 "gethttpheader.gperf"
{"Vary", kHttpVary},
#line 43 "gethttpheader.gperf"
{"Keep-Alive", kHttpKeepAlive},
#line 61 "gethttpheader.gperf"
{"WWW-Authenticate", kHttpWwwAuthenticate},
#line 35 "gethttpheader.gperf"
{"Expires", kHttpExpires},
#line 46 "gethttpheader.gperf"
{"Proxy-Authenticate", kHttpProxyAuthenticate},
#line 15 "gethttpheader.gperf"
{"Accept-Charset", kHttpAcceptCharset},
{""},
#line 58 "gethttpheader.gperf"
{"Server", kHttpServer},
{""},
#line 40 "gethttpheader.gperf"
{"If-None-Match", kHttpIfNoneMatch},
#line 47 "gethttpheader.gperf"
{"Proxy-Authorization", kHttpProxyAuthorization},
{""},
#line 48 "gethttpheader.gperf"
{"Proxy-Connection", kHttpProxyConnection},
{""},
#line 55 "gethttpheader.gperf"
{"Location", kHttpLocation},
#line 34 "gethttpheader.gperf"
{"Etag", kHttpEtag},
{""},
#line 27 "gethttpheader.gperf"
{"Content-Language", kHttpContentLanguage},
#line 44 "gethttpheader.gperf"
{"Max-Forwards", kHttpMaxForwards},
#line 21 "gethttpheader.gperf"
{"Cache-Control", kHttpCacheControl},
{""}, {""},
#line 29 "gethttpheader.gperf"
{"Content-Location", kHttpContentLocation},
{""}, {""}, {""}, {""},
#line 26 "gethttpheader.gperf"
{"Content-Encoding", kHttpContentEncoding},
#line 51 "gethttpheader.gperf"
{"Transfer-Encoding", kHttpTransferEncoding},
{""}, {""}, {""}, {""}, {""},
#line 62 "gethttpheader.gperf"
{"Last-Modified", kHttpLastModified},
#line 28 "gethttpheader.gperf"
{"Content-Length", kHttpContentLength},
#line 16 "gethttpheader.gperf"
{"Accept-Encoding", kHttpAcceptEncoding},
{""},
#line 60 "gethttpheader.gperf"
{"Warning", kHttpWarning}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = hash (str, len);
register unsigned int key = hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
if (key <= MAX_HASH_VALUE)
{
register int o = wordlist[key].name;
if (o >= 0)
{
register const char *s = o + stringpool;
register const char *s = wordlist[key].name;
if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')
return &wordlist[key];
}
}
}
return 0;
}

View File

@ -17,15 +17,17 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "net/http/gethttpmethod.inc"
#include "net/http/http.h"
void clearhttprequest(struct HttpRequest *req) {
req->uri.i = pushpop(0);
req->method.i = pushpop(0);
req->version.i = pushpop(0);
req->scratch.i = pushpop(0);
critbit0_clear(&req->headers);
/**
* Returns small number for HTTP method, or -1 if not found.
*/
int GetHttpMethod(const char *str, size_t len) {
const struct HttpMethodSlot *slot;
if ((slot = LookupHttpMethod(str, len))) {
return slot->code;
} else {
return -1;
}
}

View File

@ -0,0 +1,36 @@
%{
#include "libc/str/str.h"
#include "net/http/http.h"
#define GPERF_DOWNCASE
%}
%compare-strncmp
%ignore-case
%language=ANSI-C
%readonly-tables
%struct-type
%define lookup-function-name LookupHttpMethod
struct HttpMethodSlot { char *name; char code; };
%%
DELETE, kHttpDelete
GET, kHttpGet
HEAD, kHttpHead
POST, kHttpPost
PUT, kHttpPut
CONNECT, kHttpConnect
OPTIONS, kHttpOptions
TRACE, kHttpTrace
COPY, kHttpCopy
CHECKOUT, kHttpCheckout
LOCK, kHttpLock
MERGE, kHttpMerge
MKACTIVITY, kHttpMkactivity
MKCOL, kHttpMkcol
MOVE, kHttpMove
NOTIFY, kHttpNotify
PATCH, kHttpPatch
PROPFIND, kHttpPropfind
PROPPATCH, kHttpProppatch
REPORT, kHttpReport
SUBSCRIBE, kHttpSubscribe
UNLOCK, kHttpUnlock
UNSUBSCRIBE, kHttpUnsubscribe

View File

@ -0,0 +1,206 @@
/* ANSI-C code produced by gperf version 3.1 */
/* Command-line: gperf gethttpmethod.gperf */
/* Computed positions: -k'1-2' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
/* The character set is not based on ISO-646. */
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
#line 1 "gethttpmethod.gperf"
#include "libc/str/str.h"
#include "net/http/http.h"
#define GPERF_DOWNCASE
#line 12 "gethttpmethod.gperf"
struct HttpMethodSlot { char *name; char code; };
#define TOTAL_KEYWORDS 23
#define MIN_WORD_LENGTH 3
#define MAX_WORD_LENGTH 11
#define MIN_HASH_VALUE 4
#define MAX_HASH_VALUE 34
/* maximum key range = 31, duplicates = 0 */
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
static unsigned char gperf_downcase[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
255
};
#endif
#ifndef GPERF_CASE_STRNCMP
#define GPERF_CASE_STRNCMP 1
static int
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
{
for (; n > 0;)
{
unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
if (c1 != 0 && c1 == c2)
{
n--;
continue;
}
return (int)c1 - (int)c2;
}
return 0;
}
#endif
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static unsigned int
hash (register const char *str, register size_t len)
{
static const unsigned char asso_values[] =
{
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 0, 35, 5, 10, 10,
35, 5, 10, 35, 35, 0, 30, 15, 0, 0,
0, 35, 5, 15, 0, 5, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 0, 35, 5,
10, 10, 35, 5, 10, 35, 35, 0, 30, 15,
0, 0, 0, 35, 5, 15, 0, 5, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
35, 35, 35, 35, 35, 35
};
return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
}
const struct HttpMethodSlot *
LookupHttpMethod (register const char *str, register size_t len)
{
static const struct HttpMethodSlot wordlist[] =
{
{""}, {""}, {""}, {""},
#line 17 "gethttpmethod.gperf"
{"POST", kHttpPost},
#line 30 "gethttpmethod.gperf"
{"PATCH", kHttpPatch},
#line 29 "gethttpmethod.gperf"
{"NOTIFY", kHttpNotify},
#line 20 "gethttpmethod.gperf"
{"OPTIONS", kHttpOptions},
#line 18 "gethttpmethod.gperf"
{"PUT", kHttpPut},
#line 22 "gethttpmethod.gperf"
{"COPY", kHttpCopy},
#line 21 "gethttpmethod.gperf"
{"TRACE", kHttpTrace},
#line 35 "gethttpmethod.gperf"
{"UNLOCK", kHttpUnlock},
#line 19 "gethttpmethod.gperf"
{"CONNECT", kHttpConnect},
#line 31 "gethttpmethod.gperf"
{"PROPFIND", kHttpPropfind},
#line 32 "gethttpmethod.gperf"
{"PROPPATCH", kHttpProppatch},
{""},
#line 36 "gethttpmethod.gperf"
{"UNSUBSCRIBE", kHttpUnsubscribe},
{""},
#line 15 "gethttpmethod.gperf"
{"GET", kHttpGet},
#line 28 "gethttpmethod.gperf"
{"MOVE", kHttpMove},
#line 27 "gethttpmethod.gperf"
{"MKCOL", kHttpMkcol},
#line 33 "gethttpmethod.gperf"
{"REPORT", kHttpReport},
{""},
#line 23 "gethttpmethod.gperf"
{"CHECKOUT", kHttpCheckout},
#line 16 "gethttpmethod.gperf"
{"HEAD", kHttpHead},
#line 26 "gethttpmethod.gperf"
{"MKACTIVITY", kHttpMkactivity},
#line 14 "gethttpmethod.gperf"
{"DELETE", kHttpDelete},
{""}, {""},
#line 34 "gethttpmethod.gperf"
{"SUBSCRIBE", kHttpSubscribe},
#line 25 "gethttpmethod.gperf"
{"MERGE", kHttpMerge},
{""}, {""}, {""},
#line 24 "gethttpmethod.gperf"
{"LOCK", kHttpLock}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register unsigned int key = hash (str, len);
if (key <= MAX_HASH_VALUE)
{
register const char *s = wordlist[key].name;
if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')
return &wordlist[key];
}
}
return 0;
}

View File

@ -1,80 +1,101 @@
#ifndef COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#define COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#include "libc/alg/alg.h"
#define kHttpGet 0
#define kHttpHead 1
#define kHttpPost 2
#define kHttpPut 3
#define kHttpDelete 4
#define kHttpConnect 5
#define kHttpOptions 6
#define kHttpTrace 7
#define kHttpCopy 8
#define kHttpCheckout 9
#define kHttpLock 10
#define kHttpMerge 11
#define kHttpMkactivity 12
#define kHttpMkcol 13
#define kHttpMove 14
#define kHttpNotify 15
#define kHttpPatch 16
#define kHttpPropfind 17
#define kHttpProppatch 18
#define kHttpReport 19
#define kHttpSubscribe 20
#define kHttpUnlock 21
#define kHttpUnsubscribe 22
#define kHttpAccept 0
#define kHttpAcceptCharset 1
#define kHttpAcceptEncoding 2
#define kHttpAcceptLanguage 3
#define kHttpAge 4
#define kHttpAllow 5
#define kHttpAuthorization 6
#define kHttpCacheControl 7
#define kHttpChunked 8
#define kHttpClose 9
#define kHttpConnection 10
#define kHttpContentBase 11
#define kHttpContentEncoding 12
#define kHttpContentLanguage 13
#define kHttpContentLength 14
#define kHttpContentLocation 15
#define kHttpContentMd5 16
#define kHttpContentRange 17
#define kHttpContentType 18
#define kHttpDate 19
#define kHttpEtag 20
#define kHttpExpires 21
#define kHttpFrom 22
#define kHttpHost 23
#define kHttpIfMatch 24
#define kHttpIfModifiedSince 25
#define kHttpIfNoneMatch 26
#define kHttpIfRange 27
#define kHttpIfUnmodifiedSince 28
#define kHttpKeepAlive 29
#define kHttpMaxForwards 30
#define kHttpPragma 31
#define kHttpProxyAuthenticate 32
#define kHttpProxyAuthorization 33
#define kHttpProxyConnection 34
#define kHttpRange 35
#define kHttpReferer 36
#define kHttpTransferEncoding 37
#define kHttpUpgrade 38
#define kHttpUserAgent 39
#define kHttpVia 40
#define kHttpLocation 41
#define kHttpPublic 42
#define kHttpRetryAfter 43
#define kHttpServer 44
#define kHttpVary 45
#define kHttpWarning 46
#define kHttpWwwAuthenticate 47
#define kHttpLastModified 48
#define kHttpHeadersMax 49
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct FILE;
enum HttpHeader {
kHttpAccept = 1,
kHttpAcceptCharset,
kHttpAcceptEncoding,
kHttpAcceptLanguage,
kHttpAge,
kHttpAllow,
kHttpAuthorization,
kHttpCacheControl,
kHttpChunked,
kHttpClose,
kHttpConnection,
kHttpContentBase,
kHttpContentEncoding,
kHttpContentLanguage,
kHttpContentLength,
kHttpContentLocation,
kHttpContentMd5,
kHttpContentRange,
kHttpContentType,
kHttpDate,
kHttpEtag,
kHttpExpires,
kHttpFrom,
kHttpHost,
kHttpIfMatch,
kHttpIfModifiedSince,
kHttpIfNoneMatch,
kHttpIfRange,
kHttpIfUnmodifiedSince,
kHttpKeepAlive,
kHttpMaxForwards,
kHttpPragma,
kHttpProxyAuthenticate,
kHttpProxyAuthorization,
kHttpProxyConnection,
kHttpRange,
kHttpReferer,
kHttpTransferEncoding,
kHttpUpgrade,
kHttpUserAgent,
kHttpVia,
kHttpLocation,
kHttpPublic,
kHttpRetryAfter,
kHttpServer,
kHttpVary,
kHttpWarning,
kHttpWwwAuthenticate,
kHttpLastModified,
};
struct HttpStr {
char *p;
size_t i, n;
struct HttpRequestSlice {
short a, b;
};
struct HttpRequest {
struct HttpStr uri; /* /foo/bar.html, etc. */
struct HttpStr method; /* "GET", "POST", etc. */
struct critbit0 headers; /* TreeMultiMap<"key:value"> (no space delims) */
struct HttpStr version; /* "HTTP/1.1", etc. */
struct HttpStr scratch; /* "HTTP/1.1", etc. */
int method;
struct HttpRequestSlice uri;
struct HttpRequestSlice version;
struct HttpRequestSlice scratch;
struct HttpRequestSlice headers[kHttpHeadersMax];
};
int parsehttprequest(struct HttpRequest *, struct FILE *) paramsnonnull();
void clearhttprequest(struct HttpRequest *) paramsnonnull();
void freehttprequest(struct HttpRequest **) paramsnonnull();
int negotiatehttprequest(int, const char *, uint32_t *, char *, uint32_t *,
int GetHttpHeader(const char *, size_t);
int GetHttpMethod(const char *, size_t);
int ParseHttpRequest(struct HttpRequest *, const char *, size_t);
int NegotiateHttpRequest(int, const char *, uint32_t *, char *, uint32_t *,
uint32_t *, bool, long double);
COSMOPOLITAN_C_END_

View File

@ -1,24 +0,0 @@
DELETE
GET
HEAD
POST
PUT
CONNECT
OPTIONS
TRACE
COPY
CHECKOUT
LOCK
M-SEARCH
MERGE
MKACTIVITY
MKCOL
MOVE
NOTIFY
PATCH
PROPFIND
PROPPATCH
REPORT
SUBSCRIBE
UNLOCK
UNSUBSCRIBE

View File

@ -42,7 +42,7 @@ static pureconst long AsMilliseconds(long double ts) {
* @param singleshot should be true w/ connection: close
* @return 0 on success, or -1 w/ errno
*/
int negotiatehttprequest(int sock, const char *req, uint32_t *inout_reqsize,
int NegotiateHttpRequest(int sock, const char *req, uint32_t *inout_reqsize,
char *resp, uint32_t *inout_respsize,
uint32_t *out_resphdrsize, bool singleshot,
long double timeout) {

View File

@ -39,95 +39,84 @@ enum ParseHttpRequestState {
};
/**
* Parses req line and headers of HTTP req.
*
* This parser is very lax. All decoding is ISO-8859-1. A 1mB upper
* bound on memory is enforced.
* Parses HTTP request header.
*/
int parsehttprequest(struct HttpRequest *req, FILE *f) {
enum ParseHttpRequestState state = METHOD;
int toto = 0;
clearhttprequest(req);
while (true) {
char ch;
{
int c = fgetc(f);
if (c == -1) {
if (toto && !ferror(f)) {
return ebadmsg(); /* RFC7230 § 3.4 */
}
return -1;
}
ch = (unsigned char)c;
}
if (++toto == UINT16_MAX) {
return ebadmsg(); /* RFC7230 § 3.2.5 */
}
switch (state) {
int ParseHttpRequest(struct HttpRequest *req, const char *p, size_t n) {
int a, h, c, i, x;
enum ParseHttpRequestState t;
memset(req, 0, sizeof(*req));
a = h = 0;
t = METHOD;
if (n > SHRT_MAX - 1) n = SHRT_MAX - 1;
for (i = 0; i < n; ++i) {
c = p[i] & 0xFF;
switch (t) {
case METHOD:
if (ch == '\r' || ch == '\n') break; /* RFC7230 § 3.5 */
if (ch == ' ') {
if (req->method.i == 0) return ebadmsg();
state = URI;
} else {
append(&req->method, &ch);
if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */
if (c == ' ') {
if (!i) return ebadmsg();
if ((x = GetHttpMethod(p, i)) == -1) return ebadmsg();
req->method = x;
req->uri.a = i + 1;
t = URI;
}
break;
case URI:
if (ch == ' ') {
if (req->uri.i == 0) return ebadmsg();
state = VERSION;
} else {
append(&req->uri, &ch);
if (c == ' ') {
req->uri.b = i;
req->version.a = i + 1;
if (req->uri.a == req->uri.b) return ebadmsg();
t = VERSION;
}
break;
case VERSION:
if (ch == '\r' || ch == '\n') {
state = ch == '\r' ? CR1 : LF1;
} else {
append(&req->version, &ch);
if (c == '\r' || c == '\n') {
req->version.b = i;
t = c == '\r' ? CR1 : LF1;
}
break;
case CR1:
if (ch != '\n') return ebadmsg();
state = LF1;
if (c != '\n') return ebadmsg();
t = LF1;
break;
case LF1:
if (ch == '\r') {
state = LF2;
if (c == '\r') {
t = LF2;
break;
} else if (ch == '\n') {
} else if (c == '\n') {
return 0;
} else if (ch == ' ' || ch == '\t') { /* line folding!!! */
} else if (c == ' ' || c == '\t') { /* line folding!!! */
return eprotonosupport(); /* RFC7230 § 3.2.4 */
}
state = HKEY;
a = i;
t = HKEY;
/* εpsilon transition */
case HKEY:
if (ch == ':') state = HSEP;
ch = tolower(ch);
append(&req->scratch, &ch);
if (c == ':') {
h = GetHttpHeader(p + a, i - a);
t = HSEP;
}
break;
case HSEP:
if (ch == ' ' || ch == '\t') break;
state = HVAL;
if (c == ' ' || c == '\t') break;
a = i;
t = HVAL;
/* εpsilon transition */
case HVAL:
if (ch == '\r' || ch == '\n') {
state = ch == '\r' ? CR1 : LF1;
ch = '\0';
if (c == '\r' || c == '\n') {
if (h != -1) {
req->headers[h].a = a;
req->headers[h].b = i;
}
append(&req->scratch, &ch);
if (!ch) {
critbit0_insert(&req->headers, req->scratch.p);
req->scratch.i = 0;
t = c == '\r' ? CR1 : LF1;
}
break;
case LF2:
if (ch == '\n') return 0;
if (c == '\n') return 0;
return ebadmsg();
default:
unreachable;
}
}
return ebadmsg();
}

View File

@ -29,6 +29,7 @@ TEST_APE_LIB_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_LOG \
LIBC_STUBS \
LIBC_TESTLIB \
LIBC_X
@ -49,6 +50,10 @@ o/$(MODE)/test/ape/lib/%.com.dbg: \
$(APE)
@$(APELINK)
$(TEST_APE_LIB_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
.PHONY: o/$(MODE)/test/ape/lib
o/$(MODE)/test/ape/lib: $(TEST_APE_LIB_BINS) \
$(TEST_APE_LIB_CHECKS)

View File

@ -19,6 +19,7 @@
*/
#include "dsp/core/core.h"
#include "dsp/core/q.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
@ -49,7 +50,8 @@ TEST(GetIntegerCoefficients8, testBt601Vectors) {
for (i = 0; i < ARRAYLEN(V); ++i) {
GetIntegerCoefficients8(got, V[i].r, V[i].m, V[i].L, V[i].H);
EXPECT_EQ(0, memcmp(V[i].n, got, sizeof(got)),
"got={%ld,%ld,%ld,%ld,%ld,%ld}, want={%ld,%ld,%ld,%ld,%ld,%ld}",
"got={%ld,%ld,%ld,%ld,%ld,%ld}, want = { % ld, % ld, % ld, % ld, "
"% ld, % ld } ",
got[0], got[1], got[2], got[3], got[4], got[5], V[i].n[0],
V[i].n[1], V[i].n[2], V[i].n[3], V[i].n[4], V[i].n[5]);
}

View File

@ -47,6 +47,14 @@ o/$(MODE)/test/dsp/core/%.com.dbg: \
$(APE)
@$(APELINK)
$(TEST_DSP_CORE_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
o/$(MODE)/test/dsp/core/getintegercoefficients8_test-gcc.asm: \
OVERRIDE_CFLAGS += \
-fsanitize=address
.PHONY: o/$(MODE)/test/dsp/core
o/$(MODE)/test/dsp/core: \
$(TEST_DSP_CORE_BINS) \

View File

@ -347,7 +347,7 @@ TEST(magikarp_vs_gyarados, testHalf) {
61. / 31., 0, 0);
Magikarp2xY(32, 61, M[0], 32, 61);
Magikarp2xX(32, 61, M[0], 16, 61);
AbsoluteDifference(16, 31, D, 16, 32, G[0], 32, 61, M[0]);
AbsoluteDifference(16, 31, D, 16, 31, G[0], 32, 61, M[0]);
EXPECT_STREQ(u"\n\
oppppppppooooooooooooopppppppqp\n\
pppppooonnmmmmmmmmmmmnnoopppppp\n\
@ -386,21 +386,21 @@ pppppppppoooooooooooooppppppppq",
gc(bingblit(16, 31, G[0], 16, 31)));
EXPECT_STREQ(u"\n\
                           \n\
                          \n\
                     \n\
              \n\
    \n\
  \n\
   \n\
    \n\
     \n\
     \n\
     \n\
    \n\
         \n\
      \n\
 \n\
   oooooppppppppqp",
                            \n\
                           \n\
                         \n\
                         \n\
                        \n\
                       \n\
                         \n\
                         \n\
                         \n\
                          \n\
                           \n\
                            \n\
                         \n\
                           \n\
                          ",
gc(bingblit(16, 31, D, 16, 31)));
}

View File

@ -24,6 +24,10 @@ TEST(itoa64radix16, test) {
char buf[21];
EXPECT_EQ(5, uint64toarray_radix16(0x31337, buf));
EXPECT_STREQ("31337", buf);
EXPECT_EQ(2, uint64toarray_radix16(0x13, buf));
EXPECT_STREQ("13", buf);
EXPECT_EQ(3, uint64toarray_radix16(0x113, buf));
EXPECT_STREQ("113", buf);
}
TEST(itoa64fixed16, test) {

View File

@ -416,12 +416,8 @@ TEST(sprintf, test_float) {
EXPECT_STREQ("42.90", Format("%.2f", 42.8952));
EXPECT_STREQ("42.895200000", Format("%.9f", 42.8952));
EXPECT_STREQ("42.8952230000", Format("%.10f", 42.895223));
/* this testcase checks, that the precision is truncated to 9 digits. */
/* a perfect working float should return the whole number */
EXPECT_STREQ("42.895223123000", Format("%.12f", 42.89522312345678));
/* this testcase checks, that the precision is truncated AND rounded to 9 */
/* digits. a perfect working float should return the whole number */
EXPECT_STREQ("42.895223877000", Format("%.12f", 42.89522387654321));
EXPECT_STREQ("42.89522312345678", Format("%.14f", 42.89522312345678));
EXPECT_STREQ("42.89522387654321", Format("%.14f", 42.89522387654321));
EXPECT_STREQ(" 42.90", Format("%6.2f", 42.8952));
EXPECT_STREQ("+42.90", Format("%+6.2f", 42.8952));
EXPECT_STREQ("+42.9", Format("%+5.1f", 42.9252));

Some files were not shown because too many files have changed in this diff Show More