mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-05 17:30:27 +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
|
#-φ-examples/package/new.sh
|
||||||
include test/test.mk
|
include test/test.mk
|
||||||
|
|
||||||
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
||||||
SRCS = $(foreach x,$(PKGS),$($(x)_SRCS))
|
SRCS := $(foreach x,$(PKGS),$($(x)_SRCS))
|
||||||
HDRS = $(foreach x,$(PKGS),$($(x)_HDRS))
|
HDRS := $(foreach x,$(PKGS),$($(x)_HDRS))
|
||||||
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
||||||
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
||||||
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
||||||
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
||||||
|
|
||||||
bins: $(BINS)
|
bins: $(BINS)
|
||||||
check: $(CHECKS)
|
check: $(CHECKS)
|
||||||
|
@ -206,11 +206,17 @@ tags: TAGS HTAGS
|
||||||
o/$(MODE)/.x:
|
o/$(MODE)/.x:
|
||||||
@mkdir -p $(@D) && touch $@
|
@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))))
|
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||||
|
|
||||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(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)
|
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
|
@$(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 |
|
| FreeBSD | 12 | 2018 |
|
||||||
| OpenBSD | 6.4 | 2018 |
|
| OpenBSD | 6.4 | 2018 |
|
||||||
| NetBSD | 9.1 | 2020 |
|
| 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.
|
* 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 which can be ITIMER_REAL, ITIMER_VIRTUAL, etc.
|
||||||
* @param newvalue specifies the interval ({0,0} means one-shot) and
|
* @param newvalue specifies the interval ({0,0} means one-shot) and
|
||||||
* duration ({0,0} means disarm) in microseconds ∈ [0,999999] 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.
|
* format strings are constexprs that only contain directives.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PFLINK(FMT) \
|
#define PFLINK(FMT) \
|
||||||
({ \
|
({ \
|
||||||
if (___PFLINK(FMT, strpbrk, "faAeEgG")) STATIC_YOINK("__fmt_dtoa"); \
|
if (___PFLINK(FMT, strpbrk, "faAeg")) STATIC_YOINK("__fmt_dtoa"); \
|
||||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||||
STATIC_YOINK("strnwidth"); \
|
STATIC_YOINK("strnwidth"); \
|
||||||
STATIC_YOINK("strnwidth16"); \
|
STATIC_YOINK("strnwidth16"); \
|
||||||
STATIC_YOINK("wcsnwidth"); \
|
STATIC_YOINK("wcsnwidth"); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
FMT; \
|
FMT; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define SFLINK(FMT) \
|
#define SFLINK(FMT) \
|
||||||
|
|
|
@ -27,149 +27,17 @@
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
const struct Error {
|
extern const struct Error {
|
||||||
const long *x;
|
int x;
|
||||||
const char *s;
|
int s;
|
||||||
} kErrors[] = {
|
} kErrorNames[];
|
||||||
{&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"},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *geterrname(long x) {
|
static const char *GetErrorName(long x) {
|
||||||
int i;
|
int i;
|
||||||
if (x) {
|
if (x) {
|
||||||
for (i = 0; i < ARRAYLEN(kErrors); ++i) {
|
for (i = 0; kErrorNames[i].x; ++i) {
|
||||||
if (x == *kErrors[i].x) {
|
if (x == *(const long *)((uintptr_t)kErrorNames + kErrorNames[i].x)) {
|
||||||
return kErrors[i].s;
|
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;
|
char *p;
|
||||||
const char *s;
|
const char *s;
|
||||||
err &= 0xFFFF;
|
err &= 0xFFFF;
|
||||||
s = geterrname(err);
|
s = GetErrorName(err);
|
||||||
p = buf;
|
p = buf;
|
||||||
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
|
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
|
||||||
p = stpcpy(p, s);
|
p = stpcpy(p, s);
|
||||||
|
|
|
@ -40,9 +40,7 @@ OpenExecutable:
|
||||||
pushq MAP_ANONYMOUS(%rip) # -0x28(%rbp)
|
pushq MAP_ANONYMOUS(%rip) # -0x28(%rbp)
|
||||||
pushq MAP_PRIVATE(%rip) # -0x30(%rbp)
|
pushq MAP_PRIVATE(%rip) # -0x30(%rbp)
|
||||||
pushq MAP_FIXED(%rip) # -0x38(%rbp)
|
pushq MAP_FIXED(%rip) # -0x38(%rbp)
|
||||||
pushq MAP_SHARED(%rip) # -0x40(%rbp)
|
pushq __NR_mprotect(%rip) # -0x40(%rbp)
|
||||||
pushq __NR_mprotect(%rip) # -0x48(%rbp)
|
|
||||||
pushq __NR_mprotect(%rip) # -0x50(%rbp)
|
|
||||||
push %rbx # code buffer
|
push %rbx # code buffer
|
||||||
push %r12 # data buffer
|
push %r12 # data buffer
|
||||||
push %r14 # filename
|
push %r14 # filename
|
||||||
|
@ -98,7 +96,7 @@ OpenExecutable:
|
||||||
rep movsb
|
rep movsb
|
||||||
|
|
||||||
// Change protection.
|
// Change protection.
|
||||||
mov -0x48(%rbp),%eax # __NR_mprotect
|
mov -0x40(%rbp),%eax # __NR_mprotect
|
||||||
mov %rbx,%rdi
|
mov %rbx,%rdi
|
||||||
mov $PAGESIZE,%esi
|
mov $PAGESIZE,%esi
|
||||||
mov $PROT_READ|PROT_EXEC,%edx
|
mov $PROT_READ|PROT_EXEC,%edx
|
||||||
|
@ -133,7 +131,7 @@ OpenExecutable:
|
||||||
mov $ape_rom_filesz,%esi
|
mov $ape_rom_filesz,%esi
|
||||||
mov $PROT_READ|PROT_EXEC,%edx
|
mov $PROT_READ|PROT_EXEC,%edx
|
||||||
mov -0x38(%rbp),%r10d # MAP_FIXED
|
mov -0x38(%rbp),%r10d # MAP_FIXED
|
||||||
or -0x40(%rbp),%r10d # MAP_SHARED
|
or -0x30(%rbp),%r10d # MAP_PRIVATE
|
||||||
mov %r15d,%r8d
|
mov %r15d,%r8d
|
||||||
mov $ape_rom_offset,%r9d
|
mov $ape_rom_offset,%r9d
|
||||||
push %r9 # openbsd:pad
|
push %r9 # openbsd:pad
|
||||||
|
|
|
@ -24,6 +24,7 @@ _peekall:
|
||||||
.leafprologue
|
.leafprologue
|
||||||
ezlea _base,si
|
ezlea _base,si
|
||||||
ezlea _end,cx
|
ezlea _end,cx
|
||||||
|
add $0x1000,%rsi
|
||||||
0: mov (%rsi),%eax
|
0: mov (%rsi),%eax
|
||||||
add $PAGESIZE,%rsi
|
add $PAGESIZE,%rsi
|
||||||
cmp %rcx,%rsi
|
cmp %rcx,%rsi
|
||||||
|
|
|
@ -33,10 +33,10 @@
|
||||||
* allocated automatically, also NUL-terminated is guaranteed
|
* allocated automatically, also NUL-terminated is guaranteed
|
||||||
* @param n is the capacity of s (in/out)
|
* @param n is the capacity of s (in/out)
|
||||||
* @param delim is the stop char (and NUL is implicitly too)
|
* @param delim is the stop char (and NUL is implicitly too)
|
||||||
* @return number of bytes read, including delim, excluding NUL, or -1
|
* @return number of bytes read >0, including delim, excluding NUL,
|
||||||
* w/ errno on EOF or error; see ferror() and feof()
|
* or -1 w/ errno on EOF or error; see ferror() and feof()
|
||||||
* @note this function can't punt EINTR to caller
|
* @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) {
|
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
|
@ -17,16 +17,14 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
noasan static const unsigned char *strchr_x64(const unsigned char *p,
|
noasan static const char *strchr_x64(const char *p, uint64_t c) {
|
||||||
uint64_t c) {
|
|
||||||
unsigned a, b;
|
unsigned a, b;
|
||||||
uint64_t w, x, y;
|
uint64_t w, x, y;
|
||||||
for (c *= 0x0101010101010101;; p += 8) {
|
for (c *= 0x0101010101010101;; p += 8) {
|
||||||
w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
w = READ64LE(p);
|
||||||
(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;
|
|
||||||
if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) |
|
if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) |
|
||||||
(y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
|
(y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
|
||||||
if (x) {
|
if (x) {
|
||||||
|
@ -63,7 +61,7 @@ char *strchr(const char *s, int c) {
|
||||||
if ((*s & 0xff) == c) return s;
|
if ((*s & 0xff) == c) return s;
|
||||||
if (!*s) return NULL;
|
if (!*s) return NULL;
|
||||||
}
|
}
|
||||||
r = (char *)strchr_x64((const unsigned char *)s, c);
|
r = strchr_x64(s, c);
|
||||||
assert(!r || *r || !c);
|
assert(!r || *r || !c);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +30,8 @@
|
||||||
*/
|
*/
|
||||||
char *strstr(const char *haystack, const char *needle) {
|
char *strstr(const char *haystack, const char *needle) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
if (!*needle) return haystack;
|
||||||
|
haystack = firstnonnull(strchr(haystack, *needle), haystack);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (i = 0;;) {
|
for (i = 0;;) {
|
||||||
if (!needle[i]) return (/*unconst*/ char *)haystack;
|
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.
|
* 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 dst is output buffer
|
||||||
* @param dstsize is bytes in dst
|
* @param dstsize is bytes in dst
|
||||||
* @param src is NUL-terminated UTF-16 input string
|
* @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.
|
* 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 dst is output buffer
|
||||||
* @param dstsize is shorts in dst
|
* @param dstsize is shorts in dst
|
||||||
* @param src is NUL-terminated UTF-8 input string
|
* @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.
|
* 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;
|
||||||
|
extern char testlib_enable_tmp_setup_teardown_once;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User-defined test setup function.
|
* User-defined test setup function.
|
||||||
|
@ -82,6 +83,7 @@ extern char testlib_enable_tmp_setup_teardown;
|
||||||
* defined by the linkage.
|
* defined by the linkage.
|
||||||
*/
|
*/
|
||||||
void SetUp(void);
|
void SetUp(void);
|
||||||
|
void SetUpOnce(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User-defined test cleanup function.
|
* User-defined test cleanup function.
|
||||||
|
@ -90,6 +92,7 @@ void SetUp(void);
|
||||||
* defined by the linkage.
|
* defined by the linkage.
|
||||||
*/
|
*/
|
||||||
void TearDown(void);
|
void TearDown(void);
|
||||||
|
void TearDownOnce(void);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § testing library » assert or die ─╬─│┼
|
│ cosmopolitan § testing library » assert or die ─╬─│┼
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
|
static int x;
|
||||||
|
static char cwd[PATH_MAX];
|
||||||
|
static char tmp[PATH_MAX];
|
||||||
|
|
||||||
void testlib_finish(void) {
|
void testlib_finish(void) {
|
||||||
if (g_testlib_failed) {
|
if (g_testlib_failed) {
|
||||||
fprintf(stderr, "%u / %u %s\n", g_testlib_failed, g_testlib_ran,
|
fprintf(stderr, "%u / %u %s\n", g_testlib_failed, g_testlib_ran,
|
||||||
|
@ -42,6 +46,18 @@ wontreturn void testlib_abort(void) {
|
||||||
unreachable;
|
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.
|
* 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
|
* @see ape/ape.lds
|
||||||
*/
|
*/
|
||||||
int x;
|
|
||||||
char cwd[PATH_MAX];
|
|
||||||
char tmp[PATH_MAX];
|
|
||||||
const testfn_t *fn;
|
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) {
|
for (x = 0, fn = start; fn != end; ++fn) {
|
||||||
if (weaken(testlib_enable_tmp_setup_teardown)) {
|
if (weaken(testlib_enable_tmp_setup_teardown)) SetupTmpDir();
|
||||||
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(SetUp)) weaken(SetUp)();
|
if (weaken(SetUp)) weaken(SetUp)();
|
||||||
errno = 0;
|
errno = 0;
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
|
@ -83,9 +93,8 @@ testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
|
||||||
(*fn)();
|
(*fn)();
|
||||||
sys_getpid();
|
sys_getpid();
|
||||||
if (weaken(TearDown)) weaken(TearDown)();
|
if (weaken(TearDown)) weaken(TearDown)();
|
||||||
if (weaken(testlib_enable_tmp_setup_teardown)) {
|
if (weaken(testlib_enable_tmp_setup_teardown)) TearDownTmpDir();
|
||||||
CHECK_NE(-1, chdir(cwd));
|
|
||||||
CHECK_NE(-1, rmrf(tmp));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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;
|
char *xinet_ntop(int, const void *) _XPNN _XMAL;
|
||||||
void *xunbinga(size_t, const char16_t *) attributeallocalign((1)) _XMAL _XRET;
|
void *xunbinga(size_t, const char16_t *) attributeallocalign((1)) _XMAL _XRET;
|
||||||
void *xunbing(const char16_t *) _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 ─╬─│┼
|
│ cosmopolitan § eXtended apis » files ─╬─│┼
|
||||||
|
|
|
@ -25,16 +25,18 @@
|
||||||
*
|
*
|
||||||
* @return allocated line that needs free() and usually chomp() too,
|
* @return allocated line that needs free() and usually chomp() too,
|
||||||
* or NULL on ferror() or feof()
|
* 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 *xgetline(FILE *f) {
|
||||||
char *res;
|
char *p;
|
||||||
size_t n, got;
|
size_t n;
|
||||||
|
ssize_t m;
|
||||||
n = 0;
|
n = 0;
|
||||||
res = NULL;
|
p = 0;
|
||||||
if ((got = getdelim(&res, &n, '\n', f)) <= 0) {
|
if ((m = getdelim(&p, &n, '\n', f)) <= 0) {
|
||||||
free(res);
|
free(p);
|
||||||
res = NULL;
|
p = 0;
|
||||||
}
|
}
|
||||||
return res;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
* @param p is input value
|
* @param p is input value
|
||||||
* @param n if -1 implies strlen
|
* @param n if -1 implies strlen
|
||||||
* @param z if non-NULL receives output length
|
* @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
|
* @return allocated NUL-terminated buffer, or NULL w/ errno
|
||||||
* @error EILSEQ means UTF-8 found we can't or won't re-encode
|
* @error EILSEQ means UTF-8 found we can't or won't re-encode
|
||||||
* @error ENOMEM means malloc() failed
|
* @error ENOMEM means malloc() failed
|
||||||
|
@ -38,7 +38,12 @@
|
||||||
char *EncodeLatin1(const char *p, size_t n, size_t *z, int f) {
|
char *EncodeLatin1(const char *p, size_t n, size_t *z, int f) {
|
||||||
int c;
|
int c;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
char t[256];
|
||||||
char *r, *q;
|
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 (z) *z = 0;
|
||||||
if (n == -1) n = p ? strlen(p) : 0;
|
if (n == -1) n = p ? strlen(p) : 0;
|
||||||
if ((q = r = malloc(n + 1))) {
|
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;
|
goto Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (((f & kControlC1) && 0x80 <= c && c < 0xA0) ||
|
if (t[c]) {
|
||||||
((f & kControlC0) && (c < 32 || c == 0x7F) &&
|
|
||||||
!(c == '\t' || c == '\r' || c == '\n' || c == '\v')) ||
|
|
||||||
((f & kControlWs) &&
|
|
||||||
(c == '\t' || c == '\r' || c == '\n' || c == '\v'))) {
|
|
||||||
goto Invalid;
|
goto Invalid;
|
||||||
}
|
}
|
||||||
*q++ = c;
|
*q++ = c;
|
||||||
|
|
|
@ -28,7 +28,7 @@ char *EscapeFragment(const char *, size_t, size_t *);
|
||||||
char *EscapeSegment(const char *, size_t, size_t *);
|
char *EscapeSegment(const char *, size_t, size_t *);
|
||||||
char *EscapeJsStringLiteral(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 *Underlong(const char *, size_t, size_t *);
|
||||||
char *DecodeLatin1(const char *, size_t, size_t *);
|
char *DecodeLatin1(const char *, size_t, size_t *);
|
||||||
char *EncodeLatin1(const char *, size_t, size_t *, int);
|
char *EncodeLatin1(const char *, size_t, size_t *, int);
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "net/http/http.h"
|
#include "net/http/http.h"
|
||||||
|
|
||||||
static const struct HttpReason {
|
static const struct thatispacked HttpReason {
|
||||||
int code;
|
short code;
|
||||||
const char *name;
|
const char *name;
|
||||||
} kHttpReason[] = {
|
} kHttpReason[] = {
|
||||||
{100, "Continue"},
|
{100, "Continue"},
|
||||||
|
|
|
@ -16,11 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/errno.h"
|
#include "libc/bits/likely.h"
|
||||||
#include "libc/intrin/pcmpgtb.h"
|
|
||||||
#include "libc/intrin/pmovmskb.h"
|
|
||||||
#include "libc/mem/mem.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/thompike.h"
|
#include "libc/str/thompike.h"
|
||||||
#include "net/http/escape.h"
|
#include "net/http/escape.h"
|
||||||
|
@ -31,17 +27,22 @@
|
||||||
* @param p is input value
|
* @param p is input value
|
||||||
* @param n if -1 implies strlen
|
* @param n if -1 implies strlen
|
||||||
* @param f can have kControlWs, kControlC0, kControlC1 to forbid
|
* @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()
|
* @see VisualizeControlCodes()
|
||||||
*/
|
*/
|
||||||
bool HasControlCodes(const char *p, size_t n, int f) {
|
ssize_t HasControlCodes(const char *p, size_t n, int f) {
|
||||||
int c;
|
char t[256];
|
||||||
wint_t x, a, b;
|
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;
|
if (n == -1) n = p ? strlen(p) : 0;
|
||||||
for (i = 0; i < n;) {
|
for (i = 0; i < n;) {
|
||||||
|
g = i;
|
||||||
x = p[i++] & 0xff;
|
x = p[i++] & 0xff;
|
||||||
if (x >= 0300) {
|
if (UNLIKELY(x >= 0300)) {
|
||||||
a = ThomPikeByte(x);
|
a = ThomPikeByte(x);
|
||||||
m = ThomPikeLen(x) - 1;
|
m = ThomPikeLen(x) - 1;
|
||||||
if (i + m <= n) {
|
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) ||
|
if (x < 256 && t[x]) {
|
||||||
((f & kControlC0) && (x < 32 || x == 0x7F) &&
|
return g;
|
||||||
!(x == '\t' || x == '\r' || x == '\n' || x == '\v')) ||
|
|
||||||
((f & kControlWs) &&
|
|
||||||
(x == '\t' || x == '\r' || x == '\n' || x == '\v'))) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/likely.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/thompike.h"
|
#include "libc/str/thompike.h"
|
||||||
#include "net/http/http.h"
|
#include "net/http/http.h"
|
||||||
|
@ -45,7 +46,7 @@ bool IsAcceptablePath(const char *data, size_t size) {
|
||||||
e = p + size;
|
e = p + size;
|
||||||
while (p < e) {
|
while (p < e) {
|
||||||
x = *p++ & 0xff;
|
x = *p++ & 0xff;
|
||||||
if (x >= 0300) {
|
if (UNLIKELY(x >= 0300)) {
|
||||||
a = ThomPikeByte(x);
|
a = ThomPikeByte(x);
|
||||||
n = ThomPikeLen(x) - 1;
|
n = ThomPikeLen(x) - 1;
|
||||||
if (p + n <= e) {
|
if (p + n <= e) {
|
||||||
|
|
|
@ -19,34 +19,101 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
#define T(NAME) NAME
|
TEST(strrchr, test) {
|
||||||
#define S(S) S
|
EXPECT_EQ(NULL, strrchr("hello", 'z'));
|
||||||
#define C(C) C
|
EXPECT_STREQ("lo", strrchr("hello", 'l'));
|
||||||
#include "test/libc/str/strrchr_test.inc"
|
EXPECT_STREQ("llo", strchr("hello", 'l'));
|
||||||
#undef C
|
EXPECT_STREQ("hello", strrchr("hello", 'h'));
|
||||||
#undef S
|
EXPECT_STREQ("ello", strrchr("hello", 'e'));
|
||||||
#undef T
|
EXPECT_STREQ("o", strrchr("hello", 'o'));
|
||||||
|
}
|
||||||
|
|
||||||
#define T(NAME) NAME##16
|
TEST(strrchr, simdVectorStuffIsntBroken) {
|
||||||
#define S(S) u##S
|
EXPECT_EQ(NULL, strrchr("--------------------------------", 'x'));
|
||||||
#define C(C) u##C
|
EXPECT_STREQ("x", strrchr("-------------------------------x", 'x'));
|
||||||
#define strrchr(x, y) strrchr16(x, y)
|
EXPECT_STREQ("x-------------------------------",
|
||||||
#define strchr(x, y) strchr16(x, y)
|
strrchr("x-------------------------------", 'x'));
|
||||||
#include "test/libc/str/strrchr_test.inc"
|
EXPECT_STREQ("x"
|
||||||
#undef strchr
|
"z-------------------------------",
|
||||||
#undef strrchr
|
strrchr("x"
|
||||||
#undef C
|
"z-------------------------------",
|
||||||
#undef S
|
'x'));
|
||||||
#undef T
|
EXPECT_STREQ("x-------------------------------"
|
||||||
|
"y-------------------------------",
|
||||||
|
strrchr("x-------------------------------"
|
||||||
|
"y-------------------------------",
|
||||||
|
'x'));
|
||||||
|
EXPECT_STREQ("x"
|
||||||
|
"z-------------------------------"
|
||||||
|
"y-------------------------------",
|
||||||
|
strrchr("x"
|
||||||
|
"z-------------------------------"
|
||||||
|
"y-------------------------------",
|
||||||
|
'x'));
|
||||||
|
}
|
||||||
|
|
||||||
#define T(NAME) NAME##32
|
TEST(strrchr16, test) {
|
||||||
#define S(S) L##S
|
EXPECT_EQ(NULL, strrchr16(u"hello", 'z'));
|
||||||
#define C(C) L##C
|
EXPECT_STREQ(u"lo", strrchr16(u"hello", 'l'));
|
||||||
#define strchr(x, y) wcschr(x, y)
|
EXPECT_STREQ(u"llo", strchr16(u"hello", 'l'));
|
||||||
#define strrchr(x, y) wcsrchr(x, y)
|
EXPECT_STREQ(u"hello", strrchr16(u"hello", 'h'));
|
||||||
#include "test/libc/str/strrchr_test.inc"
|
EXPECT_STREQ(u"ello", strrchr16(u"hello", 'e'));
|
||||||
#undef strchr
|
EXPECT_STREQ(u"o", strrchr16(u"hello", 'o'));
|
||||||
#undef strrchr
|
}
|
||||||
#undef C
|
|
||||||
#undef S
|
TEST(strrchr16, simdVectorStuffIsntBroken) {
|
||||||
#undef T
|
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/nexgen32e/x86feature.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/str/internal.h"
|
#include "libc/str/internal.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
|
#include "libc/testlib/hyperion.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
#define MAKESTRING(NAME, VALUE) \
|
#define MAKESTRING(NAME, VALUE) \
|
||||||
|
@ -75,3 +77,11 @@ TEST(strstr, test) {
|
||||||
ASSERT_EQ(NULL, strstr("-Wl,--gc-sections", "sanitize"));
|
ASSERT_EQ(NULL, strstr("-Wl,--gc-sections", "sanitize"));
|
||||||
ASSERT_STREQ("x", strstr("x", "x"));
|
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 -*-│
|
/*-*- 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│
|
│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 │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ 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 │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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) {
|
TEST(utf16toutf8, test) {
|
||||||
EXPECT_EQ(NULL, strrchr(S("hello"), C('z')));
|
EXPECT_STREQ("hello☻♥", gc(utf16toutf8(u"hello☻♥", -1, 0)));
|
||||||
EXPECT_STREQ(S("lo"), strrchr(S("hello"), C('l')));
|
EXPECT_STREQ("hello☻♥hello☻♥h", gc(utf16toutf8(u"hello☻♥hello☻♥h", -1, 0)));
|
||||||
EXPECT_STREQ(S("llo"), strchr(S("hello"), C('l')));
|
EXPECT_STREQ("hello☻♥hello☻♥hi", gc(utf16toutf8(u"hello☻♥hello☻♥hi", -1, 0)));
|
||||||
EXPECT_STREQ(S("hello"), strrchr(S("hello"), C('h')));
|
EXPECT_STREQ("hello☻♥hello☻♥hello☻♥hello☻♥hello☻♥",
|
||||||
EXPECT_STREQ(S("ello"), strrchr(S("hello"), C('e')));
|
gc(utf16toutf8(u"hello☻♥hello☻♥hello☻♥hello☻♥hello☻♥", -1, 0)));
|
||||||
EXPECT_STREQ(S("o"), strrchr(S("hello"), C('o')));
|
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) {
|
BENCH(utf16toutf8, bench) {
|
||||||
EXPECT_EQ(NULL, strrchr(S("--------------------------------"), C('x')));
|
size_t n;
|
||||||
EXPECT_STREQ(S("x"), strrchr(S("-------------------------------x"), C('x')));
|
char16_t *h;
|
||||||
EXPECT_STREQ(S("x-------------------------------"),
|
h = utf8toutf16(kHyperion, kHyperionSize, &n);
|
||||||
strrchr(S("x-------------------------------"), C('x')));
|
EZBENCH2("utf16toutf8", donothing, free(utf16toutf8(h, n, 0)));
|
||||||
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')));
|
|
||||||
}
|
}
|
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"
|
#include "net/http/escape.h"
|
||||||
|
|
||||||
TEST(HasControlCodes, test) {
|
TEST(HasControlCodes, test) {
|
||||||
EXPECT_FALSE(
|
EXPECT_EQ(-1, HasControlCodes(kHyperion, kHyperionSize, kControlC0));
|
||||||
HasControlCodes(kHyperion, kHyperionSize, kControlC0 | kControlC1));
|
EXPECT_EQ(+2, HasControlCodes("hi\1", -1, kControlC0));
|
||||||
EXPECT_TRUE(HasControlCodes("hi\1", -1, kControlC0));
|
EXPECT_EQ(-1, HasControlCodes("hi\1", -1, kControlC1));
|
||||||
EXPECT_FALSE(HasControlCodes("hi\1", -1, kControlC1));
|
EXPECT_EQ(-1, HasControlCodes("hi there", -1, 0));
|
||||||
EXPECT_FALSE(HasControlCodes("hi there", -1, 0));
|
EXPECT_NE(-1, HasControlCodes("hi\tthere", -1, kControlWs));
|
||||||
EXPECT_TRUE(HasControlCodes("hi\tthere", -1, kControlWs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HasControlCodes, testDoesUtf8) {
|
TEST(HasControlCodes, testDoesUtf8) {
|
||||||
EXPECT_FALSE(HasControlCodes(u8"→", -1, kControlC0 | kControlC1));
|
EXPECT_EQ(-1, HasControlCodes(u8"→", -1, kControlC0 | kControlC1));
|
||||||
EXPECT_FALSE(HasControlCodes("\304\200", -1, kControlC0 | kControlC1));
|
EXPECT_EQ(-1, HasControlCodes("\304\200", -1, kControlC0 | kControlC1));
|
||||||
EXPECT_TRUE(HasControlCodes("\300\200", -1, kControlC0 | kControlC1));
|
EXPECT_NE(-1, HasControlCodes("\300\200", -1, kControlC0 | kControlC1));
|
||||||
EXPECT_FALSE(HasControlCodes("\300\200", -1, kControlC1));
|
EXPECT_EQ(-1, HasControlCodes("\300\200", -1, kControlC1));
|
||||||
EXPECT_TRUE(HasControlCodes("\302\202", -1, kControlC0 | kControlC1));
|
EXPECT_NE(-1, HasControlCodes("\302\202", -1, kControlC0 | kControlC1));
|
||||||
EXPECT_TRUE(HasControlCodes("\302\202", -1, kControlC1));
|
EXPECT_NE(-1, HasControlCodes("\302\202", -1, kControlC1));
|
||||||
EXPECT_FALSE(HasControlCodes("\302\202", -1, kControlC0));
|
EXPECT_EQ(-1, HasControlCodes("\302\202", -1, kControlC0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HasControlCodes, testHasLatin1FallbackBehavior) {
|
TEST(HasControlCodes, testHasLatin1FallbackBehavior) {
|
||||||
EXPECT_TRUE(HasControlCodes("\202", -1, kControlWs | kControlC1));
|
EXPECT_NE(-1, HasControlCodes("\202", -1, kControlWs | kControlC1));
|
||||||
EXPECT_FALSE(HasControlCodes("\202", -1, kControlC0));
|
EXPECT_EQ(-1, HasControlCodes("\202", -1, kControlC0));
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCH(HasControlCodes, bench) {
|
BENCH(HasControlCodes, bench) {
|
||||||
EZBENCH2("HasControlCodes", donothing,
|
EZBENCH2("HasControlCodes small", donothing, HasControlCodes("hello", -1, 0));
|
||||||
HasControlCodes(kHyperion, kHyperionSize, kControlWs));
|
EZBENCH2("HasControlCodes big", donothing,
|
||||||
|
HasControlCodes(kHyperion, kHyperionSize, kControlC1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,32 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/af.h"
|
||||||
#include "libc/sysv/consts/auxv.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/o.h"
|
||||||
|
#include "libc/sysv/consts/shut.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/sysv/consts/sock.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
|
#include "third_party/regex/regex.h"
|
||||||
/* TODO(jart): Finish this */
|
|
||||||
|
|
||||||
STATIC_YOINK("zip_uri_support");
|
STATIC_YOINK("zip_uri_support");
|
||||||
STATIC_YOINK("o/" MODE "/tool/net/redbean.com");
|
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) {
|
void SetUpOnce(void) {
|
||||||
return;
|
if (IsWindows()) return;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
char buf[512];
|
char buf[1024];
|
||||||
int fdin, fdout;
|
int fdin, fdout;
|
||||||
ASSERT_NE(-1, mkdir("bin", 0755));
|
ASSERT_NE(-1, mkdir("bin", 0755));
|
||||||
ASSERT_NE(-1, (fdin = open("zip:o/" MODE "/tool/net/redbean.com", O_RDONLY)));
|
ASSERT_NE(-1, (fdin = open("zip:o/" MODE "/tool/net/redbean.com", O_RDONLY)));
|
||||||
|
@ -45,32 +52,72 @@ void SetUp(void) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ASSERT_NE(-1, (n = read(fdin, buf, sizeof(buf))));
|
ASSERT_NE(-1, (n = read(fdin, buf, sizeof(buf))));
|
||||||
if (!n) break;
|
if (!n) break;
|
||||||
ASSERT_EQ(n, write(fdout, buf, sizeof(buf)));
|
ASSERT_EQ(n, write(fdout, buf, n));
|
||||||
}
|
}
|
||||||
close(fdout);
|
close(fdout);
|
||||||
close(fdin);
|
close(fdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(redbean, test) {
|
char *SendHttpRequest(const char *s) {
|
||||||
return;
|
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];
|
char portbuf[16];
|
||||||
int pid, port, pipefds[2];
|
int pid, pipefds[2];
|
||||||
sigset_t chldmask, savemask;
|
sigset_t chldmask, savemask;
|
||||||
sigaddset(&chldmask, SIGCHLD);
|
sigaddset(&chldmask, SIGCHLD);
|
||||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||||
ASSERT_NE(-1, pipe2(pipefds, O_CLOEXEC));
|
ASSERT_NE(-1, pipe(pipefds));
|
||||||
ASSERT_NE(-1, (pid = vfork()));
|
ASSERT_NE(-1, (pid = vfork()));
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
|
close(pipefds[0]);
|
||||||
dup2(pipefds[1], 1);
|
dup2(pipefds[1], 1);
|
||||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||||
execv("bin/redbean.com",
|
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);
|
_exit(127);
|
||||||
}
|
}
|
||||||
EXPECT_NE(-1, close(pipefds[1]));
|
EXPECT_NE(-1, close(pipefds[1]));
|
||||||
EXPECT_NE(-1, read(pipefds[0], portbuf, sizeof(portbuf)));
|
EXPECT_NE(-1, read(pipefds[0], portbuf, sizeof(portbuf)));
|
||||||
port = atoi(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, kill(pid, SIGTERM));
|
||||||
EXPECT_NE(-1, wait(0));
|
EXPECT_NE(-1, wait(0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,17 +29,21 @@ TEST_TOOL_NET_CHECKS = \
|
||||||
|
|
||||||
TEST_TOOL_NET_DIRECTDEPS = \
|
TEST_TOOL_NET_DIRECTDEPS = \
|
||||||
LIBC_CALLS \
|
LIBC_CALLS \
|
||||||
LIBC_STUBS \
|
|
||||||
LIBC_FMT \
|
LIBC_FMT \
|
||||||
LIBC_STDIO \
|
|
||||||
LIBC_INTRIN \
|
LIBC_INTRIN \
|
||||||
LIBC_NEXGEN32E \
|
LIBC_LOG \
|
||||||
LIBC_SYSV \
|
|
||||||
LIBC_MEM \
|
LIBC_MEM \
|
||||||
|
LIBC_NEXGEN32E \
|
||||||
LIBC_RUNTIME \
|
LIBC_RUNTIME \
|
||||||
LIBC_X \
|
LIBC_SOCK \
|
||||||
|
LIBC_STDIO \
|
||||||
|
LIBC_STR \
|
||||||
|
LIBC_STUBS \
|
||||||
|
LIBC_SYSV \
|
||||||
LIBC_TESTLIB \
|
LIBC_TESTLIB \
|
||||||
LIBC_ZIPOS
|
LIBC_X \
|
||||||
|
LIBC_ZIPOS \
|
||||||
|
THIRD_PARTY_REGEX
|
||||||
|
|
||||||
TEST_TOOL_NET_DEPS := \
|
TEST_TOOL_NET_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(TEST_TOOL_NET_DIRECTDEPS),$($(x))))
|
$(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 ISRIP 0x00080000
|
||||||
#define ISREG 0x00100000
|
#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 IS(P, N, S) (N == sizeof(S) - 1 && !strncasecmp(P, S, sizeof(S) - 1))
|
||||||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||||
#define READ128BE(S) ((unsigned __int128)READ64BE(S) << 64 | READ64BE((S) + 8))
|
#define READ128BE(S) ((unsigned __int128)READ64BE(S) << 64 | READ64BE((S) + 8))
|
||||||
|
@ -152,29 +157,29 @@ struct As {
|
||||||
bool inhibiterr;
|
bool inhibiterr;
|
||||||
bool inhibitwarn;
|
bool inhibitwarn;
|
||||||
struct Ints {
|
struct Ints {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
long *p;
|
long *p;
|
||||||
} ints;
|
} ints;
|
||||||
struct Floats {
|
struct Floats {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
long double *p;
|
long double *p;
|
||||||
} floats;
|
} floats;
|
||||||
struct Slices {
|
struct Slices {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Slice {
|
struct Slice {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
char *p;
|
char *p;
|
||||||
} * p;
|
} * p;
|
||||||
} slices;
|
} slices;
|
||||||
struct Sauces {
|
struct Sauces {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Sauce {
|
struct Sauce {
|
||||||
unsigned path; // strings
|
unsigned path; // strings
|
||||||
unsigned line; // 1-indexed
|
unsigned line; // 1-indexed
|
||||||
} * p;
|
} * p;
|
||||||
} sauces;
|
} sauces;
|
||||||
struct Things {
|
struct Things {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Thing {
|
struct Thing {
|
||||||
enum ThingType {
|
enum ThingType {
|
||||||
TT_INT,
|
TT_INT,
|
||||||
|
@ -189,7 +194,7 @@ struct As {
|
||||||
} * p;
|
} * p;
|
||||||
} things;
|
} things;
|
||||||
struct Sections {
|
struct Sections {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Section {
|
struct Section {
|
||||||
unsigned name; // strings
|
unsigned name; // strings
|
||||||
int flags;
|
int flags;
|
||||||
|
@ -199,7 +204,7 @@ struct As {
|
||||||
} * p;
|
} * p;
|
||||||
} sections;
|
} sections;
|
||||||
struct Symbols {
|
struct Symbols {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
bool isused;
|
bool isused;
|
||||||
unsigned char stb; // STB_*
|
unsigned char stb; // STB_*
|
||||||
|
@ -220,7 +225,7 @@ struct As {
|
||||||
} * p;
|
} * p;
|
||||||
} symbolindex;
|
} symbolindex;
|
||||||
struct Labels {
|
struct Labels {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Label {
|
struct Label {
|
||||||
unsigned id;
|
unsigned id;
|
||||||
unsigned tok; // things
|
unsigned tok; // things
|
||||||
|
@ -228,7 +233,7 @@ struct As {
|
||||||
} * p;
|
} * p;
|
||||||
} labels;
|
} labels;
|
||||||
struct Relas {
|
struct Relas {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Rela {
|
struct Rela {
|
||||||
bool isdead;
|
bool isdead;
|
||||||
int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...}
|
int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...}
|
||||||
|
@ -239,7 +244,7 @@ struct As {
|
||||||
} * p;
|
} * p;
|
||||||
} relas;
|
} relas;
|
||||||
struct Exprs {
|
struct Exprs {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
struct Expr {
|
struct Expr {
|
||||||
enum ExprKind {
|
enum ExprKind {
|
||||||
EX_INT, // integer
|
EX_INT, // integer
|
||||||
|
@ -277,11 +282,11 @@ struct As {
|
||||||
} * p;
|
} * p;
|
||||||
} exprs;
|
} exprs;
|
||||||
struct Strings {
|
struct Strings {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
char **p;
|
char **p;
|
||||||
} strings, incpaths;
|
} strings, incpaths;
|
||||||
struct SectionStack {
|
struct SectionStack {
|
||||||
unsigned long n;
|
unsigned long n, c;
|
||||||
int *p;
|
int *p;
|
||||||
} sectionstack;
|
} sectionstack;
|
||||||
};
|
};
|
||||||
|
@ -805,8 +810,7 @@ static void Tokenize(struct As *a, int path) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
buf.n = 0;
|
memset(&buf, 0, sizeof(buf));
|
||||||
buf.p = NULL;
|
|
||||||
for (i = 1; (c = p[i++]);) {
|
for (i = 1; (c = p[i++]);) {
|
||||||
if (c == '"') break;
|
if (c == '"') break;
|
||||||
c = ReadCharLiteral(&buf, c, p, &i);
|
c = ReadCharLiteral(&buf, c, p, &i);
|
||||||
|
|
|
@ -239,7 +239,11 @@ void LoadRelationships(int argc, char *argv[]) {
|
||||||
buf += PAGESIZE;
|
buf += PAGESIZE;
|
||||||
buf[-1] = '\n';
|
buf[-1] = '\n';
|
||||||
for (i = optind; i < argc; ++i) {
|
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) {
|
while (getline(&line, &linecap, finpaths) != -1) {
|
||||||
src = chomp(line);
|
src = chomp(line);
|
||||||
if (ShouldSkipSource(src)) continue;
|
if (ShouldSkipSource(src)) continue;
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "libc/sysv/consts/inaddr.h"
|
#include "libc/sysv/consts/inaddr.h"
|
||||||
#include "libc/sysv/consts/ipproto.h"
|
#include "libc/sysv/consts/ipproto.h"
|
||||||
#include "libc/sysv/consts/itimer.h"
|
#include "libc/sysv/consts/itimer.h"
|
||||||
|
#include "libc/sysv/consts/madv.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/msync.h"
|
#include "libc/sysv/consts/msync.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
@ -241,6 +242,7 @@ static struct Assets {
|
||||||
static struct Shared {
|
static struct Shared {
|
||||||
int workers;
|
int workers;
|
||||||
long double nowish;
|
long double nowish;
|
||||||
|
long double lastreindex;
|
||||||
long double lastmeltdown;
|
long double lastmeltdown;
|
||||||
char currentdate[32];
|
char currentdate[32];
|
||||||
struct rusage server;
|
struct rusage server;
|
||||||
|
@ -318,6 +320,7 @@ static struct Shared {
|
||||||
long readresets;
|
long readresets;
|
||||||
long readtimeouts;
|
long readtimeouts;
|
||||||
long redirects;
|
long redirects;
|
||||||
|
long reindexes;
|
||||||
long reloads;
|
long reloads;
|
||||||
long rewrites;
|
long rewrites;
|
||||||
long serveroptions;
|
long serveroptions;
|
||||||
|
@ -379,13 +382,14 @@ static uint32_t clientaddrsize;
|
||||||
static lua_State *L;
|
static lua_State *L;
|
||||||
static size_t zsize;
|
static size_t zsize;
|
||||||
static char *content;
|
static char *content;
|
||||||
static uint8_t *cdir;
|
|
||||||
static uint8_t *zmap;
|
static uint8_t *zmap;
|
||||||
|
static uint8_t *zcdir;
|
||||||
static size_t hdrsize;
|
static size_t hdrsize;
|
||||||
static size_t msgsize;
|
static size_t msgsize;
|
||||||
static size_t amtread;
|
static size_t amtread;
|
||||||
static char *extrahdrs;
|
static char *extrahdrs;
|
||||||
static char *luaheaderp;
|
static char *luaheaderp;
|
||||||
|
static const char *zpath;
|
||||||
static const char *brand;
|
static const char *brand;
|
||||||
static const char *pidpath;
|
static const char *pidpath;
|
||||||
static const char *logpath;
|
static const char *logpath;
|
||||||
|
@ -408,6 +412,7 @@ static struct Url url;
|
||||||
static struct HttpRequest msg;
|
static struct HttpRequest msg;
|
||||||
static char slashpath[PATH_MAX];
|
static char slashpath[PATH_MAX];
|
||||||
|
|
||||||
|
static struct stat zst;
|
||||||
static long double startread;
|
static long double startread;
|
||||||
static long double lastrefresh;
|
static long double lastrefresh;
|
||||||
static long double startserver;
|
static long double startserver;
|
||||||
|
@ -1125,7 +1130,7 @@ static void Daemonize(void) {
|
||||||
if ((pid = fork()) > 0) _exit(0);
|
if ((pid = fork()) > 0) _exit(0);
|
||||||
umask(0);
|
umask(0);
|
||||||
if (pidpath) {
|
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));
|
write(fd, ibuf, uint64toarray_radix10(getpid(), ibuf));
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
@ -1242,7 +1247,8 @@ static void ReportWorkerResources(int pid, struct rusage *ru) {
|
||||||
AppendResourceReport(ru, "\n");
|
AppendResourceReport(ru, "\n");
|
||||||
if (outbuf.n) {
|
if (outbuf.n) {
|
||||||
if ((s = IndentLines(outbuf.p, outbuf.n - 1, 0, 1))) {
|
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);
|
free(s);
|
||||||
}
|
}
|
||||||
ClearOutput();
|
ClearOutput();
|
||||||
|
@ -1411,21 +1417,20 @@ static bool IsCompressionMethodSupported(int method) {
|
||||||
|
|
||||||
static void IndexAssets(void) {
|
static void IndexAssets(void) {
|
||||||
int64_t lm;
|
int64_t lm;
|
||||||
uint64_t cf, lf;
|
uint64_t cf;
|
||||||
struct Asset *p;
|
struct Asset *p;
|
||||||
uint32_t i, n, m, step, hash;
|
uint32_t i, n, m, step, hash;
|
||||||
CHECK_GE(HASH_LOAD_FACTOR, 2);
|
CHECK_GE(HASH_LOAD_FACTOR, 2);
|
||||||
CHECK(READ32LE(cdir) == kZipCdir64HdrMagic ||
|
CHECK(READ32LE(zcdir) == kZipCdir64HdrMagic ||
|
||||||
READ32LE(cdir) == kZipCdirHdrMagic);
|
READ32LE(zcdir) == kZipCdirHdrMagic);
|
||||||
n = GetZipCdirRecords(cdir);
|
n = GetZipCdirRecords(zcdir);
|
||||||
m = roundup2pow(MAX(1, n) * HASH_LOAD_FACTOR);
|
m = roundup2pow(MAX(1, n) * HASH_LOAD_FACTOR);
|
||||||
p = xcalloc(m, sizeof(struct Asset));
|
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));
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
lf = GetZipCfileOffset(zmap + cf);
|
if (!IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf))) {
|
||||||
if (!IsCompressionMethodSupported(ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf))) {
|
|
||||||
LOGF("don't understand zip compression method %d used by %`'.*s",
|
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));
|
ZIP_CFILE_NAMESIZE(zmap + cf), ZIP_CFILE_NAME(zmap + cf));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1437,8 +1442,8 @@ static void IndexAssets(void) {
|
||||||
} while (p[i].hash);
|
} while (p[i].hash);
|
||||||
lm = GetZipCfileLastModified(zmap + cf);
|
lm = GetZipCfileLastModified(zmap + cf);
|
||||||
p[i].hash = hash;
|
p[i].hash = hash;
|
||||||
p[i].lf = lf;
|
|
||||||
p[i].cf = cf;
|
p[i].cf = cf;
|
||||||
|
p[i].lf = GetZipCfileOffset(zmap + cf);
|
||||||
p[i].istext = !!(ZIP_CFILE_INTERNALATTRIBUTES(zmap + cf) & kZipIattrText);
|
p[i].istext = !!(ZIP_CFILE_INTERNALATTRIBUTES(zmap + cf) & kZipIattrText);
|
||||||
p[i].lastmodified = lm;
|
p[i].lastmodified = lm;
|
||||||
p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm);
|
p[i].lastmodifiedstr = FormatUnixHttpDateTime(xmalloc(30), lm);
|
||||||
|
@ -1447,17 +1452,17 @@ static void IndexAssets(void) {
|
||||||
assets.n = m;
|
assets.n = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OpenZip(const char *path) {
|
static void OpenZip(void) {
|
||||||
int fd;
|
int fd;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
struct stat st;
|
if (zmap) munmap(zmap, zsize);
|
||||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
|
CHECK_NE(-1, (fd = open(zpath, O_RDONLY)));
|
||||||
CHECK_NE(-1, fstat(fd, &st));
|
CHECK_NE(-1, fstat(fd, &zst));
|
||||||
CHECK((zsize = st.st_size));
|
CHECK((zsize = zst.st_size));
|
||||||
CHECK_NE(MAP_FAILED,
|
CHECK_NE(MAP_FAILED,
|
||||||
(zmap = mmap(NULL, zsize, PROT_READ, MAP_SHARED, fd, 0)));
|
(zmap = mmap(NULL, zsize, PROT_READ, MAP_SHARED, fd, 0)));
|
||||||
CHECK_NOTNULL((cdir = GetZipCdir(zmap, zsize)));
|
CHECK_NOTNULL((zcdir = GetZipCdir(zmap, zsize)));
|
||||||
if (endswith(path, ".com.dbg") && (p = memmem(zmap, zsize, "MZqFpD", 6))) {
|
if (endswith(zpath, ".com.dbg") && (p = memmem(zmap, zsize, "MZqFpD", 6))) {
|
||||||
zsize -= p - zmap;
|
zsize -= p - zmap;
|
||||||
zmap = p;
|
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);
|
i = (hash + (step * (step + 1)) >> 1) & (assets.n - 1);
|
||||||
if (!assets.p[i].hash) return NULL;
|
if (!assets.p[i].hash) return NULL;
|
||||||
if (hash == assets.p[i].hash &&
|
if (hash == assets.p[i].hash &&
|
||||||
pathlen == ZIP_LFILE_NAMESIZE(zmap + assets.p[i].lf) &&
|
pathlen == ZIP_CFILE_NAMESIZE(zmap + assets.p[i].cf) &&
|
||||||
memcmp(path, ZIP_LFILE_NAME(zmap + assets.p[i].lf), pathlen) == 0) {
|
memcmp(path, ZIP_CFILE_NAME(zmap + assets.p[i].cf), pathlen) == 0) {
|
||||||
return &assets.p[i];
|
return &assets.p[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1695,7 +1700,7 @@ static void AppendLogo(void) {
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
if ((a = GetAsset("/redbean.png", 12)) && (p = LoadAsset(a, &n))) {
|
||||||
q = EncodeBase64(p, n, &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);
|
AppendData(q, n);
|
||||||
Append("\">\r\n");
|
Append("\">\r\n");
|
||||||
free(q);
|
free(q);
|
||||||
|
@ -2030,13 +2035,13 @@ static int GetOctalWidth(int x) {
|
||||||
return !x ? 1 : x < 8 ? 2 : 1 + bsr(x) / 3;
|
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;
|
long percent;
|
||||||
if (ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf) == kZipCompressionNone) {
|
if (ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf) == kZipCompressionNone) {
|
||||||
return "n/a";
|
return "n/a";
|
||||||
} else {
|
} else {
|
||||||
percent = lround(100 - (double)GetZipLfileCompressedSize(zmap + lf) /
|
percent = lround(100 - (double)GetZipCfileCompressedSize(zmap + cf) /
|
||||||
GetZipLfileUncompressedSize(zmap + lf) * 100);
|
GetZipCfileUncompressedSize(zmap + cf) * 100);
|
||||||
sprintf(rb, "%ld%%", MIN(999, MAX(-999, percent)));
|
sprintf(rb, "%ld%%", MIN(999, MAX(-999, percent)));
|
||||||
return rb;
|
return rb;
|
||||||
}
|
}
|
||||||
|
@ -2080,23 +2085,23 @@ td { padding-right: 3em; }\r\n\
|
||||||
"<hr>\r\n"
|
"<hr>\r\n"
|
||||||
"</header>\r\n"
|
"</header>\r\n"
|
||||||
"<pre>\r\n",
|
"<pre>\r\n",
|
||||||
strnlen(GetZipCdirComment(cdir), GetZipCdirCommentSize(cdir)),
|
strnlen(GetZipCdirComment(zcdir), GetZipCdirCommentSize(zcdir)),
|
||||||
GetZipCdirComment(cdir));
|
GetZipCdirComment(zcdir));
|
||||||
memset(w, 0, sizeof(w));
|
memset(w, 0, sizeof(w));
|
||||||
n = GetZipCdirRecords(cdir);
|
n = GetZipCdirRecords(zcdir);
|
||||||
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));
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
lf = GetZipCfileOffset(zmap + cf);
|
lf = GetZipCfileOffset(zmap + cf);
|
||||||
path = GetAssetPath(cf, &pathlen);
|
path = GetAssetPath(cf, &pathlen);
|
||||||
if (!IsHiddenPath(path)) {
|
if (!IsHiddenPath(path)) {
|
||||||
w[0] = min(80, max(w[0], strwidth(path, 0) + 2));
|
w[0] = min(80, max(w[0], strwidth(path, 0) + 2));
|
||||||
w[1] = max(w[1], GetOctalWidth(GetZipCfileMode(zmap + cf)));
|
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);
|
free(path);
|
||||||
}
|
}
|
||||||
n = GetZipCdirRecords(cdir);
|
n = GetZipCdirRecords(zcdir);
|
||||||
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));
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
lf = GetZipCfileOffset(zmap + cf);
|
lf = GetZipCfileOffset(zmap + cf);
|
||||||
path = GetAssetPath(cf, &pathlen);
|
path = GetAssetPath(cf, &pathlen);
|
||||||
|
@ -2113,17 +2118,17 @@ td { padding-right: 3em; }\r\n\
|
||||||
localtime_r(&lastmod, &tm);
|
localtime_r(&lastmod, &tm);
|
||||||
strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S %Z", &tm);
|
strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S %Z", &tm);
|
||||||
if (IsCompressionMethodSupported(
|
if (IsCompressionMethodSupported(
|
||||||
ZIP_LFILE_COMPRESSIONMETHOD(zmap + lf)) &&
|
ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf)) &&
|
||||||
IsAcceptablePath(path, pathlen)) {
|
IsAcceptablePath(path, pathlen)) {
|
||||||
Append("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
Append("<a href=\"%.*s\">%-*.*s</a> %s %0*o %4s %,*ld %'s\r\n",
|
||||||
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
rn[2], rp[2], w[0], rn[4], rp[4], tb, w[1],
|
||||||
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, lf),
|
GetZipCfileMode(zmap + cf), DescribeCompressionRatio(rb, cf),
|
||||||
w[2], GetZipLfileUncompressedSize(zmap + lf), rp[3]);
|
w[2], GetZipCfileUncompressedSize(zmap + cf), rp[3]);
|
||||||
} else {
|
} else {
|
||||||
Append("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
Append("%-*.*s %s %0*o %4s %,*ld %'s\r\n", w[0], rn[4], rp[4], tb,
|
||||||
w[1], GetZipCfileMode(zmap + cf),
|
w[1], GetZipCfileMode(zmap + cf),
|
||||||
DescribeCompressionRatio(rb, lf), w[2],
|
DescribeCompressionRatio(rb, cf), w[2],
|
||||||
GetZipLfileUncompressedSize(zmap + lf), rp[3]);
|
GetZipCfileUncompressedSize(zmap + cf), rp[3]);
|
||||||
}
|
}
|
||||||
free(rp[4]);
|
free(rp[4]);
|
||||||
free(rp[3]);
|
free(rp[3]);
|
||||||
|
@ -2299,6 +2304,7 @@ static char *ServeStatusz(void) {
|
||||||
AppendLong1("readresets", shared->readresets);
|
AppendLong1("readresets", shared->readresets);
|
||||||
AppendLong1("readtimeouts", shared->readtimeouts);
|
AppendLong1("readtimeouts", shared->readtimeouts);
|
||||||
AppendLong1("redirects", shared->redirects);
|
AppendLong1("redirects", shared->redirects);
|
||||||
|
AppendLong1("reindexes", shared->reindexes);
|
||||||
AppendLong1("reloads", shared->reloads);
|
AppendLong1("reloads", shared->reloads);
|
||||||
AppendLong1("rewrites", shared->rewrites);
|
AppendLong1("rewrites", shared->rewrites);
|
||||||
AppendLong1("serveroptions", shared->serveroptions);
|
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) {
|
static const char *LuaCheckPath(lua_State *L, int idx, size_t *pathlen) {
|
||||||
const char *path;
|
const char *path;
|
||||||
if (lua_isnoneornil(L, idx)) {
|
if (lua_isnoneornil(L, idx)) {
|
||||||
|
@ -2951,7 +2964,7 @@ static int LuaSetHeader(lua_State *L) {
|
||||||
}
|
}
|
||||||
switch (h) {
|
switch (h) {
|
||||||
case kHttpConnection:
|
case kHttpConnection:
|
||||||
if (evallen != 5 || memcmp(eval, "close", 5)) {
|
if (evallen != 5 || memcasecmp(eval, "close", 5)) {
|
||||||
luaL_argerror(L, 2, "unsupported");
|
luaL_argerror(L, 2, "unsupported");
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
@ -3162,7 +3175,7 @@ static int LuaHasControlCodes(lua_State *L) {
|
||||||
const char *p;
|
const char *p;
|
||||||
p = luaL_checklstring(L, 1, &n);
|
p = luaL_checklstring(L, 1, &n);
|
||||||
f = LuaCheckControlFlags(L, 2);
|
f = LuaCheckControlFlags(L, 2);
|
||||||
lua_pushboolean(L, HasControlCodes(p, n, f));
|
lua_pushboolean(L, HasControlCodes(p, n, f) != -1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3446,8 +3459,8 @@ static int LuaGetZipPaths(lua_State *L) {
|
||||||
size_t i, n, pathlen;
|
size_t i, n, pathlen;
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
i = 0;
|
i = 0;
|
||||||
n = GetZipCdirRecords(cdir);
|
n = GetZipCdirRecords(zcdir);
|
||||||
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));
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
path = GetAssetPath(cf, &pathlen);
|
path = GetAssetPath(cf, &pathlen);
|
||||||
lua_pushlstring(L, path, pathlen);
|
lua_pushlstring(L, path, pathlen);
|
||||||
|
@ -3847,13 +3860,31 @@ static void LuaReload(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleReload(void) {
|
static void HandleReload(void) {
|
||||||
|
LockInc(&shared->reloads);
|
||||||
LOGF("reloading");
|
LOGF("reloading");
|
||||||
|
Reindex();
|
||||||
LuaReload();
|
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) {
|
static void HandleHeartbeat(void) {
|
||||||
if (nowl() - lastrefresh > 60 * 60) RefreshTime();
|
if (nowl() - lastrefresh > 60 * 60) RefreshTime();
|
||||||
UpdateCurrentDate(nowl());
|
UpdateCurrentDate(nowl());
|
||||||
|
if (ZipCdirChanged()) {
|
||||||
|
shared->lastreindex = nowl();
|
||||||
|
kill(0, SIGUSR1);
|
||||||
|
}
|
||||||
getrusage(RUSAGE_SELF, &shared->server);
|
getrusage(RUSAGE_SELF, &shared->server);
|
||||||
#ifndef STATIC
|
#ifndef STATIC
|
||||||
LuaRun("/.heartbeat.lua");
|
LuaRun("/.heartbeat.lua");
|
||||||
|
@ -4344,6 +4375,10 @@ static void HandleMessages(void) {
|
||||||
LogClose(DescribeClose());
|
LogClose(DescribeClose());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (invalidated) {
|
||||||
|
HandleReload();
|
||||||
|
invalidated = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (msgsize == amtread) {
|
if (msgsize == amtread) {
|
||||||
amtread = 0;
|
amtread = 0;
|
||||||
|
@ -4363,6 +4398,10 @@ static void HandleMessages(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CollectGarbage();
|
CollectGarbage();
|
||||||
|
if (invalidated) {
|
||||||
|
HandleReload();
|
||||||
|
invalidated = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4485,7 +4524,7 @@ static void TuneSockets(void) {
|
||||||
setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RestoreApe(const char *prog) {
|
static void RestoreApe(void) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t n;
|
size_t n;
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
|
@ -4493,7 +4532,7 @@ static void RestoreApe(const char *prog) {
|
||||||
if (IsWindows()) return; /* TODO */
|
if (IsWindows()) return; /* TODO */
|
||||||
if (IsOpenbsd()) return; /* TODO */
|
if (IsOpenbsd()) return; /* TODO */
|
||||||
if (IsNetbsd()) return; /* TODO */
|
if (IsNetbsd()) return; /* TODO */
|
||||||
if (endswith(prog, ".com.dbg")) return;
|
if (endswith(zpath, ".com.dbg")) return;
|
||||||
close(OpenExecutable());
|
close(OpenExecutable());
|
||||||
if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) {
|
if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) {
|
||||||
mprotect(ape_rom_vaddr, PAGESIZE, PROT_READ | PROT_WRITE);
|
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;
|
uint32_t addrsize;
|
||||||
gmtoff = GetGmtOffset((lastrefresh = startserver = nowl()));
|
gmtoff = GetGmtOffset((lastrefresh = startserver = nowl()));
|
||||||
CHECK_GT(CLK_TCK, 0);
|
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),
|
(shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE),
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
|
||||||
-1, 0)));
|
-1, 0)));
|
||||||
OpenZip(prog);
|
zpath = (const char *)getauxval(AT_EXECFN);
|
||||||
|
OpenZip();
|
||||||
IndexAssets();
|
IndexAssets();
|
||||||
RestoreApe(prog);
|
RestoreApe();
|
||||||
SetDefaults();
|
SetDefaults();
|
||||||
GetOpts(argc, argv);
|
GetOpts(argc, argv);
|
||||||
LuaInit();
|
LuaInit();
|
||||||
|
@ -4530,9 +4570,6 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
||||||
xsigaction(SIGALRM, OnAlrm, 0, 0, 0);
|
xsigaction(SIGALRM, OnAlrm, 0, 0, 0);
|
||||||
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
|
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
|
||||||
/* TODO(jart): SIGXCPU and SIGXFSZ */
|
/* TODO(jart): SIGXCPU and SIGXFSZ */
|
||||||
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
|
||||||
heartless = true;
|
|
||||||
}
|
|
||||||
server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
server = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
||||||
CHECK_NE(-1, server);
|
CHECK_NE(-1, server);
|
||||||
TuneSockets();
|
TuneSockets();
|
||||||
|
@ -4556,16 +4593,23 @@ void RedBean(int argc, char *argv[], const char *prog) {
|
||||||
printf("%d\n", ntohs(serveraddr.sin_port));
|
printf("%d\n", ntohs(serveraddr.sin_port));
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
if (daemonize) Daemonize();
|
if (daemonize) {
|
||||||
|
Daemonize();
|
||||||
|
} else {
|
||||||
|
setpgid(getpid(), getpid());
|
||||||
|
}
|
||||||
|
if (setitimer(ITIMER_REAL, &kHeartbeat, NULL) == -1) {
|
||||||
|
heartless = true;
|
||||||
|
}
|
||||||
UpdateCurrentDate(nowl());
|
UpdateCurrentDate(nowl());
|
||||||
freelist.c = 8;
|
freelist.c = 8;
|
||||||
freelist.p = xcalloc(freelist.c, sizeof(*freelist.p));
|
freelist.p = xcalloc(freelist.c, sizeof(*freelist.p));
|
||||||
unmaplist.c = 1;
|
unmaplist.c = 1;
|
||||||
unmaplist.p = xcalloc(unmaplist.c, sizeof(*unmaplist.p));
|
unmaplist.p = xcalloc(unmaplist.c, sizeof(*unmaplist.p));
|
||||||
hdrbuf.n = 4 * 1024;
|
hdrbuf.n = 4 * 1024;
|
||||||
hdrbuf.p = xvalloc(hdrbuf.n);
|
hdrbuf.p = xmalloc(hdrbuf.n);
|
||||||
inbuf.n = maxpayloadsize;
|
inbuf.n = maxpayloadsize;
|
||||||
inbuf.p = xvalloc(inbuf.n);
|
inbuf.p = xmalloc(inbuf.n);
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
if (zombied) {
|
if (zombied) {
|
||||||
ReapZombies();
|
ReapZombies();
|
||||||
|
@ -4603,6 +4647,6 @@ int main(int argc, char *argv[]) {
|
||||||
setenv("GDB", "", true);
|
setenv("GDB", "", true);
|
||||||
showcrashreports();
|
showcrashreports();
|
||||||
}
|
}
|
||||||
RedBean(argc, argv, (const char *)getauxval(AT_EXECFN));
|
RedBean(argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -428,6 +428,7 @@ static void OnUnzoom(long y, long x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnMouseLeftDrag(long y, long x) {
|
static void OnMouseLeftDrag(long y, long x) {
|
||||||
|
int i;
|
||||||
if (y == save_y && x == save_x) return;
|
if (y == save_y && x == save_x) return;
|
||||||
save_y = y;
|
save_y = y;
|
||||||
save_x = x;
|
save_x = x;
|
||||||
|
@ -440,7 +441,10 @@ static void OnMouseLeftDrag(long y, long x) {
|
||||||
if (erase) {
|
if (erase) {
|
||||||
Unset(y, x);
|
Unset(y, x);
|
||||||
} else {
|
} 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