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
This commit is contained in:
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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

27
libc/elf/iself64binary.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- 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/elf/elf.h"
bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) {
if (mapsize < sizeof(Elf64_Ehdr)) return false;
if (memcmp(elf->e_ident, ELFMAG, 4)) return false;
return (elf->e_ident[EI_CLASS] == ELFCLASSNONE ||
elf->e_ident[EI_CLASS] == ELFCLASS64);
}

View file

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

View file

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

View file

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

View file

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

45
libc/intrin/mpsadbw.c Normal file
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);
}

41
libc/intrin/mpsadbw.h Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

45
libc/runtime/destruct.S Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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