mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-03 16:30:29 +00:00
Merge branch 'master' of https://github.com/jart/cosmopolitan into FEATURE/ioctl_SIOCGIFCONF
This commit is contained in:
commit
c0829f4637
36 changed files with 847 additions and 388 deletions
22
Makefile
22
Makefile
|
@ -189,13 +189,13 @@ include examples/package/build.mk
|
|||
#-φ-examples/package/new.sh
|
||||
include test/test.mk
|
||||
|
||||
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
||||
SRCS = $(foreach x,$(PKGS),$($(x)_SRCS))
|
||||
HDRS = $(foreach x,$(PKGS),$($(x)_HDRS))
|
||||
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
||||
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
||||
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
||||
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
||||
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
||||
SRCS := $(foreach x,$(PKGS),$($(x)_SRCS))
|
||||
HDRS := $(foreach x,$(PKGS),$($(x)_HDRS))
|
||||
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
||||
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
||||
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
||||
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
||||
|
||||
bins: $(BINS)
|
||||
check: $(CHECKS)
|
||||
|
@ -206,11 +206,17 @@ tags: TAGS HTAGS
|
|||
o/$(MODE)/.x:
|
||||
@mkdir -p $(@D) && touch $@
|
||||
|
||||
ifneq ($(findstring 4.,,$(MAKE_VERSION)),$(MAKE_VERSION))
|
||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||
|
||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
else
|
||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^SRCS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^HDRS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
||||
endif
|
||||
|
||||
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) $(INCS)
|
||||
@$(COMPILE) -AMKDEPS $(MKDEPS) -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt
|
||||
|
|
|
@ -73,3 +73,4 @@ find o -name \*.com | xargs ls -rShal | less
|
|||
| FreeBSD | 12 | 2018 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| NetBSD | 9.1 | 2020 |
|
||||
| GNU Make | 3.80 | 2010 |
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
*
|
||||
* Be sure to check for EINTR on your i/o calls, for best low latency.
|
||||
*
|
||||
* Timers are not inherited across fork.
|
||||
*
|
||||
* @param which can be ITIMER_REAL, ITIMER_VIRTUAL, etc.
|
||||
* @param newvalue specifies the interval ({0,0} means one-shot) and
|
||||
* duration ({0,0} means disarm) in microseconds ∈ [0,999999] and
|
||||
|
|
164
libc/fmt/kerrornames.S
Normal file
164
libc/fmt/kerrornames.S
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e
|
||||
.long \e - kErrorNames
|
||||
.long 1f - kErrorNames
|
||||
.section .rodata.str1.1
|
||||
1: .string "\e"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
kErrorNames:
|
||||
.e ENOSYS
|
||||
.e EPERM
|
||||
.e ENOENT
|
||||
.e ESRCH
|
||||
.e EINTR
|
||||
.e EIO
|
||||
.e ENXIO
|
||||
.e E2BIG
|
||||
.e ENOEXEC
|
||||
.e EBADF
|
||||
.e ECHILD
|
||||
.e EAGAIN
|
||||
.e ENOMEM
|
||||
.e EACCES
|
||||
.e EFAULT
|
||||
.e ENOTBLK
|
||||
.e EBUSY
|
||||
.e EEXIST
|
||||
.e EXDEV
|
||||
.e ENODEV
|
||||
.e ENOTDIR
|
||||
.e EISDIR
|
||||
.e EINVAL
|
||||
.e ENFILE
|
||||
.e EMFILE
|
||||
.e ENOTTY
|
||||
.e ETXTBSY
|
||||
.e EFBIG
|
||||
.e ENOSPC
|
||||
.e EDQUOT
|
||||
.e ESPIPE
|
||||
.e EROFS
|
||||
.e EMLINK
|
||||
.e EPIPE
|
||||
.e EDOM
|
||||
.e ERANGE
|
||||
.e EDEADLK
|
||||
.e ENAMETOOLONG
|
||||
.e ENOLCK
|
||||
.e ENOTEMPTY
|
||||
.e ELOOP
|
||||
.e ENOMSG
|
||||
.e EIDRM
|
||||
.e ETIME
|
||||
.e EPROTO
|
||||
.e EOVERFLOW
|
||||
.e EILSEQ
|
||||
.e EUSERS
|
||||
.e ENOTSOCK
|
||||
.e EDESTADDRREQ
|
||||
.e EMSGSIZE
|
||||
.e EPROTOTYPE
|
||||
.e ENOPROTOOPT
|
||||
.e EPROTONOSUPPORT
|
||||
.e ESOCKTNOSUPPORT
|
||||
.e ENOTSUP
|
||||
.e EOPNOTSUPP
|
||||
.e EPFNOSUPPORT
|
||||
.e EAFNOSUPPORT
|
||||
.e EADDRINUSE
|
||||
.e EADDRNOTAVAIL
|
||||
.e ENETDOWN
|
||||
.e ENETUNREACH
|
||||
.e ENETRESET
|
||||
.e ECONNABORTED
|
||||
.e ECONNRESET
|
||||
.e ENOBUFS
|
||||
.e EISCONN
|
||||
.e ENOTCONN
|
||||
.e ESHUTDOWN
|
||||
.e ETOOMANYREFS
|
||||
.e ETIMEDOUT
|
||||
.e ECONNREFUSED
|
||||
.e EHOSTDOWN
|
||||
.e EHOSTUNREACH
|
||||
.e EALREADY
|
||||
.e EINPROGRESS
|
||||
.e ESTALE
|
||||
.e EREMOTE
|
||||
.e EBADMSG
|
||||
.e ECANCELED
|
||||
.e EOWNERDEAD
|
||||
.e ENOTRECOVERABLE
|
||||
.e ENONET
|
||||
.e ERESTART
|
||||
.e ECHRNG
|
||||
.e EL2NSYNC
|
||||
.e EL3HLT
|
||||
.e EL3RST
|
||||
.e ELNRNG
|
||||
.e EUNATCH
|
||||
.e ENOCSI
|
||||
.e EL2HLT
|
||||
.e EBADE
|
||||
.e EBADR
|
||||
.e EXFULL
|
||||
.e ENOANO
|
||||
.e EBADRQC
|
||||
.e EBADSLT
|
||||
.e ENOSTR
|
||||
.e ENODATA
|
||||
.e ENOSR
|
||||
.e ENOPKG
|
||||
.e ENOLINK
|
||||
.e EADV
|
||||
.e ESRMNT
|
||||
.e ECOMM
|
||||
.e EMULTIHOP
|
||||
.e EDOTDOT
|
||||
.e ENOTUNIQ
|
||||
.e EBADFD
|
||||
.e EREMCHG
|
||||
.e ELIBACC
|
||||
.e ELIBBAD
|
||||
.e ELIBSCN
|
||||
.e ELIBMAX
|
||||
.e ELIBEXEC
|
||||
.e ESTRPIPE
|
||||
.e EUCLEAN
|
||||
.e ENOTNAM
|
||||
.e ENAVAIL
|
||||
.e EISNAM
|
||||
.e EREMOTEIO
|
||||
.e ENOMEDIUM
|
||||
.e EMEDIUMTYPE
|
||||
.e ENOKEY
|
||||
.e EKEYEXPIRED
|
||||
.e EKEYREVOKED
|
||||
.e EKEYREJECTED
|
||||
.e ERFKILL
|
||||
.e EHWPOISON
|
||||
.long 0
|
||||
.endobj kErrorNames,globl,hidden
|
|
@ -18,20 +18,20 @@
|
|||
* format strings are constexprs that only contain directives.
|
||||
*/
|
||||
|
||||
#define PFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "faAeEgG")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
#define PFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "faAeg")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
})
|
||||
|
||||
#define SFLINK(FMT) \
|
||||
|
|
|
@ -27,149 +27,17 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
const struct Error {
|
||||
const long *x;
|
||||
const char *s;
|
||||
} kErrors[] = {
|
||||
{&ENOSYS, "ENOSYS"},
|
||||
{&EPERM, "EPERM"},
|
||||
{&ENOENT, "ENOENT"},
|
||||
{&ESRCH, "ESRCH"},
|
||||
{&EINTR, "EINTR"},
|
||||
{&EIO, "EIO"},
|
||||
{&ENXIO, "ENXIO"},
|
||||
{&E2BIG, "E2BIG"},
|
||||
{&ENOEXEC, "ENOEXEC"},
|
||||
{&EBADF, "EBADF"},
|
||||
{&ECHILD, "ECHILD"},
|
||||
{&EAGAIN, "EAGAIN"},
|
||||
{&ENOMEM, "ENOMEM"},
|
||||
{&EACCES, "EACCES"},
|
||||
{&EFAULT, "EFAULT"},
|
||||
{&ENOTBLK, "ENOTBLK"},
|
||||
{&EBUSY, "EBUSY"},
|
||||
{&EEXIST, "EEXIST"},
|
||||
{&EXDEV, "EXDEV"},
|
||||
{&ENODEV, "ENODEV"},
|
||||
{&ENOTDIR, "ENOTDIR"},
|
||||
{&EISDIR, "EISDIR"},
|
||||
{&EINVAL, "EINVAL"},
|
||||
{&ENFILE, "ENFILE"},
|
||||
{&EMFILE, "EMFILE"},
|
||||
{&ENOTTY, "ENOTTY"},
|
||||
{&ETXTBSY, "ETXTBSY"},
|
||||
{&EFBIG, "EFBIG"},
|
||||
{&ENOSPC, "ENOSPC"},
|
||||
{&EDQUOT, "EDQUOT"},
|
||||
{&ESPIPE, "ESPIPE"},
|
||||
{&EROFS, "EROFS"},
|
||||
{&EMLINK, "EMLINK"},
|
||||
{&EPIPE, "EPIPE"},
|
||||
{&EDOM, "EDOM"},
|
||||
{&ERANGE, "ERANGE"},
|
||||
{&EDEADLK, "EDEADLK"},
|
||||
{&ENAMETOOLONG, "ENAMETOOLONG"},
|
||||
{&ENOLCK, "ENOLCK"},
|
||||
{&ENOTEMPTY, "ENOTEMPTY"},
|
||||
{&ELOOP, "ELOOP"},
|
||||
{&ENOMSG, "ENOMSG"},
|
||||
{&EIDRM, "EIDRM"},
|
||||
{&ETIME, "ETIME"},
|
||||
{&EPROTO, "EPROTO"},
|
||||
{&EOVERFLOW, "EOVERFLOW"},
|
||||
{&EILSEQ, "EILSEQ"},
|
||||
{&EUSERS, "EUSERS"},
|
||||
{&ENOTSOCK, "ENOTSOCK"},
|
||||
{&EDESTADDRREQ, "EDESTADDRREQ"},
|
||||
{&EMSGSIZE, "EMSGSIZE"},
|
||||
{&EPROTOTYPE, "EPROTOTYPE"},
|
||||
{&ENOPROTOOPT, "ENOPROTOOPT"},
|
||||
{&EPROTONOSUPPORT, "EPROTONOSUPPORT"},
|
||||
{&ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"},
|
||||
{&ENOTSUP, "ENOTSUP"},
|
||||
{&EOPNOTSUPP, "EOPNOTSUPP"},
|
||||
{&EPFNOSUPPORT, "EPFNOSUPPORT"},
|
||||
{&EAFNOSUPPORT, "EAFNOSUPPORT"},
|
||||
{&EADDRINUSE, "EADDRINUSE"},
|
||||
{&EADDRNOTAVAIL, "EADDRNOTAVAIL"},
|
||||
{&ENETDOWN, "ENETDOWN"},
|
||||
{&ENETUNREACH, "ENETUNREACH"},
|
||||
{&ENETRESET, "ENETRESET"},
|
||||
{&ECONNABORTED, "ECONNABORTED"},
|
||||
{&ECONNRESET, "ECONNRESET"},
|
||||
{&ENOBUFS, "ENOBUFS"},
|
||||
{&EISCONN, "EISCONN"},
|
||||
{&ENOTCONN, "ENOTCONN"},
|
||||
{&ESHUTDOWN, "ESHUTDOWN"},
|
||||
{&ETOOMANYREFS, "ETOOMANYREFS"},
|
||||
{&ETIMEDOUT, "ETIMEDOUT"},
|
||||
{&ECONNREFUSED, "ECONNREFUSED"},
|
||||
{&EHOSTDOWN, "EHOSTDOWN"},
|
||||
{&EHOSTUNREACH, "EHOSTUNREACH"},
|
||||
{&EALREADY, "EALREADY"},
|
||||
{&EINPROGRESS, "EINPROGRESS"},
|
||||
{&ESTALE, "ESTALE"},
|
||||
{&EREMOTE, "EREMOTE"},
|
||||
{&EBADMSG, "EBADMSG"},
|
||||
{&ECANCELED, "ECANCELED"},
|
||||
{&EOWNERDEAD, "EOWNERDEAD"},
|
||||
{&ENOTRECOVERABLE, "ENOTRECOVERABLE"},
|
||||
{&ENONET, "ENONET"},
|
||||
{&ERESTART, "ERESTART"},
|
||||
{&ECHRNG, "ECHRNG"},
|
||||
{&EL2NSYNC, "EL2NSYNC"},
|
||||
{&EL3HLT, "EL3HLT"},
|
||||
{&EL3RST, "EL3RST"},
|
||||
{&ELNRNG, "ELNRNG"},
|
||||
{&EUNATCH, "EUNATCH"},
|
||||
{&ENOCSI, "ENOCSI"},
|
||||
{&EL2HLT, "EL2HLT"},
|
||||
{&EBADE, "EBADE"},
|
||||
{&EBADR, "EBADR"},
|
||||
{&EXFULL, "EXFULL"},
|
||||
{&ENOANO, "ENOANO"},
|
||||
{&EBADRQC, "EBADRQC"},
|
||||
{&EBADSLT, "EBADSLT"},
|
||||
{&ENOSTR, "ENOSTR"},
|
||||
{&ENODATA, "ENODATA"},
|
||||
{&ENOSR, "ENOSR"},
|
||||
{&ENOPKG, "ENOPKG"},
|
||||
{&ENOLINK, "ENOLINK"},
|
||||
{&EADV, "EADV"},
|
||||
{&ESRMNT, "ESRMNT"},
|
||||
{&ECOMM, "ECOMM"},
|
||||
{&EMULTIHOP, "EMULTIHOP"},
|
||||
{&EDOTDOT, "EDOTDOT"},
|
||||
{&ENOTUNIQ, "ENOTUNIQ"},
|
||||
{&EBADFD, "EBADFD"},
|
||||
{&EREMCHG, "EREMCHG"},
|
||||
{&ELIBACC, "ELIBACC"},
|
||||
{&ELIBBAD, "ELIBBAD"},
|
||||
{&ELIBSCN, "ELIBSCN"},
|
||||
{&ELIBMAX, "ELIBMAX"},
|
||||
{&ELIBEXEC, "ELIBEXEC"},
|
||||
{&ESTRPIPE, "ESTRPIPE"},
|
||||
{&EUCLEAN, "EUCLEAN"},
|
||||
{&ENOTNAM, "ENOTNAM"},
|
||||
{&ENAVAIL, "ENAVAIL"},
|
||||
{&EISNAM, "EISNAM"},
|
||||
{&EREMOTEIO, "EREMOTEIO"},
|
||||
{&ENOMEDIUM, "ENOMEDIUM"},
|
||||
{&EMEDIUMTYPE, "EMEDIUMTYPE"},
|
||||
{&ENOKEY, "ENOKEY"},
|
||||
{&EKEYEXPIRED, "EKEYEXPIRED"},
|
||||
{&EKEYREVOKED, "EKEYREVOKED"},
|
||||
{&EKEYREJECTED, "EKEYREJECTED"},
|
||||
{&ERFKILL, "ERFKILL"},
|
||||
{&EHWPOISON, "EHWPOISON"},
|
||||
};
|
||||
extern const struct Error {
|
||||
int x;
|
||||
int s;
|
||||
} kErrorNames[];
|
||||
|
||||
static const char *geterrname(long x) {
|
||||
static const char *GetErrorName(long x) {
|
||||
int i;
|
||||
if (x) {
|
||||
for (i = 0; i < ARRAYLEN(kErrors); ++i) {
|
||||
if (x == *kErrors[i].x) {
|
||||
return kErrors[i].s;
|
||||
for (i = 0; kErrorNames[i].x; ++i) {
|
||||
if (x == *(const long *)((uintptr_t)kErrorNames + kErrorNames[i].x)) {
|
||||
return (const char *)((uintptr_t)kErrorNames + kErrorNames[i].s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +52,7 @@ int strerror_r(int err, char *buf, size_t size) {
|
|||
char *p;
|
||||
const char *s;
|
||||
err &= 0xFFFF;
|
||||
s = geterrname(err);
|
||||
s = GetErrorName(err);
|
||||
p = buf;
|
||||
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
|
||||
p = stpcpy(p, s);
|
||||
|
|
|
@ -40,9 +40,7 @@ OpenExecutable:
|
|||
pushq MAP_ANONYMOUS(%rip) # -0x28(%rbp)
|
||||
pushq MAP_PRIVATE(%rip) # -0x30(%rbp)
|
||||
pushq MAP_FIXED(%rip) # -0x38(%rbp)
|
||||
pushq MAP_SHARED(%rip) # -0x40(%rbp)
|
||||
pushq __NR_mprotect(%rip) # -0x48(%rbp)
|
||||
pushq __NR_mprotect(%rip) # -0x50(%rbp)
|
||||
pushq __NR_mprotect(%rip) # -0x40(%rbp)
|
||||
push %rbx # code buffer
|
||||
push %r12 # data buffer
|
||||
push %r14 # filename
|
||||
|
@ -98,7 +96,7 @@ OpenExecutable:
|
|||
rep movsb
|
||||
|
||||
// Change protection.
|
||||
mov -0x48(%rbp),%eax # __NR_mprotect
|
||||
mov -0x40(%rbp),%eax # __NR_mprotect
|
||||
mov %rbx,%rdi
|
||||
mov $PAGESIZE,%esi
|
||||
mov $PROT_READ|PROT_EXEC,%edx
|
||||
|
@ -133,7 +131,7 @@ OpenExecutable:
|
|||
mov $ape_rom_filesz,%esi
|
||||
mov $PROT_READ|PROT_EXEC,%edx
|
||||
mov -0x38(%rbp),%r10d # MAP_FIXED
|
||||
or -0x40(%rbp),%r10d # MAP_SHARED
|
||||
or -0x30(%rbp),%r10d # MAP_PRIVATE
|
||||
mov %r15d,%r8d
|
||||
mov $ape_rom_offset,%r9d
|
||||
push %r9 # openbsd:pad
|
||||
|
|
|
@ -24,6 +24,7 @@ _peekall:
|
|||
.leafprologue
|
||||
ezlea _base,si
|
||||
ezlea _end,cx
|
||||
add $0x1000,%rsi
|
||||
0: mov (%rsi),%eax
|
||||
add $PAGESIZE,%rsi
|
||||
cmp %rcx,%rsi
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
* allocated automatically, also NUL-terminated is guaranteed
|
||||
* @param n is the capacity of s (in/out)
|
||||
* @param delim is the stop char (and NUL is implicitly too)
|
||||
* @return number of bytes read, including delim, excluding NUL, or -1
|
||||
* w/ errno on EOF or error; see ferror() and feof()
|
||||
* @return number of bytes read >0, including delim, excluding NUL,
|
||||
* or -1 w/ errno on EOF or error; see ferror() and feof()
|
||||
* @note this function can't punt EINTR to caller
|
||||
* @see getline(), gettok_r()
|
||||
* @see getline(), chomp(), gettok_r()
|
||||
*/
|
||||
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
|
||||
char *p;
|
||||
|
|
|
@ -17,16 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
noasan static const unsigned char *strchr_x64(const unsigned char *p,
|
||||
uint64_t c) {
|
||||
noasan static const char *strchr_x64(const char *p, uint64_t c) {
|
||||
unsigned a, b;
|
||||
uint64_t w, x, y;
|
||||
for (c *= 0x0101010101010101;; p += 8) {
|
||||
w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
||||
(uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 |
|
||||
(uint64_t)p[1] << 010 | (uint64_t)p[0] << 000;
|
||||
w = READ64LE(p);
|
||||
if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) |
|
||||
(y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
|
||||
if (x) {
|
||||
|
@ -63,7 +61,7 @@ char *strchr(const char *s, int c) {
|
|||
if ((*s & 0xff) == c) return s;
|
||||
if (!*s) return NULL;
|
||||
}
|
||||
r = (char *)strchr_x64((const unsigned char *)s, c);
|
||||
r = strchr_x64(s, c);
|
||||
assert(!r || *r || !c);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
@ -29,6 +30,8 @@
|
|||
*/
|
||||
char *strstr(const char *haystack, const char *needle) {
|
||||
size_t i;
|
||||
if (!*needle) return haystack;
|
||||
haystack = firstnonnull(strchr(haystack, *needle), haystack);
|
||||
for (;;) {
|
||||
for (i = 0;;) {
|
||||
if (!needle[i]) return (/*unconst*/ char *)haystack;
|
||||
|
|
|
@ -49,6 +49,9 @@ static noasan axdx_t tprecode16to8_sse2(char *dst, size_t dstsize,
|
|||
/**
|
||||
* Transcodes UTF-16 to UTF-8.
|
||||
*
|
||||
* This is a low-level function intended for the core runtime. Use
|
||||
* utf16toutf8() for a much better API that uses malloc().
|
||||
*
|
||||
* @param dst is output buffer
|
||||
* @param dstsize is bytes in dst
|
||||
* @param src is NUL-terminated UTF-16 input string
|
||||
|
|
|
@ -46,6 +46,9 @@ static inline noasan axdx_t tprecode8to16_sse2(char16_t *dst, size_t dstsize,
|
|||
/**
|
||||
* Transcodes UTF-8 to UTF-16.
|
||||
*
|
||||
* This is a low-level function intended for the core runtime. Use
|
||||
* utf8toutf16() for a much better API that uses malloc().
|
||||
*
|
||||
* @param dst is output buffer
|
||||
* @param dstsize is shorts in dst
|
||||
* @param src is NUL-terminated UTF-8 input string
|
||||
|
|
|
@ -74,6 +74,7 @@ COSMOPOLITAN_C_START_
|
|||
* and if the test succeeds it'll be removed along with any contents.
|
||||
*/
|
||||
extern char testlib_enable_tmp_setup_teardown;
|
||||
extern char testlib_enable_tmp_setup_teardown_once;
|
||||
|
||||
/**
|
||||
* User-defined test setup function.
|
||||
|
@ -82,6 +83,7 @@ extern char testlib_enable_tmp_setup_teardown;
|
|||
* defined by the linkage.
|
||||
*/
|
||||
void SetUp(void);
|
||||
void SetUpOnce(void);
|
||||
|
||||
/**
|
||||
* User-defined test cleanup function.
|
||||
|
@ -90,6 +92,7 @@ void SetUp(void);
|
|||
* defined by the linkage.
|
||||
*/
|
||||
void TearDown(void);
|
||||
void TearDownOnce(void);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § testing library » assert or die ─╬─│┼
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
static int x;
|
||||
static char cwd[PATH_MAX];
|
||||
static char tmp[PATH_MAX];
|
||||
|
||||
void testlib_finish(void) {
|
||||
if (g_testlib_failed) {
|
||||
fprintf(stderr, "%u / %u %s\n", g_testlib_failed, g_testlib_ran,
|
||||
|
@ -42,6 +46,18 @@ wontreturn void testlib_abort(void) {
|
|||
unreachable;
|
||||
}
|
||||
|
||||
static void SetupTmpDir(void) {
|
||||
snprintf(tmp, sizeof(tmp), "o/tmp/%s.%d.%d", program_invocation_short_name,
|
||||
getpid(), x++);
|
||||
CHECK_NE(-1, makedirs(tmp, 0755), "tmp=%s", tmp);
|
||||
CHECK_NE(-1, chdir(tmp), "tmp=%s", tmp);
|
||||
}
|
||||
|
||||
static void TearDownTmpDir(void) {
|
||||
CHECK_NE(-1, chdir(cwd));
|
||||
CHECK_NE(-1, rmrf(tmp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all test case functions in sorted order.
|
||||
*/
|
||||
|
@ -62,18 +78,12 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
|||
*
|
||||
* @see ape/ape.lds
|
||||
*/
|
||||
int x;
|
||||
char cwd[PATH_MAX];
|
||||
char tmp[PATH_MAX];
|
||||
const testfn_t *fn;
|
||||
CHECK_NOTNULL(getcwd(cwd, sizeof(cwd)));
|
||||
if (weaken(testlib_enable_tmp_setup_teardown_once)) SetupTmpDir();
|
||||
if (weaken(SetUpOnce)) weaken(SetUpOnce)();
|
||||
for (x = 0, fn = start; fn != end; ++fn) {
|
||||
if (weaken(testlib_enable_tmp_setup_teardown)) {
|
||||
CHECK_NOTNULL(getcwd(cwd, sizeof(cwd)));
|
||||
snprintf(tmp, sizeof(tmp), "o/tmp/%s.%d.%d",
|
||||
program_invocation_short_name, getpid(), x++);
|
||||
CHECK_NE(-1, makedirs(tmp, 0755), "tmp=%s", tmp);
|
||||
CHECK_NE(-1, chdir(tmp), "tmp=%s", tmp);
|
||||
}
|
||||
if (weaken(testlib_enable_tmp_setup_teardown)) SetupTmpDir();
|
||||
if (weaken(SetUp)) weaken(SetUp)();
|
||||
errno = 0;
|
||||
SetLastError(0);
|
||||
|
@ -83,9 +93,8 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
|||
(*fn)();
|
||||
sys_getpid();
|
||||
if (weaken(TearDown)) weaken(TearDown)();
|
||||
if (weaken(testlib_enable_tmp_setup_teardown)) {
|
||||
CHECK_NE(-1, chdir(cwd));
|
||||
CHECK_NE(-1, rmrf(tmp));
|
||||
}
|
||||
if (weaken(testlib_enable_tmp_setup_teardown)) TearDownTmpDir();
|
||||
}
|
||||
if (weaken(TearDownOnce)) weaken(TearDownOnce)();
|
||||
if (weaken(testlib_enable_tmp_setup_teardown_once)) TearDownTmpDir();
|
||||
}
|
||||
|
|
91
libc/x/utf16toutf8.c
Normal file
91
libc/x/utf16toutf8.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/intrin/packsswb.h"
|
||||
#include "libc/intrin/pandn.h"
|
||||
#include "libc/intrin/pcmpgtb.h"
|
||||
#include "libc/intrin/pcmpgtw.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/intrin/punpckhbw.h"
|
||||
#include "libc/intrin/punpcklbw.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
static const int16_t kDel16[8] = {127, 127, 127, 127, 127, 127, 127, 127};
|
||||
|
||||
/**
|
||||
* Transcodes UTF-16 to UTF-8.
|
||||
*
|
||||
* @param p is input value
|
||||
* @param n if -1 implies strlen
|
||||
* @param z if non-NULL receives output length
|
||||
*/
|
||||
char *utf16toutf8(const char16_t *p, size_t n, size_t *z) {
|
||||
char *r, *q;
|
||||
wint_t x, y;
|
||||
unsigned m, j, w;
|
||||
const char16_t *e;
|
||||
int16_t v1[8], v2[8], v3[8], vz[8];
|
||||
if (z) *z = 0;
|
||||
if (n == -1) n = p ? strlen16(p) : 0;
|
||||
if ((q = r = malloc(n * 4 + 8 + 1))) {
|
||||
for (e = p + n; p < e;) {
|
||||
if (p + 8 < e) { /* 17x ascii */
|
||||
memset(vz, 0, 16);
|
||||
do {
|
||||
memcpy(v1, p, 16);
|
||||
pcmpgtw(v2, v1, vz);
|
||||
pcmpgtw(v3, v1, kDel16);
|
||||
pandn((void *)v2, (void *)v3, (void *)v2);
|
||||
if (pmovmskb((void *)v2) != 0xFFFF) break;
|
||||
packsswb((void *)v1, v1, v1);
|
||||
memcpy(q, v1, 8);
|
||||
p += 8;
|
||||
q += 8;
|
||||
} while (p + 8 < e);
|
||||
}
|
||||
x = *p++ & 0xffff;
|
||||
if (!IsUcs2(x)) {
|
||||
if (p < e) {
|
||||
y = *p++ & 0xffff;
|
||||
x = MergeUtf16(x, y);
|
||||
} else {
|
||||
x = 0xFFFD;
|
||||
}
|
||||
}
|
||||
if (x < 0200) {
|
||||
*q++ = x;
|
||||
} else {
|
||||
w = tpenc(x);
|
||||
WRITE64LE(q, w);
|
||||
q += bsr(w) >> 3;
|
||||
q += 1;
|
||||
}
|
||||
}
|
||||
if (z) *z = q - r;
|
||||
*q++ = '\0';
|
||||
if ((q = realloc(r, (q - r) * 1))) r = q;
|
||||
}
|
||||
return r;
|
||||
}
|
86
libc/x/utf8toutf16.c
Normal file
86
libc/x/utf8toutf16.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pcmpgtb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/intrin/punpckhbw.h"
|
||||
#include "libc/intrin/punpcklbw.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Transcodes UTF-8 to UTF-16.
|
||||
*
|
||||
* @param p is input value
|
||||
* @param n if -1 implies strlen
|
||||
* @param z if non-NULL receives output length
|
||||
*/
|
||||
char16_t *utf8toutf16(const char *p, size_t n, size_t *z) {
|
||||
size_t i;
|
||||
wint_t x, a, b;
|
||||
char16_t *r, *q;
|
||||
unsigned m, j, w;
|
||||
uint8_t v1[16], v2[16], vz[16];
|
||||
if (z) *z = 0;
|
||||
if (n == -1) n = p ? strlen(p) : 0;
|
||||
if ((q = r = malloc(n * sizeof(char16_t) * 2 + sizeof(char16_t)))) {
|
||||
for (i = 0; i < n;) {
|
||||
if (i + 16 < n) { /* 34x ascii */
|
||||
memset(vz, 0, 16);
|
||||
do {
|
||||
memcpy(v1, p + i, 16);
|
||||
pcmpgtb((int8_t *)v2, (int8_t *)v1, (int8_t *)vz);
|
||||
if (pmovmskb(v2) != 0xFFFF) break;
|
||||
punpcklbw(v2, v1, vz);
|
||||
punpckhbw(v1, v1, vz);
|
||||
memcpy(q + 0, v2, 16);
|
||||
memcpy(q + 8, v1, 16);
|
||||
i += 16;
|
||||
q += 16;
|
||||
} while (i + 16 < n);
|
||||
}
|
||||
x = p[i++] & 0xff;
|
||||
if (x >= 0300) {
|
||||
a = ThomPikeByte(x);
|
||||
m = ThomPikeLen(x) - 1;
|
||||
if (i + m <= n) {
|
||||
for (j = 0;;) {
|
||||
b = p[i + j] & 0xff;
|
||||
if (!ThomPikeCont(b)) break;
|
||||
a = ThomPikeMerge(a, b);
|
||||
if (++j == m) {
|
||||
x = a;
|
||||
i += j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
w = EncodeUtf16(x);
|
||||
*q++ = w;
|
||||
if ((w >>= 16)) *q++ = w;
|
||||
}
|
||||
if (z) *z = q - r;
|
||||
*q++ = '\0';
|
||||
if ((q = realloc(r, (q - r) * sizeof(char16_t)))) r = q;
|
||||
}
|
||||
return r;
|
||||
}
|
|
@ -51,6 +51,8 @@ char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL;
|
|||
char *xinet_ntop(int, const void *) _XPNN _XMAL;
|
||||
void *xunbinga(size_t, const char16_t *) attributeallocalign((1)) _XMAL _XRET;
|
||||
void *xunbing(const char16_t *) _XMAL _XRET;
|
||||
char16_t *utf8toutf16(const char *, size_t, size_t *) nodiscard;
|
||||
char *utf16toutf8(const char16_t *, size_t, size_t *) nodiscard;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § eXtended apis » files ─╬─│┼
|
||||
|
|
|
@ -25,16 +25,18 @@
|
|||
*
|
||||
* @return allocated line that needs free() and usually chomp() too,
|
||||
* or NULL on ferror() or feof()
|
||||
* @see getline() for a more difficult api
|
||||
* @see getdelim() for a more difficult api
|
||||
* @see chomp()
|
||||
*/
|
||||
char *xgetline(FILE *f) {
|
||||
char *res;
|
||||
size_t n, got;
|
||||
char *p;
|
||||
size_t n;
|
||||
ssize_t m;
|
||||
n = 0;
|
||||
res = NULL;
|
||||
if ((got = getdelim(&res, &n, '\n', f)) <= 0) {
|
||||
free(res);
|
||||
res = NULL;
|
||||
p = 0;
|
||||
if ((m = getdelim(&p, &n, '\n', f)) <= 0) {
|
||||
free(p);
|
||||
p = 0;
|
||||
}
|
||||
return res;
|
||||
return p;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* @param p is input value
|
||||
* @param n if -1 implies strlen
|
||||
* @param z if non-NULL receives output length
|
||||
* @param f can kControlC0, kControlC1 to forbid
|
||||
* @param f can kControlC0, kControlC1, kControlWs to forbid
|
||||
* @return allocated NUL-terminated buffer, or NULL w/ errno
|
||||
* @error EILSEQ means UTF-8 found we can't or won't re-encode
|
||||
* @error ENOMEM means malloc() failed
|
||||
|
@ -38,7 +38,12 @@
|
|||
char *EncodeLatin1(const char *p, size_t n, size_t *z, int f) {
|
||||
int c;
|
||||
size_t i;
|
||||
char t[256];
|
||||
char *r, *q;
|
||||
memset(t, 0, sizeof(t));
|
||||
if (f & kControlC0) memset(t + 0x00, 1, 0x20 - 0x00), t[0x7F] = 1;
|
||||
if (f & kControlC1) memset(t + 0x80, 1, 0xA0 - 0x80);
|
||||
t['\t'] = t['\r'] = t['\n'] = t['\v'] = !!(f & kControlWs);
|
||||
if (z) *z = 0;
|
||||
if (n == -1) n = p ? strlen(p) : 0;
|
||||
if ((q = r = malloc(n + 1))) {
|
||||
|
@ -51,11 +56,7 @@ char *EncodeLatin1(const char *p, size_t n, size_t *z, int f) {
|
|||
goto Invalid;
|
||||
}
|
||||
}
|
||||
if (((f & kControlC1) && 0x80 <= c && c < 0xA0) ||
|
||||
((f & kControlC0) && (c < 32 || c == 0x7F) &&
|
||||
!(c == '\t' || c == '\r' || c == '\n' || c == '\v')) ||
|
||||
((f & kControlWs) &&
|
||||
(c == '\t' || c == '\r' || c == '\n' || c == '\v'))) {
|
||||
if (t[c]) {
|
||||
goto Invalid;
|
||||
}
|
||||
*q++ = c;
|
||||
|
|
|
@ -28,7 +28,7 @@ char *EscapeFragment(const char *, size_t, size_t *);
|
|||
char *EscapeSegment(const char *, size_t, size_t *);
|
||||
char *EscapeJsStringLiteral(const char *, size_t, size_t *);
|
||||
|
||||
bool HasControlCodes(const char *, size_t, int);
|
||||
ssize_t HasControlCodes(const char *, size_t, int);
|
||||
char *Underlong(const char *, size_t, size_t *);
|
||||
char *DecodeLatin1(const char *, size_t, size_t *);
|
||||
char *EncodeLatin1(const char *, size_t, size_t *, int);
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include "libc/macros.internal.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
static const struct HttpReason {
|
||||
int code;
|
||||
static const struct thatispacked HttpReason {
|
||||
short code;
|
||||
const char *name;
|
||||
} kHttpReason[] = {
|
||||
{100, "Continue"},
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pcmpgtb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "net/http/escape.h"
|
||||
|
@ -31,17 +27,22 @@
|
|||
* @param p is input value
|
||||
* @param n if -1 implies strlen
|
||||
* @param f can have kControlWs, kControlC0, kControlC1 to forbid
|
||||
* @return true if forbidden characters were found
|
||||
* @return index of first forbidden character or -1
|
||||
* @see VisualizeControlCodes()
|
||||
*/
|
||||
bool HasControlCodes(const char *p, size_t n, int f) {
|
||||
int c;
|
||||
ssize_t HasControlCodes(const char *p, size_t n, int f) {
|
||||
char t[256];
|
||||
wint_t x, a, b;
|
||||
size_t i, j, m;
|
||||
size_t i, j, m, g;
|
||||
memset(t, 0, sizeof(t));
|
||||
if (f & kControlC0) memset(t + 0x00, 1, 0x20 - 0x00), t[0x7F] = 1;
|
||||
if (f & kControlC1) memset(t + 0x80, 1, 0xA0 - 0x80);
|
||||
t['\t'] = t['\r'] = t['\n'] = t['\v'] = !!(f & kControlWs);
|
||||
if (n == -1) n = p ? strlen(p) : 0;
|
||||
for (i = 0; i < n;) {
|
||||
g = i;
|
||||
x = p[i++] & 0xff;
|
||||
if (x >= 0300) {
|
||||
if (UNLIKELY(x >= 0300)) {
|
||||
a = ThomPikeByte(x);
|
||||
m = ThomPikeLen(x) - 1;
|
||||
if (i + m <= n) {
|
||||
|
@ -57,13 +58,9 @@ bool HasControlCodes(const char *p, size_t n, int f) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (((f & kControlC1) && 0x80 <= x && x < 0xA0) ||
|
||||
((f & kControlC0) && (x < 32 || x == 0x7F) &&
|
||||
!(x == '\t' || x == '\r' || x == '\n' || x == '\v')) ||
|
||||
((f & kControlWs) &&
|
||||
(x == '\t' || x == '\r' || x == '\n' || x == '\v'))) {
|
||||
return true;
|
||||
if (x < 256 && t[x]) {
|
||||
return g;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "net/http/http.h"
|
||||
|
@ -45,7 +46,7 @@ bool IsAcceptablePath(const char *data, size_t size) {
|
|||
e = p + size;
|
||||
while (p < e) {
|
||||
x = *p++ & 0xff;
|
||||
if (x >= 0300) {
|
||||
if (UNLIKELY(x >= 0300)) {
|
||||
a = ThomPikeByte(x);
|
||||
n = ThomPikeLen(x) - 1;
|
||||
if (p + n <= e) {
|
||||
|
|
|
@ -19,34 +19,101 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define T(NAME) NAME
|
||||
#define S(S) S
|
||||
#define C(C) C
|
||||
#include "test/libc/str/strrchr_test.inc"
|
||||
#undef C
|
||||
#undef S
|
||||
#undef T
|
||||
TEST(strrchr, test) {
|
||||
EXPECT_EQ(NULL, strrchr("hello", 'z'));
|
||||
EXPECT_STREQ("lo", strrchr("hello", 'l'));
|
||||
EXPECT_STREQ("llo", strchr("hello", 'l'));
|
||||
EXPECT_STREQ("hello", strrchr("hello", 'h'));
|
||||
EXPECT_STREQ("ello", strrchr("hello", 'e'));
|
||||
EXPECT_STREQ("o", strrchr("hello", 'o'));
|
||||
}
|
||||
|
||||
#define T(NAME) NAME##16
|
||||
#define S(S) u##S
|
||||
#define C(C) u##C
|
||||
#define strrchr(x, y) strrchr16(x, y)
|
||||
#define strchr(x, y) strchr16(x, y)
|
||||
#include "test/libc/str/strrchr_test.inc"
|
||||
#undef strchr
|
||||
#undef strrchr
|
||||
#undef C
|
||||
#undef S
|
||||
#undef T
|
||||
TEST(strrchr, simdVectorStuffIsntBroken) {
|
||||
EXPECT_EQ(NULL, strrchr("--------------------------------", 'x'));
|
||||
EXPECT_STREQ("x", strrchr("-------------------------------x", 'x'));
|
||||
EXPECT_STREQ("x-------------------------------",
|
||||
strrchr("x-------------------------------", 'x'));
|
||||
EXPECT_STREQ("x"
|
||||
"z-------------------------------",
|
||||
strrchr("x"
|
||||
"z-------------------------------",
|
||||
'x'));
|
||||
EXPECT_STREQ("x-------------------------------"
|
||||
"y-------------------------------",
|
||||
strrchr("x-------------------------------"
|
||||
"y-------------------------------",
|
||||
'x'));
|
||||
EXPECT_STREQ("x"
|
||||
"z-------------------------------"
|
||||
"y-------------------------------",
|
||||
strrchr("x"
|
||||
"z-------------------------------"
|
||||
"y-------------------------------",
|
||||
'x'));
|
||||
}
|
||||
|
||||
#define T(NAME) NAME##32
|
||||
#define S(S) L##S
|
||||
#define C(C) L##C
|
||||
#define strchr(x, y) wcschr(x, y)
|
||||
#define strrchr(x, y) wcsrchr(x, y)
|
||||
#include "test/libc/str/strrchr_test.inc"
|
||||
#undef strchr
|
||||
#undef strrchr
|
||||
#undef C
|
||||
#undef S
|
||||
#undef T
|
||||
TEST(strrchr16, test) {
|
||||
EXPECT_EQ(NULL, strrchr16(u"hello", 'z'));
|
||||
EXPECT_STREQ(u"lo", strrchr16(u"hello", 'l'));
|
||||
EXPECT_STREQ(u"llo", strchr16(u"hello", 'l'));
|
||||
EXPECT_STREQ(u"hello", strrchr16(u"hello", 'h'));
|
||||
EXPECT_STREQ(u"ello", strrchr16(u"hello", 'e'));
|
||||
EXPECT_STREQ(u"o", strrchr16(u"hello", 'o'));
|
||||
}
|
||||
|
||||
TEST(strrchr16, simdVectorStuffIsntBroken) {
|
||||
EXPECT_EQ(NULL, strrchr16(u"--------------------------------", 'x'));
|
||||
EXPECT_STREQ(u"x", strrchr16(u"-------------------------------x", 'x'));
|
||||
EXPECT_STREQ(u"x-------------------------------",
|
||||
strrchr16(u"x-------------------------------", 'x'));
|
||||
EXPECT_STREQ(u"x"
|
||||
u"z-------------------------------",
|
||||
strrchr16(u"x"
|
||||
u"z-------------------------------",
|
||||
'x'));
|
||||
EXPECT_STREQ(u"x-------------------------------"
|
||||
u"y-------------------------------",
|
||||
strrchr16(u"x-------------------------------"
|
||||
u"y-------------------------------",
|
||||
'x'));
|
||||
EXPECT_STREQ(u"x"
|
||||
u"z-------------------------------"
|
||||
u"y-------------------------------",
|
||||
strrchr16(u"x"
|
||||
u"z-------------------------------"
|
||||
u"y-------------------------------",
|
||||
'x'));
|
||||
}
|
||||
|
||||
TEST(wcsrchr, test) {
|
||||
EXPECT_EQ(NULL, wcsrchr(L"hello", 'z'));
|
||||
EXPECT_STREQ(L"lo", wcsrchr(L"hello", 'l'));
|
||||
EXPECT_STREQ(L"llo", wcschr(L"hello", 'l'));
|
||||
EXPECT_STREQ(L"hello", wcsrchr(L"hello", 'h'));
|
||||
EXPECT_STREQ(L"ello", wcsrchr(L"hello", 'e'));
|
||||
EXPECT_STREQ(L"o", wcsrchr(L"hello", 'o'));
|
||||
}
|
||||
|
||||
TEST(wcsrchr, simdVectorStuffIsntBroken) {
|
||||
EXPECT_EQ(NULL, wcsrchr(L"--------------------------------", 'x'));
|
||||
EXPECT_STREQ(L"x", wcsrchr(L"-------------------------------x", 'x'));
|
||||
EXPECT_STREQ(L"x-------------------------------",
|
||||
wcsrchr(L"x-------------------------------", 'x'));
|
||||
EXPECT_STREQ(L"x"
|
||||
L"z-------------------------------",
|
||||
wcsrchr(L"x"
|
||||
L"z-------------------------------",
|
||||
'x'));
|
||||
EXPECT_STREQ(L"x-------------------------------"
|
||||
L"y-------------------------------",
|
||||
wcsrchr(L"x-------------------------------"
|
||||
L"y-------------------------------",
|
||||
'x'));
|
||||
EXPECT_STREQ(L"x"
|
||||
L"z-------------------------------"
|
||||
L"y-------------------------------",
|
||||
wcsrchr(L"x"
|
||||
L"z-------------------------------"
|
||||
L"y-------------------------------",
|
||||
'x'));
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/str/internal.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
#define MAKESTRING(NAME, VALUE) \
|
||||
|
@ -75,3 +77,11 @@ TEST(strstr, test) {
|
|||
ASSERT_EQ(NULL, strstr("-Wl,--gc-sections", "sanitize"));
|
||||
ASSERT_STREQ("x", strstr("x", "x"));
|
||||
}
|
||||
|
||||
BENCH(strstr, bench) {
|
||||
EZBENCH2("strstr", donothing, EXPROPRIATE(strstr(kHyperion, "THE END")));
|
||||
EZBENCH2("strstr", donothing,
|
||||
EXPROPRIATE(strstr(
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
|
||||
"aaaaaab")));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,31 +16,27 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
TEST(T(strrchr), test) {
|
||||
EXPECT_EQ(NULL, strrchr(S("hello"), C('z')));
|
||||
EXPECT_STREQ(S("lo"), strrchr(S("hello"), C('l')));
|
||||
EXPECT_STREQ(S("llo"), strchr(S("hello"), C('l')));
|
||||
EXPECT_STREQ(S("hello"), strrchr(S("hello"), C('h')));
|
||||
EXPECT_STREQ(S("ello"), strrchr(S("hello"), C('e')));
|
||||
EXPECT_STREQ(S("o"), strrchr(S("hello"), C('o')));
|
||||
TEST(utf16toutf8, test) {
|
||||
EXPECT_STREQ("hello☻♥", gc(utf16toutf8(u"hello☻♥", -1, 0)));
|
||||
EXPECT_STREQ("hello☻♥hello☻♥h", gc(utf16toutf8(u"hello☻♥hello☻♥h", -1, 0)));
|
||||
EXPECT_STREQ("hello☻♥hello☻♥hi", gc(utf16toutf8(u"hello☻♥hello☻♥hi", -1, 0)));
|
||||
EXPECT_STREQ("hello☻♥hello☻♥hello☻♥hello☻♥hello☻♥",
|
||||
gc(utf16toutf8(u"hello☻♥hello☻♥hello☻♥hello☻♥hello☻♥", -1, 0)));
|
||||
EXPECT_STREQ("hello--hello--h", gc(utf16toutf8(u"hello--hello--h", -1, 0)));
|
||||
EXPECT_STREQ("hello--hello--hi", gc(utf16toutf8(u"hello--hello--hi", -1, 0)));
|
||||
EXPECT_STREQ("hello--hello--hello--hello--hello--",
|
||||
gc(utf16toutf8(u"hello--hello--hello--hello--hello--", -1, 0)));
|
||||
}
|
||||
|
||||
TEST(T(strrchr), simdVectorStuffIsntBroken) {
|
||||
EXPECT_EQ(NULL, strrchr(S("--------------------------------"), C('x')));
|
||||
EXPECT_STREQ(S("x"), strrchr(S("-------------------------------x"), C('x')));
|
||||
EXPECT_STREQ(S("x-------------------------------"),
|
||||
strrchr(S("x-------------------------------"), C('x')));
|
||||
EXPECT_STREQ(S("x") S("z-------------------------------"),
|
||||
strrchr(S("x") S("z-------------------------------"), C('x')));
|
||||
EXPECT_STREQ(S("x-------------------------------")
|
||||
S("y-------------------------------"),
|
||||
strrchr(S("x-------------------------------")
|
||||
S("y-------------------------------"),
|
||||
C('x')));
|
||||
EXPECT_STREQ(S("x") S("z-------------------------------")
|
||||
S("y-------------------------------"),
|
||||
strrchr(S("x") S("z-------------------------------")
|
||||
S("y-------------------------------"),
|
||||
C('x')));
|
||||
BENCH(utf16toutf8, bench) {
|
||||
size_t n;
|
||||
char16_t *h;
|
||||
h = utf8toutf16(kHyperion, kHyperionSize, &n);
|
||||
EZBENCH2("utf16toutf8", donothing, free(utf16toutf8(h, n, 0)));
|
||||
}
|
40
test/libc/x/utf8toutf16_test.c
Normal file
40
test/libc/x/utf8toutf16_test.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
TEST(utf8toutf16, test) {
|
||||
EXPECT_STREQ(u"hello☻♥", gc(utf8toutf16("hello☻♥", -1, 0)));
|
||||
EXPECT_STREQ(u"hello☻♥hello☻♥h", gc(utf8toutf16("hello☻♥hello☻♥h", -1, 0)));
|
||||
EXPECT_STREQ(u"hello☻♥hello☻♥hi", gc(utf8toutf16("hello☻♥hello☻♥hi", -1, 0)));
|
||||
EXPECT_STREQ(u"hello☻♥hello☻♥hello☻♥hello☻♥hello☻♥",
|
||||
gc(utf8toutf16("hello☻♥hello☻♥hello☻♥hello☻♥hello☻♥", -1, 0)));
|
||||
EXPECT_STREQ(u"hello--hello--h", gc(utf8toutf16("hello--hello--h", -1, 0)));
|
||||
EXPECT_STREQ(u"hello--hello--hi", gc(utf8toutf16("hello--hello--hi", -1, 0)));
|
||||
EXPECT_STREQ(u"hello--hello--hello--hello--hello--",
|
||||
gc(utf8toutf16("hello--hello--hello--hello--hello--", -1, 0)));
|
||||
}
|
||||
|
||||
BENCH(utf8toutf16, bench) {
|
||||
EZBENCH2("utf8toutf16", donothing,
|
||||
free(utf8toutf16(kHyperion, kHyperionSize, 0)));
|
||||
}
|
|
@ -22,30 +22,30 @@
|
|||
#include "net/http/escape.h"
|
||||
|
||||
TEST(HasControlCodes, test) {
|
||||
EXPECT_FALSE(
|
||||
HasControlCodes(kHyperion, kHyperionSize, kControlC0 | kControlC1));
|
||||
EXPECT_TRUE(HasControlCodes("hi\1", -1, kControlC0));
|
||||
EXPECT_FALSE(HasControlCodes("hi\1", -1, kControlC1));
|
||||
EXPECT_FALSE(HasControlCodes("hi there", -1, 0));
|
||||
EXPECT_TRUE(HasControlCodes("hi\tthere", -1, kControlWs));
|
||||
EXPECT_EQ(-1, HasControlCodes(kHyperion, kHyperionSize, kControlC0));
|
||||
EXPECT_EQ(+2, HasControlCodes("hi\1", -1, kControlC0));
|
||||
EXPECT_EQ(-1, HasControlCodes("hi\1", -1, kControlC1));
|
||||
EXPECT_EQ(-1, HasControlCodes("hi there", -1, 0));
|
||||
EXPECT_NE(-1, HasControlCodes("hi\tthere", -1, kControlWs));
|
||||
}
|
||||
|
||||
TEST(HasControlCodes, testDoesUtf8) {
|
||||
EXPECT_FALSE(HasControlCodes(u8"→", -1, kControlC0 | kControlC1));
|
||||
EXPECT_FALSE(HasControlCodes("\304\200", -1, kControlC0 | kControlC1));
|
||||
EXPECT_TRUE(HasControlCodes("\300\200", -1, kControlC0 | kControlC1));
|
||||
EXPECT_FALSE(HasControlCodes("\300\200", -1, kControlC1));
|
||||
EXPECT_TRUE(HasControlCodes("\302\202", -1, kControlC0 | kControlC1));
|
||||
EXPECT_TRUE(HasControlCodes("\302\202", -1, kControlC1));
|
||||
EXPECT_FALSE(HasControlCodes("\302\202", -1, kControlC0));
|
||||
EXPECT_EQ(-1, HasControlCodes(u8"→", -1, kControlC0 | kControlC1));
|
||||
EXPECT_EQ(-1, HasControlCodes("\304\200", -1, kControlC0 | kControlC1));
|
||||
EXPECT_NE(-1, HasControlCodes("\300\200", -1, kControlC0 | kControlC1));
|
||||
EXPECT_EQ(-1, HasControlCodes("\300\200", -1, kControlC1));
|
||||
EXPECT_NE(-1, HasControlCodes("\302\202", -1, kControlC0 | kControlC1));
|
||||
EXPECT_NE(-1, HasControlCodes("\302\202", -1, kControlC1));
|
||||
EXPECT_EQ(-1, HasControlCodes("\302\202", -1, kControlC0));
|
||||
}
|
||||
|
||||
TEST(HasControlCodes, testHasLatin1FallbackBehavior) {
|
||||
EXPECT_TRUE(HasControlCodes("\202", -1, kControlWs | kControlC1));
|
||||
EXPECT_FALSE(HasControlCodes("\202", -1, kControlC0));
|
||||
EXPECT_NE(-1, HasControlCodes("\202", -1, kControlWs | kControlC1));
|
||||
EXPECT_EQ(-1, HasControlCodes("\202", -1, kControlC0));
|
||||
}
|
||||
|
||||
BENCH(HasControlCodes, bench) {
|
||||
EZBENCH2("HasControlCodes", donothing,
|
||||
HasControlCodes(kHyperion, kHyperionSize, kControlWs));
|
||||
EZBENCH2("HasControlCodes small", donothing, HasControlCodes("hello", -1, 0));
|
||||
EZBENCH2("HasControlCodes big", donothing,
|
||||
HasControlCodes(kHyperion, kHyperionSize, kControlC1));
|
||||
}
|
||||
|
|
|
@ -19,25 +19,32 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/inaddr.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/shut.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/* TODO(jart): Finish this */
|
||||
#include "third_party/regex/regex.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
STATIC_YOINK("o/" MODE "/tool/net/redbean.com");
|
||||
char testlib_enable_tmp_setup_teardown;
|
||||
char testlib_enable_tmp_setup_teardown_once;
|
||||
int port;
|
||||
|
||||
void SetUp(void) {
|
||||
return;
|
||||
void SetUpOnce(void) {
|
||||
if (IsWindows()) return;
|
||||
ssize_t n;
|
||||
char buf[512];
|
||||
char buf[1024];
|
||||
int fdin, fdout;
|
||||
ASSERT_NE(-1, mkdir("bin", 0755));
|
||||
ASSERT_NE(-1, (fdin = open("zip:o/" MODE "/tool/net/redbean.com", O_RDONLY)));
|
||||
|
@ -45,32 +52,72 @@ void SetUp(void) {
|
|||
for (;;) {
|
||||
ASSERT_NE(-1, (n = read(fdin, buf, sizeof(buf))));
|
||||
if (!n) break;
|
||||
ASSERT_EQ(n, write(fdout, buf, sizeof(buf)));
|
||||
ASSERT_EQ(n, write(fdout, buf, n));
|
||||
}
|
||||
close(fdout);
|
||||
close(fdin);
|
||||
}
|
||||
|
||||
TEST(redbean, test) {
|
||||
return;
|
||||
char *SendHttpRequest(const char *s) {
|
||||
int fd;
|
||||
char *p;
|
||||
size_t n;
|
||||
ssize_t rc;
|
||||
struct sockaddr_in addr = {AF_INET, htons(port), {htonl(INADDR_LOOPBACK)}};
|
||||
EXPECT_NE(-1, (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
|
||||
EXPECT_NE(-1, connect(fd, &addr, sizeof(addr)));
|
||||
n = strlen(s);
|
||||
EXPECT_EQ(n, write(fd, s, n));
|
||||
shutdown(fd, SHUT_WR);
|
||||
for (p = 0, n = 0;; n += rc) {
|
||||
p = xrealloc(p, n + 512);
|
||||
EXPECT_NE(-1, (rc = read(fd, p + n, 512)));
|
||||
if (rc <= 0) break;
|
||||
}
|
||||
p = xrealloc(p, n + 1);
|
||||
p[n] = 0;
|
||||
close(fd);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool Matches(const char *regex, const char *str) {
|
||||
bool r;
|
||||
regex_t re;
|
||||
CHECK_EQ(REG_OK, regcomp(&re, regex, 0));
|
||||
r = regexec(&re, str, 0, 0, 0) == REG_OK;
|
||||
regfree(&re);
|
||||
return r;
|
||||
}
|
||||
|
||||
TEST(redbean, testOptions) {
|
||||
if (IsWindows()) return;
|
||||
char portbuf[16];
|
||||
int pid, port, pipefds[2];
|
||||
int pid, pipefds[2];
|
||||
sigset_t chldmask, savemask;
|
||||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
ASSERT_NE(-1, pipe2(pipefds, O_CLOEXEC));
|
||||
ASSERT_NE(-1, pipe(pipefds));
|
||||
ASSERT_NE(-1, (pid = vfork()));
|
||||
if (!pid) {
|
||||
close(pipefds[0]);
|
||||
dup2(pipefds[1], 1);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
execv("bin/redbean.com",
|
||||
(char *const[]){"bin/redbean.com", "-zp0", "-l127.0.0.1", 0});
|
||||
(char *const[]){"bin/redbean.com", "-szp0", "-l127.0.0.1", 0});
|
||||
_exit(127);
|
||||
}
|
||||
EXPECT_NE(-1, close(pipefds[1]));
|
||||
EXPECT_NE(-1, read(pipefds[0], portbuf, sizeof(portbuf)));
|
||||
port = atoi(portbuf);
|
||||
printf("port %d\n", port);
|
||||
EXPECT_TRUE(Matches("HTTP/1\\.1 200 OK\r\n"
|
||||
"Accept: \\*/\\*\r\n"
|
||||
"Accept-Charset: utf-8,ISO-8859-1;q=0\\.7,\\*;q=0\\.5\r\n"
|
||||
"Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS\r\n"
|
||||
"Date: .*\r\n"
|
||||
"Server: redbean/0\\.4\r\n"
|
||||
"Content-Length: 0\r\n"
|
||||
"\r\n",
|
||||
gc(SendHttpRequest("OPTIONS * HTTP/1.1\n\n"))));
|
||||
EXPECT_NE(-1, kill(pid, SIGTERM));
|
||||
EXPECT_NE(-1, wait(0));
|
||||
}
|
||||
|
|
|
@ -29,17 +29,21 @@ TEST_TOOL_NET_CHECKS = \
|
|||
|
||||
TEST_TOOL_NET_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_STUBS \
|
||||
LIBC_FMT \
|
||||
LIBC_STDIO \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_SYSV \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_X \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_ZIPOS
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
TEST_TOOL_NET_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TEST_TOOL_NET_DIRECTDEPS),$($(x))))
|
||||
|
|
36
third_party/chibicc/as.c
vendored
36
third_party/chibicc/as.c
vendored
|
@ -136,7 +136,12 @@
|
|||
#define ISRIP 0x00080000
|
||||
#define ISREG 0x00100000
|
||||
|
||||
#define APPEND(L) L.p = realloc(L.p, ++L.n * sizeof(*L.p))
|
||||
#define APPEND(L) \
|
||||
if (++L.n > L.c) { \
|
||||
L.c = L.n + 2 + (L.c >> 1); \
|
||||
L.p = realloc(L.p, L.c * sizeof(*L.p)); \
|
||||
}
|
||||
|
||||
#define IS(P, N, S) (N == sizeof(S) - 1 && !strncasecmp(P, S, sizeof(S) - 1))
|
||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define READ128BE(S) ((unsigned __int128)READ64BE(S) << 64 | READ64BE((S) + 8))
|
||||
|
@ -152,29 +157,29 @@ struct As {
|
|||
bool inhibiterr;
|
||||
bool inhibitwarn;
|
||||
struct Ints {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
long *p;
|
||||
} ints;
|
||||
struct Floats {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
long double *p;
|
||||
} floats;
|
||||
struct Slices {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Slice {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
char *p;
|
||||
} * p;
|
||||
} slices;
|
||||
struct Sauces {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Sauce {
|
||||
unsigned path; // strings
|
||||
unsigned line; // 1-indexed
|
||||
} * p;
|
||||
} sauces;
|
||||
struct Things {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Thing {
|
||||
enum ThingType {
|
||||
TT_INT,
|
||||
|
@ -189,7 +194,7 @@ struct As {
|
|||
} * p;
|
||||
} things;
|
||||
struct Sections {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Section {
|
||||
unsigned name; // strings
|
||||
int flags;
|
||||
|
@ -199,7 +204,7 @@ struct As {
|
|||
} * p;
|
||||
} sections;
|
||||
struct Symbols {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Symbol {
|
||||
bool isused;
|
||||
unsigned char stb; // STB_*
|
||||
|
@ -220,7 +225,7 @@ struct As {
|
|||
} * p;
|
||||
} symbolindex;
|
||||
struct Labels {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Label {
|
||||
unsigned id;
|
||||
unsigned tok; // things
|
||||
|
@ -228,7 +233,7 @@ struct As {
|
|||
} * p;
|
||||
} labels;
|
||||
struct Relas {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Rela {
|
||||
bool isdead;
|
||||
int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...}
|
||||
|
@ -239,7 +244,7 @@ struct As {
|
|||
} * p;
|
||||
} relas;
|
||||
struct Exprs {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
struct Expr {
|
||||
enum ExprKind {
|
||||
EX_INT, // integer
|
||||
|
@ -277,11 +282,11 @@ struct As {
|
|||
} * p;
|
||||
} exprs;
|
||||
struct Strings {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
char **p;
|
||||
} strings, incpaths;
|
||||
struct SectionStack {
|
||||
unsigned long n;
|
||||
unsigned long n, c;
|
||||
int *p;
|
||||
} sectionstack;
|
||||
};
|
||||
|
@ -805,8 +810,7 @@ static void Tokenize(struct As *a, int path) {
|
|||
continue;
|
||||
}
|
||||
if (c == '"') {
|
||||
buf.n = 0;
|
||||
buf.p = NULL;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
for (i = 1; (c = p[i++]);) {
|
||||
if (c == '"') break;
|
||||
c = ReadCharLiteral(&buf, c, p, &i);
|
||||
|
|
|
@ -239,7 +239,11 @@ void LoadRelationships(int argc, char *argv[]) {
|
|||
buf += PAGESIZE;
|
||||
buf[-1] = '\n';
|
||||
for (i = optind; i < argc; ++i) {
|
||||
CHECK_NOTNULL((finpaths = fopen(argv[i], "r")));
|
||||
if (!(finpaths = fopen(argv[i], "r"))) {
|
||||
fprintf(stderr, "\n\e[1mERROR: %s FAILED BECAUSE %s CAUSED %m\e[0m\n\n",
|
||||
argv[0], argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
while (getline(&line, &linecap, finpaths) != -1) {
|
||||
src = chomp(line);
|
||||
if (ShouldSkipSource(src)) continue;
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "libc/sysv/consts/inaddr.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -241,6 +242,7 @@ static struct Assets {
|
|||
static struct Shared {
|
||||
int workers;
|
||||
long double nowish;
|
||||
long double lastreindex;
|
||||
long double lastmeltdown;
|
||||
char currentdate[32];
|
||||
struct rusage server;
|
||||
|
@ -318,6 +320,7 @@ static struct Shared {
|
|||
long readresets;
|
||||
long readtimeouts;
|
||||
long redirects;
|
||||
long reindexes;
|
||||
long reloads;
|
||||
long rewrites;
|
||||
long serveroptions;
|
||||
|
@ -379,13 +382,14 @@ static uint32_t clientaddrsize;
|
|||
static lua_State *L;
|
||||
static size_t zsize;
|
||||
static char *content;
|
||||
static uint8_t *cdir;
|
||||
static uint8_t *zmap;
|
||||
static uint8_t *zcdir;
|
||||
static size_t hdrsize;
|
||||
static size_t msgsize;
|
||||
static size_t amtread;
|
||||
static char *extrahdrs;
|
||||
static char *luaheaderp;
|
||||
static const char *zpath;
|
||||
static const char *brand;
|
||||
static const char *pidpath;
|
||||
static const char *logpath;
|
||||
|
@ -408,6 +412,7 @@ static struct Url url;
|
|||
static struct HttpRequest msg;
|
||||
static char slashpath[PATH_MAX];
|
||||
|
||||
static struct stat zst;
|
||||
static long double startread;
|
||||
static long double lastrefresh;
|
||||
static long double startserver;
|
||||
|
@ -1125,7 +1130,7 @@ static void Daemonize(void) {
|
|||
if ((pid = fork()) > 0) _exit(0);
|
||||
umask(0);
|
||||
if (pidpath) {
|
||||
fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0644);
|
||||
fd = open(pidpath, O_CREAT | O_WRONLY, 0644);
|
||||
write(fd, ibuf, uint64toarray_radix10(getpid(), ibuf));
|
||||
close(fd);
|
||||
}
|
||||
|
@ -1242,7 +1247,8 @@ static void ReportWorkerResources(int pid, struct rusage *ru) {
|
|||
AppendResourceReport(ru, "\n");
|
||||
if (outbuf.n) {
|
||||
if ((s = IndentLines(outbuf.p, outbuf.n - 1, 0, 1))) {
|
||||
LOGF("resource report for pid %d\n%s", pid, s);
|
||||
flogf(kLogInfo, __FILE__, __LINE__, NULL,
|
||||
"resource report for pid %d\n%s", pid, s);
|
||||
free(s);
|
||||
}
|
||||
ClearOutput();
|
||||
|
@ -1411,21 +1417,20 @@ static bool IsCompressionMethodSupported(int method) {
|
|||
|
||||
static void IndexAssets(void) {
|
||||
int64_t lm;
|
||||
uint64_t cf, lf;
|
||||
uint64_t cf;
|
||||
struct Asset *p;
|
||||
uint32_t i, n, m, step, hash;
|
||||
CHECK_GE(HASH_LOAD_FACTOR, 2);
|
||||
CHECK(READ32LE(cdir) == kZipCdir64HdrMagic ||
|
||||
READ32LE(cdir) == kZipCdirHdrMagic);
|
||||
n = GetZipCdirRecords(cdir);
|
||||
CHECK(READ32LE(zcdir) == kZipCdir64HdrMagic ||
|
||||
READ32LE(zcdir) == kZipCdirHdrMagic);
|
||||
n = GetZipCdirRecords(zcdir);
|
||||
m = roundup2pow(MAX(1, n) * HASH_LOAD_FACTOR);
|
||||
p = xcalloc(m, sizeof(struct Asset));
|
||||
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
for (cf = GetZipCdirOffset(zcdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||
lf = GetZipCfileOffset(zmap + cf);
|
||||
if (!IsCompressionMethodSupported(ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf))) {
|
||||
if (!IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf))) {
|
||||
LOGF("don't understand zip compression method %d used by %`'.*s",
|
||||
ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf),
|
||||
ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf),
|
||||
ZIP_CFILE_NAMESIZE(zmap + cf), ZIP_CFILE_NAME(zmap + cf));
|
||||
continue;
|
||||
}
|
||||
|
@ -1437,8 +1442,8 @@ static void IndexAssets(void) {
|
|||
} while (p[i].hash);
|
||||
lm = GetZipCfileLastModified(zmap + cf);
|
||||
p[i].hash = hash;
|
||||
p[i].lf = lf;
|
||||
p[i].cf = cf;
|
||||
p[i].lf = GetZipCfileOffset(zmap + cf);
|
||||
p[i].istext = !!(ZIP_CFILE_INTERNALATTRIBUTES(zmap + cf) & kZipIattrText);
|
||||
p[i].lastmodified = lm;
|
||||
p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm);
|
||||
|
@ -1447,17 +1452,17 @@ static void IndexAssets(void) {
|
|||
assets.n = m;
|
||||
}
|
||||
|
||||
static void OpenZip(const char *path) {
|
||||
static void OpenZip(void) {
|
||||
int fd;
|
||||
uint8_t *p;
|
||||
struct stat st;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK((zsize = st.st_size));
|
||||
if (zmap) munmap(zmap, zsize);
|
||||
CHECK_NE(-1, (fd = open(zpath, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &zst));
|
||||
CHECK((zsize = zst.st_size));
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(zmap = mmap(NULL, zsize, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
CHECK_NOTNULL((cdir = GetZipCdir(zmap, zsize)));
|
||||
if (endswith(path, ".com.dbg") && (p = memmem(zmap, zsize, "MZqFpD", 6))) {
|
||||
CHECK_NOTNULL((zcdir = GetZipCdir(zmap, zsize)));
|
||||
if (endswith(zpath, ".com.dbg") && (p = memmem(zmap, zsize, "MZqFpD", 6))) {
|
||||
zsize -= p - zmap;
|
||||
zmap = p;
|
||||
}
|
||||
|
@ -1472,8 +1477,8 @@ static struct Asset *GetAssetZip(const char *path, size_t pathlen) {
|
|||
i = (hash + (step * (step + 1)) >> 1) & (assets.n - 1);
|
||||
if (!assets.p[i].hash) return NULL;
|
||||
if (hash == assets.p[i].hash &&
|
||||
pathlen == ZIP_LFILE_NAMESIZE(zmap + assets.p[i].lf) &&
|
||||
memcmp(path, ZIP_LFILE_NAME(zmap + assets.p[i].lf), pathlen) == 0) {
|
||||
pathlen == ZIP_CFILE_NAMESIZE(zmap + assets.p[i].cf) &&
|
||||
memcmp(path, ZIP_CFILE_NAME(zmap + assets.p[i].cf), pathlen) == 0) {
|
||||
return &assets.p[i];
|
||||
}
|
||||
}
|
||||
|
@ -1695,7 +1700,7 @@ static void AppendLogo(void) {
|
|||
struct Asset *a;
|
||||
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
||||
q = EncodeBase64(p, n, &n);
|
||||
Append("<img src=\"data:image/png;base64,");
|
||||
Append("<img alt=\"[logo]\" src=\"data:image/png;base64,");
|
||||
AppendData(q, n);
|
||||
Append("\">\r\n");
|
||||
free(q);
|
||||
|
@ -2030,13 +2035,13 @@ static int GetOctalWidth(int x) {
|
|||
return !x ? 1 : x < 8 ? 2 : 1 + bsr(x) / 3;
|
||||
}
|
||||
|
||||
static const char *DescribeCompressionRatio(char rb[8], uint64_t lf) {
|
||||
static const char *DescribeCompressionRatio(char rb[8], uint64_t cf) {
|
||||
long percent;
|
||||
if (ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf) == kZipCompressionNone) {
|
||||
if (ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf) == kZipCompressionNone) {
|
||||
return "n/a";
|
||||
} else {
|
||||
percent = lround(100 - (double)GetZipLfileCompressedSize(zmap + lf) /
|
||||
GetZipLfileUncompressedSize(zmap + lf) * 100);
|
||||
percent = lround(100 - (double)GetZipCfileCompressedSize(zmap + cf) /
|
||||
GetZipCfileUncompressedSize(zmap + cf) * 100);
|
||||
sprintf(rb, "%ld%%", MIN(999, MAX(-999, percent)));
|
||||
return rb;
|
||||
}
|
||||
|
@ -2080,23 +2085,23 @@ td { padding-right: 3em; }\r\n\
|
|||
"<hr>\r\n"
|
||||
"</header>\r\n"
|
||||
"<pre>\r\n",
|
||||
strnlen(GetZipCdirComment(cdir), GetZipCdirCommentSize(cdir)),
|
||||
GetZipCdirComment(cdir));
|
||||
strnlen(GetZipCdirComment(zcdir), GetZipCdirCommentSize(zcdir)),
|
||||
GetZipCdirComment(zcdir));
|
||||
memset(w, 0, sizeof(w));
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
n = GetZipCdirRecords(zcdir);
|
||||
for (cf = GetZipCdirOffset(zcdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||
lf = GetZipCfileOffset(zmap + cf);
|
||||
path = GetAssetPath(cf, &pathlen);
|
||||
if (!IsHiddenPath(path)) {
|
||||
w[0] = min(80, max(w[0], strwidth(path, 0) + 2));
|
||||
w[1] = max(w[1], GetOctalWidth(GetZipCfileMode(zmap + cf)));
|
||||
w[2] = max(w[2], GetDecimalWidth(GetZipLfileUncompressedSize(zmap + lf)));
|
||||
w[2] = max(w[2], GetDecimalWidth(GetZipCfileUncompressedSize(zmap + cf)));
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
n = GetZipCdirRecords(zcdir);
|
||||
for (cf = GetZipCdirOffset(zcdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||
lf = GetZipCfileOffset(zmap + cf);
|
||||
path = GetAssetPath(cf, &pathlen);
|
||||
|
@ -2113,17 +2118,17 @@ td { padding-right: 3em; }\r\n\
|
|||
localtime_r(&lastmod, &tm);
|
||||
strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S %Z", &tm);
|
||||
if (IsCompressionMethodSupported(
|
||||
ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf)) &&
|
||||
ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf)) &&
|
||||
IsAcceptablePath(path, pathlen)) {
|
||||
Append("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
||||
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
||||
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, lf),
|
||||
w[2], GetZipLfileUncompressedSize(zmap + lf), rp[3]);
|
||||
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, cf),
|
||||
w[2], GetZipCfileUncompressedSize(zmap + cf), rp[3]);
|
||||
} else {
|
||||
Append("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
||||
w[1], GetZipCfileMode(zmap + cf),
|
||||
DescribeCompressionRatio(rb, lf), w[2],
|
||||
GetZipLfileUncompressedSize(zmap + lf), rp[3]);
|
||||
DescribeCompressionRatio(rb, cf), w[2],
|
||||
GetZipCfileUncompressedSize(zmap + cf), rp[3]);
|
||||
}
|
||||
free(rp[4]);
|
||||
free(rp[3]);
|
||||
|
@ -2299,6 +2304,7 @@ static char *ServeStatusz(void) {
|
|||
AppendLong1("readresets", shared->readresets);
|
||||
AppendLong1("readtimeouts", shared->readtimeouts);
|
||||
AppendLong1("redirects", shared->redirects);
|
||||
AppendLong1("reindexes", shared->reindexes);
|
||||
AppendLong1("reloads", shared->reloads);
|
||||
AppendLong1("rewrites", shared->rewrites);
|
||||
AppendLong1("serveroptions", shared->serveroptions);
|
||||
|
@ -2507,6 +2513,13 @@ static char *Route(const char *host, size_t hostlen, const char *path,
|
|||
}
|
||||
}
|
||||
|
||||
static void Reindex(void) {
|
||||
LockInc(&shared->reindexes);
|
||||
LOGF("reindexing");
|
||||
OpenZip();
|
||||
IndexAssets();
|
||||
}
|
||||
|
||||
static const char *LuaCheckPath(lua_State *L, int idx, size_t *pathlen) {
|
||||
const char *path;
|
||||
if (lua_isnoneornil(L, idx)) {
|
||||
|
@ -2951,7 +2964,7 @@ static int LuaSetHeader(lua_State *L) {
|
|||
}
|
||||
switch (h) {
|
||||
case kHttpConnection:
|
||||
if (evallen != 5 || memcmp(eval, "close", 5)) {
|
||||
if (evallen != 5 || memcasecmp(eval, "close", 5)) {
|
||||
luaL_argerror(L, 2, "unsupported");
|
||||
unreachable;
|
||||
}
|
||||
|
@ -3162,7 +3175,7 @@ static int LuaHasControlCodes(lua_State *L) {
|
|||
const char *p;
|
||||
p = luaL_checklstring(L, 1, &n);
|
||||
f = LuaCheckControlFlags(L, 2);
|
||||
lua_pushboolean(L, HasControlCodes(p, n, f));
|
||||
lua_pushboolean(L, HasControlCodes(p, n, f) != -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -3446,8 +3459,8 @@ static int LuaGetZipPaths(lua_State *L) {
|
|||
size_t i, n, pathlen;
|
||||
lua_newtable(L);
|
||||
i = 0;
|
||||
n = GetZipCdirRecords(cdir);
|
||||
for (cf = GetZipCdirOffset(cdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
n = GetZipCdirRecords(zcdir);
|
||||
for (cf = GetZipCdirOffset(zcdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||
path = GetAssetPath(cf, &pathlen);
|
||||
lua_pushlstring(L, path, pathlen);
|
||||
|
@ -3847,13 +3860,31 @@ static void LuaReload(void) {
|
|||
}
|
||||
|
||||
static void HandleReload(void) {
|
||||
LockInc(&shared->reloads);
|
||||
LOGF("reloading");
|
||||
Reindex();
|
||||
LuaReload();
|
||||
}
|
||||
|
||||
static bool ZipCdirChanged(void) {
|
||||
struct stat st;
|
||||
if (!IsZipCdir32(zmap, zsize, zcdir - zmap) &&
|
||||
!IsZipCdir64(zmap, zsize, zcdir - zmap)) {
|
||||
return true;
|
||||
}
|
||||
if (stat(zpath, &st) != -1 && st.st_ino != zst.st_ino) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleHeartbeat(void) {
|
||||
if (nowl() - lastrefresh > 60 * 60) RefreshTime();
|
||||
UpdateCurrentDate(nowl());
|
||||
if (ZipCdirChanged()) {
|
||||
shared->lastreindex = nowl();
|
||||
kill(0, SIGUSR1);
|
||||
}
|
||||
getrusage(RUSAGE_SELF, &shared->server);
|
||||
#ifndef STATIC
|
||||
LuaRun("/.heartbeat.lua");
|
||||
|
@ -4344,6 +4375,10 @@ static void HandleMessages(void) {
|
|||
LogClose(DescribeClose());
|
||||
return;
|
||||
}
|
||||
if (invalidated) {
|
||||
HandleReload();
|
||||
invalidated = false;
|
||||
}
|
||||
}
|
||||
if (msgsize == amtread) {
|
||||
amtread = 0;
|
||||
|
@ -4363,6 +4398,10 @@ static void HandleMessages(void) {
|
|||
}
|
||||
}
|
||||
CollectGarbage();
|
||||
if (invalidated) {
|
||||
HandleReload();
|
||||
invalidated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4485,7 +4524,7 @@ static void TuneSockets(void) {
|
|||
setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
static void RestoreApe(const char *prog) {
|
||||
static void RestoreApe(void) {
|
||||
char *p;
|
||||
size_t n;
|
||||
struct Asset *a;
|
||||
|
@ -4493,7 +4532,7 @@ static void RestoreApe(const char *prog) {
|
|||
if (IsWindows()) return; /* TODO */
|
||||
if (IsOpenbsd()) return; /* TODO */
|
||||
if (IsNetbsd()) return; /* TODO */
|
||||
if (endswith(prog, ".com.dbg")) return;
|
||||
if (endswith(zpath, ".com.dbg")) return;
|
||||
close(OpenExecutable());
|
||||
if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) {
|
||||
mprotect(ape_rom_vaddr, PAGESIZE, PROT_READ | PROT_WRITE);
|
||||
|
@ -4506,7 +4545,7 @@ static void RestoreApe(const char *prog) {
|
|||
}
|
||||
}
|
||||
|
||||
void RedBean(int argc, char *argv[], const char *prog) {
|
||||
void RedBean(int argc, char *argv[]) {
|
||||
uint32_t addrsize;
|
||||
gmtoff = GetGmtOffset((lastrefresh = startserver = nowl()));
|
||||
CHECK_GT(CLK_TCK, 0);
|
||||
|
@ -4514,9 +4553,10 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
|||
(shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE),
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
||||
-1, 0)));
|
||||
OpenZip(prog);
|
||||
zpath = (const char *)getauxval(AT_EXECFN);
|
||||
OpenZip();
|
||||
IndexAssets();
|
||||
RestoreApe(prog);
|
||||
RestoreApe();
|
||||
SetDefaults();
|
||||
GetOpts(argc, argv);
|
||||
LuaInit();
|
||||
|
@ -4530,9 +4570,6 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
|||
xsigaction(SIGALRM, OnAlrm, 0, 0, 0);
|
||||
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
|
||||
/* TODO(jart): SIGXCPU and SIGXFSZ */
|
||||
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
||||
heartless = true;
|
||||
}
|
||||
server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
||||
CHECK_NE(-1, server);
|
||||
TuneSockets();
|
||||
|
@ -4556,16 +4593,23 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
|||
printf("%d\n", ntohs(serveraddr.sin_port));
|
||||
fflush(stdout);
|
||||
}
|
||||
if (daemonize) Daemonize();
|
||||
if (daemonize) {
|
||||
Daemonize();
|
||||
} else {
|
||||
setpgid(getpid(), getpid());
|
||||
}
|
||||
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
||||
heartless = true;
|
||||
}
|
||||
UpdateCurrentDate(nowl());
|
||||
freelist.c = 8;
|
||||
freelist.p = xcalloc(freelist.c, sizeof(*freelist.p));
|
||||
unmaplist.c = 1;
|
||||
unmaplist.p = xcalloc(unmaplist.c, sizeof(*unmaplist.p));
|
||||
hdrbuf.n = 4 * 1024;
|
||||
hdrbuf.p = xvalloc(hdrbuf.n);
|
||||
hdrbuf.p = xmalloc(hdrbuf.n);
|
||||
inbuf.n = maxpayloadsize;
|
||||
inbuf.p = xvalloc(inbuf.n);
|
||||
inbuf.p = xmalloc(inbuf.n);
|
||||
while (!terminated) {
|
||||
if (zombied) {
|
||||
ReapZombies();
|
||||
|
@ -4603,6 +4647,6 @@ int main(int argc, char *argv[]) {
|
|||
setenv("GDB", "", true);
|
||||
showcrashreports();
|
||||
}
|
||||
RedBean(argc, argv, (const char *)getauxval(AT_EXECFN));
|
||||
RedBean(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -428,6 +428,7 @@ static void OnUnzoom(long y, long x) {
|
|||
}
|
||||
|
||||
static void OnMouseLeftDrag(long y, long x) {
|
||||
int i;
|
||||
if (y == save_y && x == save_x) return;
|
||||
save_y = y;
|
||||
save_x = x;
|
||||
|
@ -440,7 +441,10 @@ static void OnMouseLeftDrag(long y, long x) {
|
|||
if (erase) {
|
||||
Unset(y, x);
|
||||
} else {
|
||||
Set(y, x);
|
||||
for (i = 0; i < (2 << zoom); ++i) {
|
||||
Set(y + (rand() % (zoom + 1)) - (rand() % (zoom + 1)),
|
||||
x + (rand() % (zoom + 1)) - (rand() % (zoom + 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue