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

View File

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

View File

@ -58,6 +58,12 @@ o/$(MODE)/dsp/core/det3.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-ffast-math -ffast-math
ifeq (,$(MODE))
$(DSP_CORE_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
DSP_CORE_LIBS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x))) DSP_CORE_LIBS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)))
DSP_CORE_SRCS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_SRCS)) DSP_CORE_SRCS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_SRCS))
DSP_CORE_HDRS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_HDRS)) 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 (!dar) dar = sn, dar /= dn;
if (!off) off = (dar - 1) / 2; if (!off) off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar; f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 1; s = 3 * f + 4;
fweights = gc(xcalloc(s, sizeof(double))); fweights = gc(xcalloc(s, sizeof(double)));
res = NewSamplingSolution(dn, s); res = NewSamplingSolution(dn, s);
weights = res->weights; 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, 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 sxw, const int src[syw][sxw], long dyn, long dxn,
long syn, long sxn, short tmp0[restrict dyn][sxn], long syn, long sxn, int tmp0[restrict dyn][sxn],
short tmp1[restrict dyn][sxn], int tmp1[restrict dyn][sxn],
short tmp2[restrict dyn][dxn], long yfn, long xfn, int tmp2[restrict dyn][dxn], long yfn, long xfn,
const short fyi[dyn][yfn], const short fyw[dyn][yfn], const short fyi[dyn][yfn], const short fyw[dyn][yfn],
const short fxi[dxn][xfn], const short fxw[dxn][xfn], const short fxi[dxn][xfn], const short fxw[dxn][xfn],
bool sharpen) { 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(syn, 0x7fff);
CHECK_LE(sxn, 0x7fff); CHECK_LE(sxn, 0x7fff);
GyaradosImpl(dyw, dxw, dst, syw, sxw, src, dyn, dxn, syn, sxn, GyaradosImpl(dyw, dxw, dst, syw, sxw, src, dyn, dxn, syn, sxn,
gc(xmemalign(64, sizeof(short) * dyn * sxn)), gc(xmemalign(64, sizeof(int) * dyn * sxn)),
gc(xmemalign(64, sizeof(short) * dyn * sxn)), gc(xmemalign(64, sizeof(int) * dyn * sxn)),
gc(xmemalign(64, sizeof(short) * dyn * dxn)), cy->s, cx->s, gc(xmemalign(64, sizeof(int) * dyn * dxn)), cy->s, cx->s,
cy->indices, cy->weights, cx->indices, cx->weights, sharpen); cy->indices, cy->weights, cx->indices, cx->weights, sharpen);
} else { } else {
ZeroMatrix(dyw, dxw, dst, dyn, dxn); ZeroMatrix(dyw, dxw, dst, dyn, dxn);

View File

@ -59,6 +59,12 @@ o/$(MODE)/dsp/tty/ttyraster.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
$(MATHEMATICAL) $(MATHEMATICAL)
ifeq (,$(MODE))
$(DSP_TTY_OBJS): \
OVERRIDE_CFLAGS += \
-fsanitize=address
endif
DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x))) DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)))
DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS)) DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS))
DSP_TTY_HDRS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_HDRS)) 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(buf, &x, sizeof(x));
memcpy(&lo, &buf[0], sizeof(lo)); memcpy(&lo, &buf[0], sizeof(lo));
memcpy(&hi, &buf[8], sizeof(hi)); 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) { 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(buf, &x, sizeof(x));
memcpy(&lo, &buf[0], sizeof(lo)); memcpy(&lo, &buf[0], sizeof(lo));
memcpy(&hi, &buf[8], sizeof(hi)); 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) \ #define DOBIN(OP) \
@ -65,7 +65,6 @@ int main(int argc, char *argv[]) {
DOBIN(fldlg2); DOBIN(fldlg2);
DOBIN(fldln2); DOBIN(fldln2);
DOBIN(fldl2e); DOBIN(fldl2e);
DOBIN(finit);
fputc('\n', stdout); fputc('\n', stdout);
fputs(kHeaderHex, stdout); fputs(kHeaderHex, stdout);
DOHEX(fldz); DOHEX(fldz);
@ -75,7 +74,6 @@ int main(int argc, char *argv[]) {
DOHEX(fldlg2); DOHEX(fldlg2);
DOHEX(fldln2); DOHEX(fldln2);
DOHEX(fldl2e); DOHEX(fldl2e);
DOHEX(finit);
return 0; 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 jmp 0b
.endfn _start,globl .endfn _start,globl
.source __FILE__ .source __FILE__
.rodata.cst4
1: .float -1.5

View File

@ -23,6 +23,8 @@
#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/dirent.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/mem/mem.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/files.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/win32finddata.h" #include "libc/nt/struct/win32finddata.h"
@ -31,9 +33,18 @@
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.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 { struct dirstream {
int64_t tell; int64_t tell;
int64_t fd; int64_t fd;
struct dirent ent;
union { union {
struct { struct {
unsigned buf_pos; unsigned buf_pos;
@ -41,8 +52,6 @@ struct dirstream {
char buf[BUFSIZ]; char buf[BUFSIZ];
}; };
struct { struct {
struct dirent winent;
char __d_name[PATH_MAX];
bool isdone; bool isdone;
struct NtWin32FindData windata; 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 * @returns newly allocated DIR object, or NULL w/ errno
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM * @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
* @see glob() * @see glob()
*/ */
DIR *opendir(const char *name) { DIR *opendir(const char *name) {
int fd;
DIR *res;
if (!IsWindows() && !IsXnu()) { if (!IsWindows() && !IsXnu()) {
int fd; res = NULL;
DIR *res = NULL;
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) { if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) {
if (!(res = fdopendir(fd))) close(fd); if (!(res = fdopendir(fd))) close(fd);
} }
@ -103,8 +155,8 @@ DIR *opendir(const char *name) {
* @errors ENOMEM and fd is closed * @errors ENOMEM and fd is closed
*/ */
DIR *fdopendir(int fd) { DIR *fdopendir(int fd) {
DIR *dir;
if (!IsWindows() && !IsXnu()) { if (!IsWindows() && !IsXnu()) {
DIR *dir;
if ((dir = calloc(1, sizeof(*dir)))) { if ((dir = calloc(1, sizeof(*dir)))) {
dir->fd = fd; dir->fd = fd;
return dir; return dir;
@ -125,35 +177,36 @@ DIR *fdopendir(int fd) {
* differentiated by setting errno to 0 beforehand * differentiated by setting errno to 0 beforehand
*/ */
struct dirent *readdir(DIR *dir) { struct dirent *readdir(DIR *dir) {
int rc;
struct dirent *ent;
struct dirent$freebsd *freebsd;
if (!IsWindows()) { if (!IsWindows()) {
if (dir->buf_pos >= dir->buf_end) { if (dir->buf_pos >= dir->buf_end) {
int rc; if (!(rc = getdents(dir->fd, dir->buf,
if (!(rc = getdents(dir->fd, dir->buf, BUFSIZ)) || rc == -1) { sizeof(dir->buf) - sizeof(dir->ent.d_name))) ||
rc == -1) {
return NULL; return NULL;
} }
dir->buf_pos = 0; dir->buf_pos = 0;
dir->buf_end = rc; dir->buf_end = rc;
} }
/* TODO(jart): Check FreeBSD and OpenBSD again regarding this */ if (IsLinux()) {
char *record = dir->buf + dir->buf_pos; ent = (struct dirent *)(dir->buf + dir->buf_pos);
char *name = record + 8 + 8 + 2; dir->buf_pos += ent->d_reclen;
size_t namelen = strlen(name); dir->tell = ent->d_off;
unsigned char dtype = name[namelen + 1]; } else {
memmove(name + 1, name, namelen + 1); /* shove forward one byte */ freebsd = (struct dirent$freebsd *)(dir->buf + dir->buf_pos);
*name = dtype; /* is dirent d_type field */ dir->buf_pos += freebsd->d_reclen;
struct dirent *ent = (void *)record; ent = &dir->ent;
dir->buf_pos += ent->d_reclen; ent->d_ino = freebsd->d_fileno;
dir->tell = ent->d_off; 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; return ent;
} else { } else {
if (dir->isdone) return NULL; return readdir$nt(dir);
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;
} }
} }
@ -177,7 +230,7 @@ int closedir(DIR *dir) {
} }
/** /**
* Returns current byte offset into directory data. * Returns offset into directory data.
*/ */
long telldir(DIR *dir) { long telldir(DIR *dir) {
return dir->tell; return dir->tell;

View File

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

View File

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

View File

@ -2,12 +2,12 @@
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_DIRENT_H_ #define COSMOPOLITAN_LIBC_CALLS_STRUCT_DIRENT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
struct dirent { struct dirent { /* linux getdents64 abi */
uint64_t d_ino; /* inode number */ uint64_t d_ino; /* inode number */
int64_t d_off; /* implementation-dependent location number */ int64_t d_off; /* implementation-dependent location number */
uint16_t d_reclen; /* byte length of this whole struct and string */ 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 */ uint8_t d_type; /* DT_UNKNOWN, DT_BLK, DT_DIR, etc. */
char d_name[1]; /* NUL-terminated basename */ char d_name[256]; /* NUL-terminated basename */
}; };
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #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/timespectofiletime.o \
o/$(MODE)/libc/conv/filetimetotimespec.o \ o/$(MODE)/libc/conv/filetimetotimespec.o \
o/$(MODE)/libc/conv/filetimetotimeval.o: \ o/$(MODE)/libc/conv/filetimetotimeval.o: \
OVERRIDE_COPTS += \ OVERRIDE_CFLAGS += \
-O3 -O3
$(LIBC_CONV_A_OBJS): \
OVERRIDE_CFLAGS += \
$(NO_MAGIC)
LIBC_CONV_LIBS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x))) LIBC_CONV_LIBS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)))
LIBC_CONV_SRCS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_SRCS)) LIBC_CONV_SRCS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_SRCS))
LIBC_CONV_HDRS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_HDRS)) 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 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/alg/reverse.h"
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/conv/itoa.h" #include "libc/conv/itoa.h"
size_t uint64toarray_fixed16(uint64_t i, char a[hasatleast 17], uint8_t b) { size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) {
size_t j; int i;
assert(b <= 64); char *p;
assert(b % 4 == 0); assert(k <= 64 && !(k & 3));
j = 0; for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
if (b) { *p = '\0';
do { return p - b;
a[j++] = "0123456789abcdef"[i & 15];
i >>= 4;
} while (b -= 4);
}
a[j] = '\0';
reverse(a, j);
return j;
} }

View File

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

View File

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

View File

@ -23,6 +23,7 @@ Elf64_Ehdr *mapelfread(const char *, struct MappedFile *);
char *getelfstringtable(const Elf64_Ehdr *, size_t); char *getelfstringtable(const Elf64_Ehdr *, size_t);
Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *); Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *, size_t, void *); 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, forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize,
intptr_t addr, size_t addrsize) { intptr_t addr, size_t addrsize) {
@ -33,13 +34,6 @@ forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize,
#endif #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) { static inline bool iselfsymbolcontent(const Elf64_Sym *sym) {
return sym->st_size > 0 && (ELF64_ST_TYPE(sym->st_info) == STT_FUNC || return sym->st_size > 0 && (ELF64_ST_TYPE(sym->st_info) == STT_FUNC ||
ELF64_ST_TYPE(sym->st_info) == STT_OBJECT); ELF64_ST_TYPE(sym->st_info) == STT_OBJECT);

View File

@ -17,9 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/testlib/testlib.h" #include "libc/elf/elf.h"
TEST(flattenhighmemory, test) { bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) {
/* EXPECT_EQ(0, flattenhighmemory()); */ if (mapsize < sizeof(Elf64_Ehdr)) return false;
/* EXPECT_STREQ("", flattenhighmemory()); */ 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/fmt/palandprintf.h"
#include "libc/math.h" #include "libc/math.h"
static const int kPow10[] = {1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000, 1000000000};
/** /**
* Formats floating point number. * Formats floating point number.
* *
* @see xdtoa() for higher precision at the cost of bloat * @see xdtoa() for higher precision at the cost of bloat
* @see palandprintf() which is intended caller * @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) { unsigned long width, unsigned long flags) {
long whole, frac; long whole, frac;
long double tmp, diff; long double tmp, diff;
@ -72,32 +69,31 @@ int ftoa(int out(int, void *), void *arg, long double value, unsigned long prec,
prec = 6; prec = 6;
} }
/* limit precision to 9, cause a prec >= 10 can lead to overflow errors */ while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 14) {
while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 9) {
buf[len++] = '0'; buf[len++] = '0';
prec--; prec--;
} }
whole = truncl(fabsl(value)); whole = truncl(fabsl(value));
tmp = (fabsl(value) - whole) * kPow10[prec]; tmp = (fabsl(value) - whole) * exp10l(prec);
frac = tmp; frac = tmp;
diff = tmp - frac; diff = tmp - frac;
if (diff > 0.5) { if (diff > .5) {
++frac; /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */ ++frac; /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
if (frac >= kPow10[prec]) { if (frac >= exp10l(prec)) {
frac = 0; frac = 0;
++whole; ++whole;
} }
} else if (diff < 0.5) { } else if (diff < .5) {
} else if (!frac || (frac & 1)) { } else if (!frac || (frac & 1)) {
++frac; /* if halfway, round up if odd OR if last digit is 0 */ ++frac; /* if halfway, round up if odd OR if last digit is 0 */
} }
if (!prec) { if (!prec) {
diff = fabsl(value) - whole; diff = fabsl(value) - whole;
if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { if ((!(diff < .5) || (diff > .5)) && (whole & 1)) {
/* exactly 0.5 and ODD, then round up */ /* exactly .5 and ODD, then round up */
/* 1.5 -> 2, but 2.5 -> 2 */ /* 1.5 -> 2, but 2.5 -> 2 */
++whole; ++whole;
} }

View File

@ -8,7 +8,7 @@
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
int spacepad(int(int, void *), void *, unsigned long) hidden; 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; unsigned long) hidden;
int stoa(int(int, void *), void *, void *, unsigned long, unsigned long, int stoa(int(int, void *), void *, void *, unsigned long, unsigned long,
unsigned long, unsigned char, unsigned char) hidden; unsigned long, unsigned char, unsigned char) hidden;

View File

@ -179,7 +179,7 @@ typedef struct axdx_t {
#undef __SIZEOF_INTMAX__ #undef __SIZEOF_INTMAX__
#endif #endif
#if !defined(__STRICT_ANSI__) && __SIZEOF_POINTER__ == 8 && \ #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 #define __SIZEOF_INTMAX__ 16
#else #else
#define __SIZEOF_INTMAX__ __SIZEOF_POINTER__ #define __SIZEOF_INTMAX__ __SIZEOF_POINTER__
@ -279,7 +279,7 @@ typedef uint64_t uintmax_t;
#ifndef noinstrument #ifndef noinstrument
#if !defined(__STRICT_ANSI__) && \ #if !defined(__STRICT_ANSI__) && \
(__has_attribute(__no_instrument_function__) || \ (__has_attribute(__no_instrument_function__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 204) (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 204)
#define noinstrument __attribute__((__no_instrument_function__)) #define noinstrument __attribute__((__no_instrument_function__))
#else #else
#define noinstrument #define noinstrument
@ -287,8 +287,9 @@ typedef uint64_t uintmax_t;
#endif #endif
#ifndef noreturn #ifndef noreturn
#if !defined(__STRICT_ANSI__) && \ #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__)) #define noreturn __attribute__((__noreturn__))
#else #else
#define noreturn #define noreturn
@ -301,8 +302,9 @@ typedef uint64_t uintmax_t;
* @see pureconst * @see pureconst
*/ */
#ifndef nosideeffect #ifndef nosideeffect
#if !defined(__STRICT_ANSI__) && \ #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__)) #define nosideeffect __attribute__((__pure__))
#else #else
#define nosideeffect #define nosideeffect
@ -310,8 +312,9 @@ typedef uint64_t uintmax_t;
#endif #endif
#ifndef noinline #ifndef noinline
#if !defined(__STRICT_ANSI__) && \ #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__)) #define noinline __attribute__((__noinline__))
#else #else
#define noinline #define noinline
@ -319,8 +322,9 @@ typedef uint64_t uintmax_t;
#endif #endif
#ifndef noclone #ifndef noclone
#if !defined(__STRICT_ANSI__) && \ #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__)) #define noclone __attribute__((__noclone__))
#else #else
#define noclone #define noclone
@ -343,9 +347,11 @@ typedef uint64_t uintmax_t;
#ifdef __cplusplus #ifdef __cplusplus
#define forceinline inline #define forceinline inline
#else #else
#if !defined(__STRICT_ANSI__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 302 #if !defined(__STRICT_ANSI__) && \
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 403 || !defined(__cplusplus) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 302
(defined(__clang__) && \ #if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \
!defined(__cplusplus) || \
(defined(__clang__) && \
(defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__))) (defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__)))
#if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus) #if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus)
#define forceinline \ #define forceinline \
@ -379,8 +385,9 @@ typedef uint64_t uintmax_t;
* @see unsigned char * @see unsigned char
*/ */
#ifndef mayalias #ifndef mayalias
#if !defined(__STRICT_ANSI__) && \ #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__)) #define mayalias __attribute__((__may_alias__))
#else #else
#define mayalias #define mayalias
@ -393,8 +400,9 @@ typedef uint64_t uintmax_t;
* @see gc(), free(), close(), etc. * @see gc(), free(), close(), etc.
*/ */
#ifndef nodiscard #ifndef nodiscard
#if !defined(__STRICT_ANSI__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304 || \ #if !defined(__STRICT_ANSI__) && \
__has_attribute(__warn_unused_result__)) ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \
__has_attribute(__warn_unused_result__))
#define nodiscard __attribute__((__warn_unused_result__)) #define nodiscard __attribute__((__warn_unused_result__))
#else #else
#define nodiscard #define nodiscard
@ -416,7 +424,7 @@ typedef uint64_t uintmax_t;
#ifndef flattenout #ifndef flattenout
#if __has_attribute(__flatten__) || \ #if __has_attribute(__flatten__) || \
(__GNUC__ * 100 + __GNUC_MINOR__ >= 401 && !defined(__llvm__)) ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 401 && !defined(__llvm__))
#define flattenout __attribute__((__flatten__)) #define flattenout __attribute__((__flatten__))
#else #else
#define flattenout #define flattenout
@ -424,9 +432,10 @@ typedef uint64_t uintmax_t;
#endif #endif
#ifndef externinline #ifndef externinline
#if !defined(__STRICT_ANSI__) && \ #if !defined(__STRICT_ANSI__) && \
(!defined(__cplusplus) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403 || \ (!defined(__cplusplus) || \
(defined(__clang__) && \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \
(defined(__clang__) && \
(defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__)))) (defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__))))
#if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus) #if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus)
#define externinline extern __inline __attribute__((__gnu_inline__)) #define externinline extern __inline __attribute__((__gnu_inline__))
@ -443,16 +452,18 @@ typedef uint64_t uintmax_t;
* @note can be used to minimize page-faults and improve locality * @note can be used to minimize page-faults and improve locality
*/ */
#ifndef relegated #ifndef relegated
#if !defined(__STRICT_ANSI__) && \ #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__)) #define relegated __attribute__((__cold__))
#else #else
#define relegated #define relegated
#endif #endif
#endif #endif
#if !defined(__STRICT_ANSI__) && \ #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))) #define warnifused(s) __attribute__((__warning__(s)))
#else #else
#define warnifused(s) #define warnifused(s)
@ -465,7 +476,8 @@ typedef uint64_t uintmax_t;
*/ */
#ifndef firstclass #ifndef firstclass
#if !defined(__STRICT_ANSI__) && \ #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__)) #define firstclass __attribute__((__hot__))
#else #else
#define firstclass #define firstclass
@ -479,8 +491,9 @@ typedef uint64_t uintmax_t;
* runtime too (only in MODE=dbg mode) by synthetic Ubsan code. * runtime too (only in MODE=dbg mode) by synthetic Ubsan code.
*/ */
#ifndef paramsnonnull #ifndef paramsnonnull
#if !defined(__STRICT_ANSI__) && \ #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)) #define paramsnonnull(opt_1idxs) __attribute__((__nonnull__ opt_1idxs))
#else #else
#define paramsnonnull(opt_1idxs) #define paramsnonnull(opt_1idxs)
@ -505,7 +518,7 @@ typedef uint64_t uintmax_t;
*/ */
#if __STDC_VERSION__ + 0 < 199901L && !defined(restrict) #if __STDC_VERSION__ + 0 < 199901L && !defined(restrict)
#if !defined(__STRICT_ANSI__) && !defined(__cplusplus) && \ #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__ #define restrict __restrict__
#else #else
#define restrict #define restrict
@ -520,7 +533,8 @@ typedef uint64_t uintmax_t;
#ifndef nocallback #ifndef nocallback
#if !defined(__STRICT_ANSI__) && \ #if !defined(__STRICT_ANSI__) && \
(__has_attribute(__leaf__) || \ (__has_attribute(__leaf__) || \
(!defined(__llvm__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 406)) (!defined(__llvm__) && \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406))
#define nocallback __attribute__((__leaf__)) #define nocallback __attribute__((__leaf__))
#else #else
#define nocallback #define nocallback
@ -529,7 +543,8 @@ typedef uint64_t uintmax_t;
#ifndef nothrow #ifndef nothrow
#if defined(__cplusplus) && !defined(__STRICT_ANSI__) && \ #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__)) #define nothrow __attribute__((__nothrow__))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define nothrow __declspec(nothrow) #define nothrow __declspec(nothrow)
@ -545,7 +560,8 @@ typedef uint64_t uintmax_t;
*/ */
#ifndef nooptimize #ifndef nooptimize
#ifndef __STRICT_ANSI__ #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))) #define nooptimize __attribute__((__optimize__(1)))
#elif defined(__llvm__) || __has_attribute(__optnone__) #elif defined(__llvm__) || __has_attribute(__optnone__)
#define nooptimize __attribute__((__optnone__)) #define nooptimize __attribute__((__optnone__))
@ -564,7 +580,8 @@ typedef uint64_t uintmax_t;
*/ */
#ifndef optimizesize #ifndef optimizesize
#ifndef __STRICT_ANSI__ #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"))) #define optimizesize __attribute__((__optimize__("s")))
#elif defined(__llvm__) || __has_attribute(__optnone__) #elif defined(__llvm__) || __has_attribute(__optnone__)
#define optimizesize __attribute__((__optnone__)) #define optimizesize __attribute__((__optnone__))
@ -584,8 +601,9 @@ typedef uint64_t uintmax_t;
* @todo this is dangerous delete? * @todo this is dangerous delete?
*/ */
#ifndef optimizespeed #ifndef optimizespeed
#if !defined(__STRICT_ANSI__) && \ #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))) #define optimizespeed __attribute__((__optimize__(3)))
#else #else
#define optimizespeed #define optimizespeed
@ -596,8 +614,9 @@ typedef uint64_t uintmax_t;
* Declares prototype that behaves similar to setjmp() or vfork(). * Declares prototype that behaves similar to setjmp() or vfork().
*/ */
#ifndef returnstwice #ifndef returnstwice
#if !defined(__STRICT_ANSI__) && (__has_attribute(__returns_twice__) || \ #if !defined(__STRICT_ANSI__) && \
__GNUC__ * 100 + __GNUC_MINOR__ >= 402) (__has_attribute(__returns_twice__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 402)
#define returnstwice __attribute__((__returns_twice__)) #define returnstwice __attribute__((__returns_twice__))
#else #else
#define returnstwice #define returnstwice
@ -622,8 +641,9 @@ typedef uint64_t uintmax_t;
* @see nodebuginfo * @see nodebuginfo
*/ */
#ifndef artificial #ifndef artificial
#if !defined(__STRICT_ANSI__) && (__has_attribute(__artificial__) || \ #if !defined(__STRICT_ANSI__) && \
__GNUC__ * 100 + __GNUC_MINOR__ >= 403) (__has_attribute(__artificial__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403)
#define artificial __attribute__((__artificial__)) #define artificial __attribute__((__artificial__))
#else #else
#define artificial #define artificial
@ -636,8 +656,9 @@ typedef uint64_t uintmax_t;
* @see libc/dce.h * @see libc/dce.h
*/ */
#ifndef microarchitecture #ifndef microarchitecture
#if !defined(__STRICT_ANSI__) && \ #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))) #define microarchitecture(march) __attribute__((__target__(march)))
#else #else
#define microarchitecture(march) #define microarchitecture(march)
@ -661,7 +682,7 @@ typedef uint64_t uintmax_t;
* Defines function with prologue that fixes misaligned stack. * Defines function with prologue that fixes misaligned stack.
* @see nocallersavedregisters and consider assembly * @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__) __has_attribute(__force_align_arg_pointer__)
#define forcealignargpointer __attribute__((__force_align_arg_pointer__)) #define forcealignargpointer __attribute__((__force_align_arg_pointer__))
#else #else
@ -675,8 +696,9 @@ typedef uint64_t uintmax_t;
* runtime too by synthetic code, only in MODE=dbg mode. * runtime too by synthetic code, only in MODE=dbg mode.
*/ */
#ifndef returnsnonnull #ifndef returnsnonnull
#if !defined(__STRICT_ANSI__) && (__has_attribute(__returns_nonnull__) || \ #if !defined(__STRICT_ANSI__) && \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409) (__has_attribute(__returns_nonnull__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define returnsnonnull __attribute__((__returns_nonnull__)) #define returnsnonnull __attribute__((__returns_nonnull__))
#else #else
#define returnsnonnull #define returnsnonnull
@ -690,8 +712,9 @@ typedef uint64_t uintmax_t;
* @param (alignment, misalignment) * @param (alignment, misalignment)
* @see attributeallocalign(), returnspointerwithnoaliases, mallocesque * @see attributeallocalign(), returnspointerwithnoaliases, mallocesque
*/ */
#if !defined(__STRICT_ANSI__) && (__has_attribute(__assume_aligned__) || \ #if !defined(__STRICT_ANSI__) && \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409) (__has_attribute(__assume_aligned__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define returnsaligned(x) __attribute__((__assume_aligned__ x)) #define returnsaligned(x) __attribute__((__assume_aligned__ x))
#else #else
#define returnsaligned(x) #define returnsaligned(x)
@ -702,8 +725,9 @@ typedef uint64_t uintmax_t;
* @see attributeallocsize(), attributeallocalign() * @see attributeallocsize(), attributeallocalign()
*/ */
#ifndef returnspointerwithnoaliases #ifndef returnspointerwithnoaliases
#if !defined(__STRICT_ANSI__) && \ #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__)) #define returnspointerwithnoaliases __attribute__((__malloc__))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define returnspointerwithnoaliases __declspec(allocator) #define returnspointerwithnoaliases __declspec(allocator)
@ -713,8 +737,9 @@ typedef uint64_t uintmax_t;
#endif #endif
#ifndef attributeallocsize #ifndef attributeallocsize
#if !defined(__STRICT_ANSI__) && (__has_attribute(__alloc_size__) || \ #if !defined(__STRICT_ANSI__) && \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409) (__has_attribute(__alloc_size__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define attributeallocsize(x) __attribute__((__alloc_size__ x)) #define attributeallocsize(x) __attribute__((__alloc_size__ x))
#else #else
#define attributeallocsize(x) #define attributeallocsize(x)
@ -722,8 +747,9 @@ typedef uint64_t uintmax_t;
#endif #endif
#ifndef attributeallocalign #ifndef attributeallocalign
#if !defined(__STRICT_ANSI__) && (__has_attribute(__alloc_align__) || \ #if !defined(__STRICT_ANSI__) && \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409) (__has_attribute(__alloc_align__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define attributeallocalign(x) __attribute__((__alloc_align__ x)) #define attributeallocalign(x) __attribute__((__alloc_align__ x))
#else #else
#define attributeallocalign(x) #define attributeallocalign(x)
@ -747,7 +773,7 @@ typedef uint64_t uintmax_t;
#if __cplusplus + 0 >= 201103L #if __cplusplus + 0 >= 201103L
#define autotype(x) auto #define autotype(x) auto
#elif (__has_builtin(auto_type) || defined(__llvm__) || \ #elif (__has_builtin(auto_type) || defined(__llvm__) || \
__GNUC__ * 100 + __GNUC_MINOR__ >= 409) (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409)
#define autotype(x) __auto_type #define autotype(x) __auto_type
#else #else
#define autotype(x) typeof(x) #define autotype(x) typeof(x)

View File

@ -75,7 +75,7 @@
#define ENV_MAX 0x7fff /* b/c windows */ #define ENV_MAX 0x7fff /* b/c windows */
#define ARG_MAX 0x3fff /* b/c windows */ #define ARG_MAX 0x3fff /* b/c windows */
#define CMD_MAX 0x4000 /* 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 NAME_MAX 63 /* b/c dns */
#define CHILD_MAX 25 /* only if malloc isn't linked */ #define CHILD_MAX 25 /* only if malloc isn't linked */
#define OPEN_MAX 16 /* 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" #include "libc/macros.h"
/ Phil Katz CRC-32 Polynomial / Jump table for mpsadbw() with non-constexpr immediate parameter.
/ 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 / @note needs sse4 cf. core c. 2006 cf. bulldozer c. 2011
/ bitreverse32(0x104c11db7) / @see mpsadbw()
#define kZipCrc32Polynomial 0xedb88320 .align 8
__mpsadbws:
.initbss 300,_init_kCrc32Tab i = 0
kCrc32Tab: .rept 8
.rept 256 mpsadbw $i,%xmm1,%xmm0
.long 0 ret
nop
i = i + 1
.endr .endr
.endobj kCrc32Tab,globl,hidden .endfn __mpsadbws,globl
.previous
.init.start 300,_init_kCrc32Tab
push %rsi
mov $kZipCrc32Polynomial,%esi
call crc32init
pop %rsi
.init.end 300,_init_kCrc32Tab
.source __FILE__

View File

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

View File

@ -102,6 +102,111 @@ struct AsanGlobal {
char *odr_indicator; 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) { static bool __asan_is_mapped(void *p) {
int x, i; int x, i;
x = (intptr_t)p >> 16; 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; return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y;
} }
void __asan_map_shadow(void *addr, size_t size) { static void *__asan_allocate(size_t align, size_t size, int underrun,
int i, n, x; int overrun) {
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) {
char *p, *s; char *p, *s;
size_t q, r, i; size_t q, r, i;
if (!(p = dlmemalign(align, ROUNDUP(size, 8) + 16))) return NULL; 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; 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; char *s;
size_t n; size_t n;
s = (char *)SHADOW((intptr_t)p); for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) {
n = dlmalloc_usable_size(p); if (!*s) {
n /= 8; n += 8;
memset(s, kind, n); } else if (*s > 0) {
dlfree(p); n += *s & 7;
} else {
break;
}
}
return n;
} }
void __asan_free(void *vp) { static void __asan_free(void *p) {
__asan_deallocate(vp, kAsanHeapFree); 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); 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); 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; char *p;
size_t size; size_t size;
if (__builtin_mul_overflow(n, m, &size)) size = -1; if (__builtin_mul_overflow(n, m, &size)) size = -1;
@ -190,7 +292,7 @@ void *__asan_calloc(size_t n, size_t m) {
return p; return p;
} }
void *__asan_realloc(void *p, size_t n) { static void *__asan_realloc(void *p, size_t n) {
char *p2; char *p2;
if (p) { if (p) {
if (n) { if (n) {
@ -208,86 +310,32 @@ void *__asan_realloc(void *p, size_t n) {
return p2; return p2;
} }
void *__asan_valloc(size_t n) { static void *__asan_valloc(size_t n) {
return __asan_memalign(PAGESIZE, 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)); 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) { void __asan_register_globals(struct AsanGlobal g[], int n) {
size_t i; unsigned i;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
__asan_poison((intptr_t)g[i].addr, g[i].size, g[i].size_with_redzone, __asan_poison_redzone((intptr_t)g[i].addr, g[i].size,
kAsanGlobalOverrun); g[i].size_with_redzone, kAsanGlobalOverrun);
} }
} }
void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) { void __asan_unregister_globals(struct AsanGlobal g[], int n) {
char *p, *s, ibuf[21], buf[256]; unsigned i;
switch (*(char *)SHADOW((intptr_t)addr)) { intptr_t a, b;
case kAsanStackFree: for (i = 0; i < n; ++i) {
s = "stack use after release"; a = ROUNDUP((intptr_t)g[i].addr, 8);
break; b = ROUNDDOWN((intptr_t)g[i].addr + g[i].size_with_redzone, 8);
case kAsanHeapFree: if (b > a) {
s = "heap use after free"; memset((char *)SHADOW(a), kAsanGlobalUnregistered, (b - a) >> 3);
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;
} }
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) { 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) { 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) { 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; 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) { 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) { 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); 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; int i;
static bool once; static bool once;
register intptr_t rsp asm("rsp"); 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

@ -1,18 +1,19 @@
#ifndef COSMOPOLITAN_LIBC_LOG_ASAN_H_ #ifndef COSMOPOLITAN_LIBC_LOG_ASAN_H_
#define COSMOPOLITAN_LIBC_LOG_ASAN_H_ #define COSMOPOLITAN_LIBC_LOG_ASAN_H_
#define kAsanScale 3 #define kAsanScale 3
#define kAsanMagic 0x7fff8000 #define kAsanMagic 0x7fff8000
#define kAsanHeapFree -1 #define kAsanHeapFree -1
#define kAsanStackFree -2 #define kAsanStackFree -2
#define kAsanRelocated -3 #define kAsanRelocated -3
#define kAsanHeapUnderrun -4 #define kAsanHeapUnderrun -4
#define kAsanHeapOverrun -5 #define kAsanHeapOverrun -5
#define kAsanGlobalOverrun -6 #define kAsanGlobalOverrun -6
#define kAsanStackUnderrun -7 #define kAsanGlobalUnregistered -7
#define kAsanStackOverrun -8 #define kAsanStackUnderrun -8
#define kAsanAllocaOverrun -9 #define kAsanStackOverrun -9
#define kAsanUnscoped -10 #define kAsanAllocaOverrun -10
#define kAsanUnscoped -11
#define SHADOW(x) (((x) >> kAsanScale) + kAsanMagic) #define SHADOW(x) (((x) >> kAsanScale) + kAsanMagic)

View File

@ -18,41 +18,29 @@
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/alg/bisectcarleft.h" #include "libc/alg/bisectcarleft.h"
#include "libc/assert.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/conv/itoa.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/log/backtrace.h" #include "libc/log/backtrace.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/nexgen32e/gc.h" #include "libc/nexgen32e/gc.h"
#include "libc/nexgen32e/stackframe.h" #include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/symbols.h" #include "libc/runtime/symbols.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.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;
}
int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp, int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
struct SymbolTable *symbols) { struct SymbolTable *st) {
size_t gi; size_t gi;
char buf[256];
intptr_t addr; intptr_t addr;
int64_t addend;
struct Garbages *garbage; struct Garbages *garbage;
char *p, buf[256], ibuf[21];
const struct Symbol *symbol;
const struct StackFrame *frame; const struct StackFrame *frame;
if (!symbols) return -1; if (!st) return -1;
garbage = weaken(g_garbage); garbage = weaken(g_garbage);
gi = garbage ? garbage->i : 0; gi = garbage ? garbage->i : 0;
for (frame = bp; frame; frame = frame->next) { for (frame = bp; frame; frame = frame->next) {
@ -62,8 +50,25 @@ int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp,
--gi; --gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage")); } while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage"));
} }
fprintf(f, "%p %p %s\n", frame, addr, p = buf;
FormatAddress(f, symbols, addr, buf, sizeof(buf), true)); 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; return 0;
} }

View File

@ -17,11 +17,11 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/conv/itoa.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/log.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. * Handles failure of CHECK_xx() macros in -DNDEBUG mode.
@ -35,8 +35,17 @@
*/ */
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got, relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) { const char *opchar) {
int lasterr = errno; char bx[21];
int lasterr;
lasterr = errno;
startfatal_ndebug(); startfatal_ndebug();
fprintf(stderr, "%s: %#lx %s %#lx (%s)\n", "check failed", want, opchar, got, __print_string("check failed: 0x");
strerror(lasterr)); __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/bits/safemacros.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/ok.h" #include "libc/sysv/consts/ok.h"
@ -31,12 +32,12 @@ nodiscard char *commandvenv(const char *var, const char *cmd) {
char pathbuf[PATH_MAX]; char pathbuf[PATH_MAX];
if ((exepath = getenv(var))) { if ((exepath = getenv(var))) {
if (!isempty(exepath) && access(exepath, X_OK) != -1) { if (!isempty(exepath) && access(exepath, X_OK) != -1) {
return exepath; return strdup(exepath);
} else { } else {
return NULL; return NULL;
} }
} else if ((exepath = commandv(cmd, pathbuf))) { } else if ((exepath = commandv(cmd, pathbuf))) {
return exepath; return strdup(exepath);
} else { } else {
return NULL; return NULL;
} }

View File

@ -24,7 +24,7 @@
STATIC_YOINK("ntoa"); STATIC_YOINK("ntoa");
void malloc_stats(void) { 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, "max system bytes = %'10zu\n", res.maxfp);
(fprintf)(stderr, "system bytes = %'10zu\n", res.fp); (fprintf)(stderr, "system bytes = %'10zu\n", res.fp);
(fprintf)(stderr, "in use bytes = %'10zu\n", res.used); (fprintf)(stderr, "in use bytes = %'10zu\n", res.used);

View File

@ -27,64 +27,6 @@
/ since ASAN has the same stylistic hugeness as UBSAN. / since ASAN has the same stylistic hugeness as UBSAN.
/ We also guard all the functions, against reentrancy. / 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: __asan_report_load1:
push $1 push $1
jmp OnReportLoad jmp OnReportLoad
@ -264,10 +206,6 @@ __asan_after_dynamic_init:
ret ret
.endfn __asan_after_dynamic_init,globl .endfn __asan_after_dynamic_init,globl
__asan_unregister_globals:
ret
.endfn __asan_unregister_globals,globl
__asan_version_mismatch_check_v8: __asan_version_mismatch_check_v8:
ret ret
.endfn __asan_version_mismatch_check_v8,globl .endfn __asan_version_mismatch_check_v8,globl
@ -287,7 +225,7 @@ __asan_version_mismatch_check_v8:
.rodata.cst4 .rodata.cst4
__asan_option_detect_stack_use_after_return: __asan_option_detect_stack_use_after_return:
.long 1 .long 0
.endobj __asan_option_detect_stack_use_after_return,globl .endobj __asan_option_detect_stack_use_after_return,globl
.previous .previous

View File

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

View File

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

View File

@ -312,30 +312,6 @@ void sincosl(long double, long double *, long double *);
#define __X87_CONST(OP, VALUE) VALUE #define __X87_CONST(OP, VALUE) VALUE
#endif #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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_MATH_H_ */ #endif /* COSMOPOLITAN_LIBC_MATH_H_ */

View File

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

View File

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

View File

@ -21,12 +21,25 @@
#include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/crc32.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
static uint32_t kCrc32Tab[256];
/** /**
* Computes Phil Katz CRC-32 used by zip/zlib/gzip/etc. * 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) { uint32_t crc32_z(uint32_t h, const void *data, size_t size) {
const unsigned char *p, *pe; const unsigned char *p, *pe;
static bool once;
size_t skip; size_t skip;
if (!once) {
crc32init(kCrc32Tab, 0xedb88320);
once = true;
}
if (data) { if (data) {
h ^= 0xffffffff; h ^= 0xffffffff;
if (size >= 64 && X86_HAVE(PCLMUL)) { if (size >= 64 && X86_HAVE(PCLMUL)) {

View File

@ -12,8 +12,11 @@ struct NtWin32FindData {
uint32_t nFileSizeLow; uint32_t nFileSizeLow;
uint32_t dwReserved0; uint32_t dwReserved0;
uint32_t dwReserved1; uint32_t dwReserved1;
char16_t cFileName[PATH_MAX]; char16_t cFileName[260];
char16_t cAlternateFileName[14]; char16_t cAlternateFileName[14];
uint32_t dwFileType;
uint32_t dwCreatorType;
uint16_t wFinderFlags;
}; };
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #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 push %rdi
xor %edi,%edi xor %edi,%edi
call __cxa_finalize call __cxa_finalize
call _destruct
pop %rdi pop %rdi
pop %rdi pop %rdi
call _Exit call _Exit

View File

@ -136,7 +136,8 @@
} \ } \
while (0) 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 LOAD_DEFAULT_RBX() /* disabled for now b/c clang */
#define RESTORE_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 * @clob nothing except flags
* @see PRINT() * @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; int64_t ax, ordinal;
LOAD_DEFAULT_RBX();
if (NT_HAVE_IMPORT(__imp_WriteFile)) { if (NT_HAVE_IMPORT(__imp_WriteFile)) {
__print$nt(data, len); __print$nt(data, len);
} else { } else {
@ -69,3 +68,9 @@ privileged interruptfn void __print(const void *data, size_t len) {
} }
RESTORE_RBX(); 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 * @return client fd which needs close(), or -1 w/ errno
*/ */
int accept4(int fd, void *out_addr, uint32_t *inout_addrsize, int flags) { 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()) { if (!IsWindows()) {
return accept4$sysv(fd, out_addr, inout_addrsize, flags); return accept4$sysv(fd, out_addr, inout_addrsize, flags);
} else if (isfdkind(fd, kFdSocket)) { } else if (isfdkind(fd, kFdSocket)) {

View File

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

View File

@ -34,6 +34,7 @@
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int connect(int fd, const void *addr, uint32_t addrsize) { int connect(int fd, const void *addr, uint32_t addrsize) {
if (!addr) return efault();
if (!IsWindows()) { if (!IsWindows()) {
return connect$sysv(fd, addr, addrsize); return connect$sysv(fd, addr, addrsize);
} else if (isfdkind(fd, kFdSocket)) { } 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 iovec2nt(struct iovec$nt[hasatleast 16], const struct iovec *,
size_t) hidden; size_t) hidden;
ssize_t sendto$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *, 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 *, ssize_t recvfrom$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *,
uint32_t *) hidden; uint32_t *) hidden;

View File

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

View File

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

View File

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

View File

@ -17,16 +17,20 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/limits.h"
#include "libc/str/str.h" #include "libc/str/str.h"
/** /**
* Copies string, returning pointer to where copying ended. * Copies string and advances destination pointer.
*
* @see strcpy(), mempcpy()
* @asyncsignalsafe * @asyncsignalsafe
*/ */
char *stpcpy(char *dst, const char *src) { char *stpcpy(char *dst, const char *src) {
dst = memccpy(dst, src, '\0', SIZE_MAX); char c;
return dst - 1; 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 */ #else /* hosted/sse2/unbloat */
#define memmove(DEST, SRC, SIZE) __memcpy((DEST), (SRC), (SIZE))
#define mempcpy(DEST, SRC, SIZE) \ #define mempcpy(DEST, SRC, SIZE) \
({ \ ({ \
void *Rdi, *Dest = (DEST); \ void *Rdi, *Dest = (DEST); \
@ -513,21 +511,6 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque;
#endif /* hosted/sse2/unbloat */ #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 pututf16(BUF, SIZE, CH, AWESOME) __pututf16(BUF, SIZE, CH, AWESOME)
#define getutf16(BUF, CHPTR) __getutf16(BUF, CHPTR) #define getutf16(BUF, CHPTR) __getutf16(BUF, CHPTR)
size_t _strlen(const char *s) asm("strlen") strlenesque; size_t _strlen(const char *s) asm("strlen") strlenesque;

View File

@ -42,10 +42,6 @@ $(LIBC_STR_A).pkg: \
$(LIBC_STR_A_OBJS) \ $(LIBC_STR_A_OBJS) \
$(foreach x,$(LIBC_STR_A_DIRECTDEPS),$($(x)_A).pkg) $(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_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)))
LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS)) LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS))
LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS)) LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS))

View File

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.inc" .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__BASE 64 64 64 64 64 # unix consensus & force NT
syscon ex EX__MAX 78 78 78 78 78 # 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 # msync() flags
# #
# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary # 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_IP 0 0 0 0 0 # consensus
syscon sol SOL_SOCKET 1 0xffff 0xffff 0xffff 0xffff # bsd+nt 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_AAL 265 0 0 0 0
syscon sol SOL_ALG 279 0 0 0 0 syscon sol SOL_ALG 279 0 0 0 0
syscon sol SOL_ATM 264 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_CAIF 278 0 0 0 0
syscon sol SOL_DCCP 269 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_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_IRDA 266 0 0 0 0
syscon sol SOL_IUCV 277 0 0 0 0 syscon sol SOL_IUCV 277 0 0 0 0
syscon sol SOL_KCM 281 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_RAW 255 0 0 0 0
syscon sol SOL_RDS 276 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_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_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 sol SOL_X25 262 0 0 0 0
syscon in IN_LOOPBACKNET 127 127 127 127 0 # unix consensus 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 BLKSECTSET 0x1266 0 0 0 0
syscon misc BLKSSZGET 0x1268 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_FIN 1 1 1 1 1 # consensus
syscon misc TH_SYN 2 2 2 2 2 # consensus syscon misc TH_SYN 2 2 2 2 2 # consensus
syscon misc TH_RST 4 4 4 4 4 # consensus syscon misc TH_RST 4 4 4 4 4 # consensus

View File

@ -1,2 +1,2 @@
.include "libc/sysv/consts/syscon.inc" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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" .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_ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_
#include "libc/runtime/symbolic.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) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ 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_CHR;
hidden extern const long DT_DIR; hidden extern const long DT_DIR;
hidden extern const long DT_FIFO; hidden extern const long DT_BLK;
hidden extern const long DT_LNK;
hidden extern const long DT_REG; hidden extern const long DT_REG;
hidden extern const long DT_LNK;
hidden extern const long DT_SOCK; hidden extern const long DT_SOCK;
hidden extern const long DT_UNKNOWN;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #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_ */ #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_create 0xffffffffffff00d5 globl
scall epoll_wait 0xffffffffffff00e8 globl scall epoll_wait 0xffffffffffff00e8 globl
scall epoll_ctl 0xffffffffffff00e9 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 set_tid_address 0xffffffffffff00da globl
scall restart_syscall 0xffffffffffff00db globl scall restart_syscall 0xffffffffffff00db globl
scall semtimedop 0xffffffffffff00dc globl scall semtimedop 0xffffffffffff00dc globl

View File

@ -24,7 +24,7 @@
testonly void testlib_formatbinaryasglyphs(const char16_t *want, testonly void testlib_formatbinaryasglyphs(const char16_t *want,
const void *got, size_t n, const void *got, size_t n,
char **out_v1, char **out_v2) { 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_v1 = xasprintf("%`#.*hs", n, want);
*out_v2 = xasprintf(" %`'#.*s", n, got); *out_v2 = xasprintf(" %`'#.*s", n, got);
} }

View File

@ -28,7 +28,7 @@ static unsigned clip(unsigned index, unsigned count) {
return index < count ? index : 0; 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", (snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
kWeekdayNameShort[clip(date->tm_wday, 7)], kWeekdayNameShort[clip(date->tm_wday, 7)],
kMonthNameShort[clip(date->tm_mon, 12)], date->tm_mday, kMonthNameShort[clip(date->tm_mon, 12)], date->tm_mday,

View File

@ -20,7 +20,7 @@
#include "libc/time/struct/tm.h" #include "libc/time/struct/tm.h"
#include "libc/time/time.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]; struct tm date[1];
return asctime_r(localtime_r(timep, date), buf); return asctime_r(localtime_r(timep, date), buf);
} }

View File

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

View File

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

View File

@ -1,15 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_ #ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_
#define 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/timespec.h"
#include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/struct/utimbuf.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
struct itimerval;
struct timezone;
struct tm;
struct utimbuf;
extern const char kWeekdayNameShort[7][4]; extern const char kWeekdayNameShort[7][4];
extern const char kWeekdayName[7][10]; extern const char kWeekdayName[7][10];
extern const char kMonthNameShort[12][4]; 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 *) size_t strftime(char *, size_t, const char *, const struct tm *)
strftimeesque(3); strftimeesque(3);
char *asctime(const struct tm *); char *asctime(const struct tm *);
char *asctime_r(const struct tm *, char * /*[64]*/);
char *ctime(const int64_t *); 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 futimens(int, const struct timespec[2]);
int utimensat(int, const char *, const struct timespec[2], int); 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 := \ LIBC_TIME_A_FILES := \
$(wildcard libc/time/struct/*) \ $(wildcard libc/time/struct/*) \
$(wildcard libc/time/*) $(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_S = $(filter %.S,$(LIBC_TIME_A_FILES))
LIBC_TIME_A_SRCS_C = $(filter %.c,$(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 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "ape/lib/pc.h"
#include "libc/macros.h" #include "libc/macros.h"
.source __FILE__ .source __FILE__
@ -29,7 +30,7 @@ tinymath_copysignl:
fnstsw fnstsw
fstp %st fstp %st
fldt 16(%rbp) fldt 16(%rbp)
testb $2,%ah test $FPU_C1>>8,%ah
fabs fabs
je 1f je 1f
fchs fchs

View File

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

View File

@ -26,7 +26,7 @@
/ /
/ @param 𝑥 is double scalar in low half of %xmm0 / @param 𝑥 is double scalar in low half of %xmm0
/ @return 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,𝑥)) / round(𝑥) = trunc(𝑥+copysign(.5,𝑥))
tinymath_round: tinymath_round:
#if !X86_NEED(SSE4_2) #if !X86_NEED(SSE4_2)

View File

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

View File

@ -21,13 +21,13 @@
#include "net/http/http.h" #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; const struct HttpHeaderSlot *slot;
if ((slot = in_word_set(str, len))) { if ((slot = LookupHttpHeader(str, len))) {
return slot->code; return slot->code;
} else { } else {
return 0; return -1;
} }
} }

View File

@ -6,57 +6,57 @@
%compare-strncmp %compare-strncmp
%ignore-case %ignore-case
%language=ANSI-C %language=ANSI-C
%pic
%readonly-tables %readonly-tables
%struct-type %struct-type
struct HttpHeaderSlot { unsigned char name; unsigned char code; }; %define lookup-function-name LookupHttpHeader
struct HttpHeaderSlot { char *name; char code; };
%% %%
Accept, kHttpAccept Accept, kHttpAccept
Accept-Charset, kHttpAcceptCharset Accept-Charset, kHttpAcceptCharset
Accept-Encoding, kHttpAcceptEncoding Accept-Encoding, kHttpAcceptEncoding
Accept-Language, kHttpAcceptLanguage Accept-Language, kHttpAcceptLanguage
Age, kHttpAge Age, kHttpAge
Allow, kHttpAllow Allow, kHttpAllow
Authorization, kHttpAuthorization Authorization, kHttpAuthorization
Cache-Control, kHttpCacheControl Cache-Control, kHttpCacheControl
Chunked, kHttpChunked Chunked, kHttpChunked
Close, kHttpClose Close, kHttpClose
Connection, kHttpConnection Connection, kHttpConnection
Content-Base, kHttpContentBase Content-Base, kHttpContentBase
Content-Encoding, kHttpContentEncoding Content-Encoding, kHttpContentEncoding
Content-Language, kHttpContentLanguage Content-Language, kHttpContentLanguage
Content-Length, kHttpContentLength Content-Length, kHttpContentLength
Content-Location, kHttpContentLocation Content-Location, kHttpContentLocation
Content-Md5, kHttpContentMd5 Content-Md5, kHttpContentMd5
Content-Range, kHttpContentRange Content-Range, kHttpContentRange
Content-Type, kHttpContentType Content-Type, kHttpContentType
Date, kHttpDate Date, kHttpDate
Etag, kHttpEtag Etag, kHttpEtag
Expires, kHttpExpires Expires, kHttpExpires
From, kHttpFrom From, kHttpFrom
Host, kHttpHost Host, kHttpHost
If-Match, kHttpIfMatch If-Match, kHttpIfMatch
If-Modified-Since, kHttpIfModifiedSince If-Modified-Since, kHttpIfModifiedSince
If-None-Match, kHttpIfNoneMatch If-None-Match, kHttpIfNoneMatch
If-Range, kHttpIfRange If-Range, kHttpIfRange
If-Unmodified-Since, kHttpIfUnmodifiedSince If-Unmodified-Since, kHttpIfUnmodifiedSince
Keep-Alive, kHttpKeepAlive Keep-Alive, kHttpKeepAlive
Max-Forwards, kHttpMaxForwards Max-Forwards, kHttpMaxForwards
Pragma, kHttpPragma Pragma, kHttpPragma
Proxy-Authenticate, kHttpProxyAuthenticate Proxy-Authenticate, kHttpProxyAuthenticate
Proxy-Authorization, kHttpProxyAuthorization Proxy-Authorization, kHttpProxyAuthorization
Proxy-Connection, kHttpProxyConnection Proxy-Connection, kHttpProxyConnection
Range, kHttpRange Range, kHttpRange
Referer, kHttpReferer Referer, kHttpReferer
Transfer-Encoding, kHttpTransferEncoding Transfer-Encoding, kHttpTransferEncoding
Upgrade, kHttpUpgrade Upgrade, kHttpUpgrade
User-Agent, kHttpUserAgent User-Agent, kHttpUserAgent
Via, kHttpVia Via, kHttpVia
Location, kHttpLocation Location, kHttpLocation
Public, kHttpPublic Public, kHttpPublic
Retry-After, kHttpRetryAfter Retry-After, kHttpRetryAfter
Server, kHttpServer Server, kHttpServer
Vary, kHttpVary Vary, kHttpVary
Warning, kHttpWarning Warning, kHttpWarning
WWW-Authenticate, kHttpWwwAuthenticate WWW-Authenticate, kHttpWwwAuthenticate
Last-Modified, kHttpLastModified Last-Modified, kHttpLastModified

View File

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

View File

@ -17,15 +17,17 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA 02110-1301 USA
*/ */
#include "libc/alg/alg.h" #include "net/http/gethttpmethod.inc"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "net/http/http.h" #include "net/http/http.h"
void clearhttprequest(struct HttpRequest *req) { /**
req->uri.i = pushpop(0); * Returns small number for HTTP method, or -1 if not found.
req->method.i = pushpop(0); */
req->version.i = pushpop(0); int GetHttpMethod(const char *str, size_t len) {
req->scratch.i = pushpop(0); const struct HttpMethodSlot *slot;
critbit0_clear(&req->headers); 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_ #ifndef COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#define COSMOPOLITAN_LIBC_HTTP_HTTP_H_ #define COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#include "libc/alg/alg.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) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
struct FILE; struct HttpRequestSlice {
short a, b;
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 HttpRequest { struct HttpRequest {
struct HttpStr uri; /* /foo/bar.html, etc. */ int method;
struct HttpStr method; /* "GET", "POST", etc. */ struct HttpRequestSlice uri;
struct critbit0 headers; /* TreeMultiMap<"key:value"> (no space delims) */ struct HttpRequestSlice version;
struct HttpStr version; /* "HTTP/1.1", etc. */ struct HttpRequestSlice scratch;
struct HttpStr scratch; /* "HTTP/1.1", etc. */ struct HttpRequestSlice headers[kHttpHeadersMax];
}; };
int parsehttprequest(struct HttpRequest *, struct FILE *) paramsnonnull(); int GetHttpHeader(const char *, size_t);
void clearhttprequest(struct HttpRequest *) paramsnonnull(); int GetHttpMethod(const char *, size_t);
void freehttprequest(struct HttpRequest **) paramsnonnull(); int ParseHttpRequest(struct HttpRequest *, const char *, size_t);
int negotiatehttprequest(int, const char *, uint32_t *, char *, uint32_t *, int NegotiateHttpRequest(int, const char *, uint32_t *, char *, uint32_t *,
uint32_t *, bool, long double); uint32_t *, bool, long double);
COSMOPOLITAN_C_END_ 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 * @param singleshot should be true w/ connection: close
* @return 0 on success, or -1 w/ errno * @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, char *resp, uint32_t *inout_respsize,
uint32_t *out_resphdrsize, bool singleshot, uint32_t *out_resphdrsize, bool singleshot,
long double timeout) { long double timeout) {

View File

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

View File

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

View File

@ -19,6 +19,7 @@
*/ */
#include "dsp/core/core.h" #include "dsp/core/core.h"
#include "dsp/core/q.h" #include "dsp/core/q.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
@ -49,7 +50,8 @@ TEST(GetIntegerCoefficients8, testBt601Vectors) {
for (i = 0; i < ARRAYLEN(V); ++i) { for (i = 0; i < ARRAYLEN(V); ++i) {
GetIntegerCoefficients8(got, V[i].r, V[i].m, V[i].L, V[i].H); GetIntegerCoefficients8(got, V[i].r, V[i].m, V[i].L, V[i].H);
EXPECT_EQ(0, memcmp(V[i].n, got, sizeof(got)), 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], 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]); 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) $(APE)
@$(APELINK) @$(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 .PHONY: o/$(MODE)/test/dsp/core
o/$(MODE)/test/dsp/core: \ o/$(MODE)/test/dsp/core: \
$(TEST_DSP_CORE_BINS) \ $(TEST_DSP_CORE_BINS) \

View File

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

View File

@ -24,6 +24,10 @@ TEST(itoa64radix16, test) {
char buf[21]; char buf[21];
EXPECT_EQ(5, uint64toarray_radix16(0x31337, buf)); EXPECT_EQ(5, uint64toarray_radix16(0x31337, buf));
EXPECT_STREQ("31337", 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) { TEST(itoa64fixed16, test) {

View File

@ -416,12 +416,8 @@ TEST(sprintf, test_float) {
EXPECT_STREQ("42.90", Format("%.2f", 42.8952)); EXPECT_STREQ("42.90", Format("%.2f", 42.8952));
EXPECT_STREQ("42.895200000", Format("%.9f", 42.8952)); EXPECT_STREQ("42.895200000", Format("%.9f", 42.8952));
EXPECT_STREQ("42.8952230000", Format("%.10f", 42.895223)); EXPECT_STREQ("42.8952230000", Format("%.10f", 42.895223));
/* this testcase checks, that the precision is truncated to 9 digits. */ EXPECT_STREQ("42.89522312345678", Format("%.14f", 42.89522312345678));
/* a perfect working float should return the whole number */ EXPECT_STREQ("42.89522387654321", Format("%.14f", 42.89522387654321));
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.90", Format("%6.2f", 42.8952)); EXPECT_STREQ(" 42.90", Format("%6.2f", 42.8952));
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)); 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