mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Improve redbean
- Improve serialization - Add Benchmark() API to redbean - Refactor UNIX API to be assert() friendly - Make the redbean Lua REPL print data structures - Fix recent regressions in linenoise reverse search - Add -i flag so redbean can be a language interpreter
This commit is contained in:
parent
2046c0d2ae
commit
451e3f73d9
74 changed files with 1781 additions and 1024 deletions
|
@ -119,6 +119,9 @@ int fsync(int);
|
|||
int ftruncate(int, int64_t);
|
||||
int getdents(unsigned, void *, unsigned, long *);
|
||||
int getdomainname(char *, size_t);
|
||||
int getegid(void) nosideeffect;
|
||||
int geteuid(void) nosideeffect;
|
||||
int getgid(void) nosideeffect;
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int);
|
||||
|
@ -130,6 +133,7 @@ int getrlimit(int, struct rlimit *);
|
|||
int getrusage(int, struct rusage *);
|
||||
int getsid(int) nosideeffect;
|
||||
int gettid(void);
|
||||
int getuid(void) nosideeffect;
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int link(const char *, const char *) dontthrow;
|
||||
|
@ -196,6 +200,7 @@ int sysinfo(struct sysinfo *);
|
|||
int touch(const char *, uint32_t);
|
||||
int truncate(const char *, uint64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
int umask(int);
|
||||
int uname(struct utsname *);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
|
@ -226,11 +231,6 @@ ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
|||
ssize_t vmsplice(int, const struct iovec *, int64_t, uint32_t);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
struct dirent *readdir(DIR *);
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
uint32_t getuid(void) nosideeffect;
|
||||
uint32_t umask(uint32_t);
|
||||
void rewinddir(DIR *);
|
||||
void sync(void);
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ o/$(MODE)/libc/calls/execlp.o \
|
|||
o/$(MODE)/libc/calls/execve-nt.o \
|
||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||
o/$(MODE)/libc/calls/readlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/describeopenflags.greg.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
|
38
libc/calls/describeclockname.c
Normal file
38
libc/calls/describeclockname.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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 2022 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/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
|
||||
/**
|
||||
* Describes clock_gettime() clock argument.
|
||||
*/
|
||||
char *DescribeClockName(int x) {
|
||||
int i;
|
||||
char *s;
|
||||
_Alignas(char) static char buf[32];
|
||||
if ((s = GetMagnumStr(kClockNames, x))) {
|
||||
stpcpy(stpcpy(buf, "CLOCK_"), s);
|
||||
return buf;
|
||||
} else {
|
||||
FormatInt32(buf, x);
|
||||
return buf;
|
||||
}
|
||||
}
|
41
libc/calls/describeopenflags.greg.c
Normal file
41
libc/calls/describeopenflags.greg.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- 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 2022 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/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
|
||||
/**
|
||||
* Describes clock_gettime() clock argument.
|
||||
*/
|
||||
char *DescribeOpenFlags(int x) {
|
||||
char *s;
|
||||
int i, n;
|
||||
struct DescribeFlags *d;
|
||||
_Alignas(char) static char openflags[128];
|
||||
// TODO(jart): unify DescribeFlags and MagnumStr data structures
|
||||
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR;) ++n;
|
||||
d = alloca(n * sizeof(struct DescribeFlags));
|
||||
for (i = 0; i < n; ++i) {
|
||||
d[i].flag = MAGNUM_NUMBER(kOpenFlags, i);
|
||||
d[i].name = MAGNUM_STRING(kOpenFlags, i);
|
||||
}
|
||||
return DescribeFlags(openflags, sizeof(openflags), d, n, "O_", x);
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
int32_t sys_fstatat(int32_t dirfd, const char *path, struct stat *st,
|
||||
int32_t flags) {
|
||||
int rc;
|
||||
void *p;
|
||||
union metastat ms;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* Returns effective group ID of calling process.
|
||||
* @return group id
|
||||
*/
|
||||
uint32_t getegid(void) {
|
||||
int getegid(void) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_getegid();
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* Returns effective user ID of calling process.
|
||||
* @return user id
|
||||
*/
|
||||
uint32_t geteuid(void) {
|
||||
int geteuid(void) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_geteuid();
|
||||
|
|
|
@ -51,7 +51,7 @@ static textwindows dontinline uint32_t GetUserNameHash(void) {
|
|||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
uint32_t getuid(void) {
|
||||
int getuid(void) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_getuid();
|
||||
|
@ -71,7 +71,7 @@ uint32_t getuid(void) {
|
|||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
uint32_t getgid(void) {
|
||||
int getgid(void) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_getgid();
|
||||
|
|
47
libc/calls/kclocknames.S
Normal file
47
libc/calls/kclocknames.S
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*-*- 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/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e s
|
||||
.long \e - kClockNames
|
||||
.long 1f - kClockNames
|
||||
.rodata.str1.1
|
||||
1: .string "\s"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
.underrun
|
||||
kClockNames:
|
||||
.e CLOCK_REALTIME,"REALTIME"
|
||||
.e CLOCK_MONOTONIC,"MONOTONIC"
|
||||
.e CLOCK_MONOTONIC_RAW,"MONOTONIC_RAW"
|
||||
.e CLOCK_REALTIME_COARSE,"REALTIME_COARSE"
|
||||
.e CLOCK_MONOTONIC_COARSE,"MONOTONIC_COARSE"
|
||||
.e CLOCK_PROCESS_CPUTIME_ID,"PROCESS_CPUTIME_ID"
|
||||
.e CLOCK_TAI,"TAI"
|
||||
.e CLOCK_PROF,"PROF"
|
||||
.e CLOCK_BOOTTIME,"BOOTTIME"
|
||||
.e CLOCK_REALTIME_ALARM,"REALTIME_ALARM"
|
||||
.e CLOCK_BOOTTIME_ALARM,"BOOTTIME_ALARM"
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kClockNames,globl,hidden
|
||||
.overrun
|
64
libc/calls/kopenflags.S
Normal file
64
libc/calls/kopenflags.S
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*-*- 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/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e s
|
||||
.long \e - kOpenFlags
|
||||
.long 1f - kOpenFlags
|
||||
.rodata.str1.1
|
||||
1: .string "\s"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
.underrun
|
||||
kOpenFlags:
|
||||
.e O_RDWR,"RDWR" // order matters
|
||||
.e O_RDONLY,"RDONLY" //
|
||||
.e O_WRONLY,"WRONLY" //
|
||||
.e O_ACCMODE,"ACCMODE" // mask of prev three
|
||||
.e O_CREAT,"CREAT" //
|
||||
.e O_EXCL,"EXCL" //
|
||||
.e O_TRUNC,"TRUNC" //
|
||||
.e O_CLOEXEC,"CLOEXEC" //
|
||||
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
||||
.e O_APPEND,"APPEND" // weird on nt
|
||||
.e O_TMPFILE,"TMPFILE" // linux, windows
|
||||
.e O_NOFOLLOW,"NOFOLLOW" // unix
|
||||
.e O_SYNC,"SYNC" // unix
|
||||
.e O_ASYNC,"ASYNC" // unix
|
||||
.e O_NOCTTY,"NOCTTY" // unix
|
||||
.e O_NOATIME,"NOATIME" // linux
|
||||
.e O_EXEC,"EXEC" // free/openbsd
|
||||
.e O_SEARCH,"SEARCH" // free/netbsd
|
||||
.e O_DSYNC,"DSYNC" // linux/xnu/open/netbsd
|
||||
.e O_RSYNC,"RSYNC" // linux/open/netbsd
|
||||
.e O_PATH,"PATH" // linux
|
||||
.e O_VERIFY,"VERIFY" // freebsd
|
||||
.e O_SHLOCK,"SHLOCK" // bsd
|
||||
.e O_EXLOCK,"EXLOCK" // bsd
|
||||
.e O_RANDOM,"RANDOM" // windows
|
||||
.e O_SEQUENTIAL,"SEQUENTIAL" // windows
|
||||
.e O_COMPRESSED,"COMPRESSED" // windows
|
||||
.e O_INDEXED,"INDEXED" // windows
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kOpenFlags,globl,hidden
|
||||
.overrun
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -74,7 +75,8 @@ int openat(int dirfd, const char *file, int flags, ...) {
|
|||
} else {
|
||||
rc = efault();
|
||||
}
|
||||
STRACE("openat(%s, %#s, %#x, %#o) → %d% m", __strace_dirfd(buf, dirfd), file,
|
||||
flags, (flags & (O_CREAT | O_TMPFILE)) ? mode : 0, rc);
|
||||
STRACE("openat(%s, %#s, %s, %#o) → %d% m", __strace_dirfd(buf, dirfd), file,
|
||||
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
* @return previous mask
|
||||
* @note always succeeds
|
||||
*/
|
||||
unsigned umask(unsigned newmask) {
|
||||
unsigned oldmask;
|
||||
int umask(int newmask) {
|
||||
int oldmask;
|
||||
if (!IsWindows()) {
|
||||
oldmask = sys_umask(newmask);
|
||||
} else {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e s
|
||||
|
@ -115,6 +116,6 @@ kErrnoDocs:
|
|||
.e ENOTRECOVERABLE,"State not recoverable"
|
||||
.e ENONET,"Machine is not on the network"
|
||||
.e ERESTART,"Interrupted system call should be restarted"
|
||||
.long -123
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kErrnoDocs,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e
|
||||
|
@ -27,7 +28,7 @@
|
|||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
.align 4
|
||||
.underrun
|
||||
kErrnoNames:
|
||||
.e EINVAL
|
||||
|
@ -116,6 +117,6 @@ kErrnoNames:
|
|||
.e ENONET
|
||||
.e ERESTART
|
||||
.e ENODATA
|
||||
.long -123
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kErrnoNames,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -1,22 +1,35 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_MAGNUMSTRS_H_
|
||||
|
||||
#define MAGNUM_TERMINATOR -123
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define MAGNUM_NUMBER(TABLE, INDEX) \
|
||||
*(const int *)((uintptr_t)TABLE + TABLE[INDEX].x)
|
||||
|
||||
#define MAGNUM_STRING(TABLE, INDEX) \
|
||||
(const char *)((uintptr_t)TABLE + TABLE[INDEX].s)
|
||||
|
||||
struct MagnumStr {
|
||||
int x, s;
|
||||
};
|
||||
|
||||
extern const struct MagnumStr kErrnoDocs[];
|
||||
extern const struct MagnumStr kErrnoNames[];
|
||||
extern const struct MagnumStr kIpOptnames[];
|
||||
extern const struct MagnumStr kSignalNames[];
|
||||
extern const struct MagnumStr kSockOptnames[];
|
||||
extern const struct MagnumStr kTcpOptnames[];
|
||||
hidden extern const struct MagnumStr kClockNames[];
|
||||
hidden extern const struct MagnumStr kErrnoDocs[];
|
||||
hidden extern const struct MagnumStr kErrnoNames[];
|
||||
hidden extern const struct MagnumStr kIpOptnames[];
|
||||
hidden extern const struct MagnumStr kOpenFlags[];
|
||||
hidden extern const struct MagnumStr kSignalNames[];
|
||||
hidden extern const struct MagnumStr kSockOptnames[];
|
||||
hidden extern const struct MagnumStr kTcpOptnames[];
|
||||
|
||||
const char *DescribeSockLevel(int);
|
||||
const char *DescribeSockOptname(int, int);
|
||||
const char *GetMagnumStr(const struct MagnumStr *, int);
|
||||
char *DescribeClockName(int) hidden;
|
||||
char *DescribeOpenFlags(int) hidden;
|
||||
char *DescribeSockLevel(int) hidden;
|
||||
char *DescribeSockOptname(int, int) hidden;
|
||||
char *GetMagnumStr(const struct MagnumStr *, int) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* Converts errno value to descriptive sentence.
|
||||
* @return non-null rodata string or null if not found
|
||||
*/
|
||||
const char *strerdoc(int x) {
|
||||
char *strerdoc(int x) {
|
||||
if (x) {
|
||||
return GetMagnumStr(kErrnoDocs, x);
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* Converts errno value to symbolic name.
|
||||
* @return non-null rodata string or null if not found
|
||||
*/
|
||||
const char *strerrno(int x) {
|
||||
char *strerrno(int x) {
|
||||
if (x) {
|
||||
return GetMagnumStr(kErrnoNames, x);
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
const char *DescribeMapFlags(int x) {
|
||||
static char mapflags[256];
|
||||
_Alignas(char) static char mapflags[256];
|
||||
const struct DescribeFlags kMapFlags[] = {
|
||||
{MAP_ANONYMOUS, "ANONYMOUS"}, //
|
||||
{MAP_PRIVATE, "PRIVATE"}, //
|
||||
|
|
|
@ -34,7 +34,7 @@ static const struct DescribeFlags kConsoleModeInputFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtConsoleModeInputFlags(uint32_t x) {
|
||||
static char consolemodeinputflags[256];
|
||||
_Alignas(char) static char consolemodeinputflags[256];
|
||||
return DescribeFlags(consolemodeinputflags, sizeof(consolemodeinputflags),
|
||||
kConsoleModeInputFlags, ARRAYLEN(kConsoleModeInputFlags),
|
||||
"kNtEnable", x);
|
||||
|
|
|
@ -29,7 +29,7 @@ static const struct DescribeFlags kConsoleModeOutputFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtConsoleModeOutputFlags(uint32_t x) {
|
||||
static char consolemodeoutputflags[128];
|
||||
_Alignas(char) static char consolemodeoutputflags[128];
|
||||
return DescribeFlags(consolemodeoutputflags, sizeof(consolemodeoutputflags),
|
||||
kConsoleModeOutputFlags,
|
||||
ARRAYLEN(kConsoleModeOutputFlags), "kNt", x);
|
||||
|
|
|
@ -64,7 +64,7 @@ static const struct DescribeFlags kFileAccessflags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtFileAccessFlags(uint32_t x) {
|
||||
static char ntfileaccessflags[512];
|
||||
_Alignas(char) static char ntfileaccessflags[512];
|
||||
return DescribeFlags(ntfileaccessflags, sizeof(ntfileaccessflags),
|
||||
kFileAccessflags, ARRAYLEN(kFileAccessflags), "kNt", x);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ static const struct DescribeFlags kFileFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtFileFlagsAndAttributes(uint32_t x) {
|
||||
static char ntfileflags[256];
|
||||
_Alignas(char) static char ntfileflags[256];
|
||||
if (x == -1u) return "-1u";
|
||||
return DescribeFlags(ntfileflags, sizeof(ntfileflags), kFileFlags,
|
||||
ARRAYLEN(kFileFlags), "kNtFile", x);
|
||||
|
|
|
@ -31,7 +31,7 @@ static const struct DescribeFlags kFileMapFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtFileMapFlags(uint32_t x) {
|
||||
static char filemapflags[64];
|
||||
_Alignas(char) static char filemapflags[64];
|
||||
return DescribeFlags(filemapflags, sizeof(filemapflags), kFileMapFlags,
|
||||
ARRAYLEN(kFileMapFlags), "kNtFileMap", x);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ static const struct DescribeFlags kFileShareflags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtFileShareFlags(uint32_t x) {
|
||||
static char ntfileshareflags[64];
|
||||
_Alignas(char) static char ntfileshareflags[64];
|
||||
return DescribeFlags(ntfileshareflags, sizeof(ntfileshareflags),
|
||||
kFileShareflags, ARRAYLEN(kFileShareflags),
|
||||
"kNtFileShare", x);
|
||||
|
|
|
@ -29,7 +29,7 @@ static const struct DescribeFlags kFiletypeFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtFiletypeFlags(uint32_t x) {
|
||||
static char filetypeflags[64];
|
||||
_Alignas(char) static char filetypeflags[64];
|
||||
return DescribeFlags(filetypeflags, sizeof(filetypeflags), kFiletypeFlags,
|
||||
ARRAYLEN(kFiletypeFlags), "kNtFileType", x);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ static const struct DescribeFlags kMoveFileInputFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtMoveFileInputFlags(uint32_t x) {
|
||||
static char movefileflags[256];
|
||||
_Alignas(char) static char movefileflags[256];
|
||||
return DescribeFlags(movefileflags, sizeof(movefileflags),
|
||||
kMoveFileInputFlags, ARRAYLEN(kMoveFileInputFlags),
|
||||
"kNtMovefile", x);
|
||||
|
|
|
@ -42,7 +42,7 @@ static const struct DescribeFlags kPageFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtPageFlags(uint32_t x) {
|
||||
static char pageflags[64];
|
||||
_Alignas(char) static char pageflags[64];
|
||||
return DescribeFlags(pageflags, sizeof(pageflags), kPageFlags,
|
||||
ARRAYLEN(kPageFlags), "kNt", x);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ static const struct DescribeFlags kPipeModeFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtPipeModeFlags(uint32_t x) {
|
||||
static char pipemodeflags[64];
|
||||
_Alignas(char) static char pipemodeflags[64];
|
||||
return DescribeFlags(pipemodeflags, sizeof(pipemodeflags), kPipeModeFlags,
|
||||
ARRAYLEN(kPipeModeFlags), "kNtPipe", x);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ static const struct DescribeFlags kPipeOpenFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtPipeOpenFlags(uint32_t x) {
|
||||
static char pipeopenflags[64];
|
||||
_Alignas(char) static char pipeopenflags[64];
|
||||
return DescribeFlags(pipeopenflags, sizeof(pipeopenflags), kPipeOpenFlags,
|
||||
ARRAYLEN(kPipeOpenFlags), "kNtPipeAccess", x);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ static const struct DescribeFlags kProcessAccessflags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtProcessAccessFlags(uint32_t x) {
|
||||
static char ntprocessaccessflags[256];
|
||||
_Alignas(char) static char ntprocessaccessflags[256];
|
||||
return DescribeFlags(ntprocessaccessflags, sizeof(ntprocessaccessflags),
|
||||
kProcessAccessflags, ARRAYLEN(kProcessAccessflags),
|
||||
"kNtProcess", x);
|
||||
|
|
|
@ -39,7 +39,7 @@ static const struct DescribeFlags kNtStartFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtStartFlags(uint32_t x) {
|
||||
static char startflags[128];
|
||||
_Alignas(char) static char startflags[128];
|
||||
return DescribeFlags(startflags, sizeof(startflags), kNtStartFlags,
|
||||
ARRAYLEN(kNtStartFlags), "kNtStartf", x);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ static const struct DescribeFlags kSymbolicLinkflags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeNtSymbolicLinkFlags(uint32_t x) {
|
||||
static char ntsymboliclinkflags[64];
|
||||
_Alignas(char) static char ntsymboliclinkflags[64];
|
||||
return DescribeFlags(ntsymboliclinkflags, sizeof(ntsymboliclinkflags),
|
||||
kSymbolicLinkflags, ARRAYLEN(kSymbolicLinkflags),
|
||||
"kNtSymbolicLinkFlag", x);
|
||||
|
|
|
@ -27,7 +27,7 @@ static const struct DescribeFlags kProtFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeProtFlags(int x) {
|
||||
static char protflags[64];
|
||||
_Alignas(char) static char protflags[64];
|
||||
return DescribeFlags(protflags, sizeof(protflags), kProtFlags,
|
||||
ARRAYLEN(kProtFlags), "PROT_", x);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ static const struct DescribeFlags kRemapFlags[] = {
|
|||
};
|
||||
|
||||
const char *DescribeRemapFlags(int x) {
|
||||
static char remapflags[64];
|
||||
_Alignas(char) static char remapflags[64];
|
||||
return DescribeFlags(remapflags, sizeof(remapflags), kRemapFlags,
|
||||
ARRAYLEN(kRemapFlags), "MREMAP_", x);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
|
||||
const char *GetMagnumStr(const struct MagnumStr *ms, int x) {
|
||||
char *GetMagnumStr(const struct MagnumStr *ms, int x) {
|
||||
int i;
|
||||
for (i = 0; ms[i].x != -123; ++i) {
|
||||
if (x == *(const int *)((uintptr_t)ms + ms[i].x)) {
|
||||
return (const char *)((uintptr_t)ms + ms[i].s);
|
||||
for (i = 0; ms[i].x != MAGNUM_TERMINATOR; ++i) {
|
||||
if (x == MAGNUM_NUMBER(ms, i)) {
|
||||
return MAGNUM_STRING(ms, i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
STATIC_YOINK("__get_symbol_by_addr");
|
||||
|
||||
#define MAXLEAKS 1000
|
||||
|
||||
static bool once;
|
||||
static bool hasleaks;
|
||||
|
||||
|
@ -46,15 +48,18 @@ static noasan void CheckLeak(void *x, void *y, size_t n, void *a) {
|
|||
static noasan void OnMemory(void *x, void *y, size_t n, void *a) {
|
||||
static int i;
|
||||
if (n) {
|
||||
if (++i < 20) {
|
||||
kprintf("%p %,lu bytes [dlmalloc]", x, n);
|
||||
if (IsAsan()) {
|
||||
__asan_print_trace(x);
|
||||
if (MAXLEAKS) {
|
||||
if (i < MAXLEAKS) {
|
||||
++i;
|
||||
kprintf("%p %,lu bytes [dlmalloc]", x, n);
|
||||
if (IsAsan()) {
|
||||
__asan_print_trace(x);
|
||||
}
|
||||
kprintf("\n");
|
||||
} else if (i == MAXLEAKS) {
|
||||
++i;
|
||||
kprintf("etc. etc.\n");
|
||||
}
|
||||
kprintf("\n");
|
||||
}
|
||||
if (i == 20) {
|
||||
kprintf("etc. etc.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
libc/nt/struct/linger.h
Normal file
13
libc/nt/struct/linger.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_NT_STRUCT_LINGER_H_
|
||||
#define COSMOPOLITAN_LIBC_NT_STRUCT_LINGER_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct linger_nt {
|
||||
uint16_t l_onoff; /* on/off */
|
||||
uint16_t l_linger; /* seconds */
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_NT_STRUCT_LINGER_H_ */
|
|
@ -22,7 +22,7 @@
|
|||
/**
|
||||
* Describes setsockopt() level arguments.
|
||||
*/
|
||||
const char *DescribeSockLevel(int x) {
|
||||
char *DescribeSockLevel(int x) {
|
||||
static char buf[12];
|
||||
if (x == SOL_IP) return "SOL_IP";
|
||||
if (x == SOL_TCP) return "SOL_TCP";
|
||||
|
|
|
@ -18,26 +18,32 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
|
||||
/**
|
||||
* Describes setsockopt() optname arguments.
|
||||
*/
|
||||
const char *DescribeSockOptname(int l, int x) {
|
||||
char *DescribeSockOptname(int l, int x) {
|
||||
int i;
|
||||
static char buf[12], *s;
|
||||
char *ps, *s;
|
||||
const struct MagnumStr *ms = 0;
|
||||
_Alignas(char) static char buf[32];
|
||||
if (x) {
|
||||
if (l == SOL_SOCKET) {
|
||||
ps = "SO_";
|
||||
ms = kSockOptnames;
|
||||
} else if (l == SOL_TCP) {
|
||||
ps = "TCP_";
|
||||
ms = kTcpOptnames;
|
||||
} else if (l == SOL_IP) {
|
||||
ps = "IP_";
|
||||
ms = kIpOptnames;
|
||||
}
|
||||
}
|
||||
if (ms && (s = GetMagnumStr(ms, x))) {
|
||||
return s;
|
||||
stpcpy(stpcpy(buf, ps), s);
|
||||
return buf;
|
||||
} else {
|
||||
FormatInt32(buf, x);
|
||||
return buf;
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/nt/struct/linger.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/yoink.inc"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
|
@ -33,6 +35,7 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
uint32_t *inout_optlen) {
|
||||
uint64_t ms;
|
||||
uint32_t in_optlen;
|
||||
struct linger_nt linger;
|
||||
assert(fd->kind == kFdSocket);
|
||||
|
||||
if (out_opt_optval && inout_optlen) {
|
||||
|
@ -55,6 +58,11 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
((struct timeval *)out_opt_optval)->tv_sec = ms / 1000;
|
||||
((struct timeval *)out_opt_optval)->tv_usec = ms % 1000 * 1000;
|
||||
*inout_optlen = sizeof(struct timeval);
|
||||
} else if (optname == SO_LINGER && in_optlen == sizeof(struct linger)) {
|
||||
linger = *(struct linger_nt *)out_opt_optval;
|
||||
((struct linger *)out_opt_optval)->l_onoff = !!linger.l_onoff;
|
||||
((struct linger *)out_opt_optval)->l_linger = linger.l_linger;
|
||||
*inout_optlen = sizeof(struct linger);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,24 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e
|
||||
.macro .e e s
|
||||
.long \e - kIpOptnames
|
||||
.long 1f - kIpOptnames
|
||||
.rodata.str1.1
|
||||
1: .string "\e"
|
||||
1: .string "\s"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
.align 4
|
||||
.underrun
|
||||
kIpOptnames:
|
||||
.e IP_TOS # int
|
||||
.e IP_MTU # int
|
||||
.e IP_TTL # int
|
||||
.e IP_HDRINCL # bool32
|
||||
.long -123
|
||||
.e IP_TOS,"TOS" # int
|
||||
.e IP_MTU,"MTU" # int
|
||||
.e IP_TTL,"TTL" # int
|
||||
.e IP_HDRINCL,"HDRINCL" # bool32
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kIpOptnames,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e
|
||||
.macro .e e s
|
||||
.long \e - kSockOptnames
|
||||
.long 1f - kSockOptnames
|
||||
.rodata.str1.1
|
||||
1: .string "\e"
|
||||
1: .string "\s"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
|
@ -30,20 +31,22 @@
|
|||
.align 4
|
||||
.underrun
|
||||
kSockOptnames:
|
||||
.e SO_DEBUG # bool32
|
||||
.e SO_BROADCAST # bool32
|
||||
.e SO_REUSEADDR # bool32
|
||||
.e SO_REUSEPORT # bool32
|
||||
.e SO_KEEPALIVE # bool32
|
||||
.e SO_DONTROUTE # bool32
|
||||
.e SO_RCVTIMEO # timeval
|
||||
.e SO_SNDTIMEO # timeval
|
||||
.e SO_LINGER # linger
|
||||
.e SO_SNDBUF # int
|
||||
.e SO_RCVBUF # int
|
||||
.e SO_RCVLOWAT # int
|
||||
.e SO_SNDLOWAT # int
|
||||
.e SO_ERROR # int
|
||||
.long -123
|
||||
.e SO_DEBUG,"DEBUG" # bool32
|
||||
.e SO_ACCEPTCONN,"ACCEPTCONN" # bool32
|
||||
.e SO_BROADCAST,"BROADCAST" # bool32
|
||||
.e SO_REUSEADDR,"REUSEADDR" # bool32
|
||||
.e SO_REUSEPORT,"REUSEPORT" # bool32
|
||||
.e SO_KEEPALIVE,"KEEPALIVE" # bool32
|
||||
.e SO_DONTROUTE,"DONTROUTE" # bool32
|
||||
.e SO_RCVTIMEO,"RCVTIMEO" # timeval
|
||||
.e SO_SNDTIMEO,"SNDTIMEO" # timeval
|
||||
.e SO_LINGER,"LINGER" # linger
|
||||
.e SO_TYPE,"TYPE" # int
|
||||
.e SO_SNDBUF,"SNDBUF" # int
|
||||
.e SO_RCVBUF,"RCVBUF" # int
|
||||
.e SO_RCVLOWAT,"RCVLOWAT" # int
|
||||
.e SO_SNDLOWAT,"SNDLOWAT" # int
|
||||
.e SO_ERROR,"ERROR" # int
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kSockOptnames,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -16,33 +16,34 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e
|
||||
.macro .e e s
|
||||
.long \e - kTcpOptnames
|
||||
.long 1f - kTcpOptnames
|
||||
.rodata.str1.1
|
||||
1: .string "\e"
|
||||
1: .string "\s"
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.section .rodata
|
||||
.align 4
|
||||
.align 4
|
||||
.underrun
|
||||
kTcpOptnames:
|
||||
.e TCP_NODELAY # bool32
|
||||
.e TCP_CORK # bool32
|
||||
.e TCP_QUICKACK # bool32
|
||||
.e TCP_FASTOPEN_CONNECT # bool32
|
||||
.e TCP_DEFER_ACCEPT # bool32
|
||||
.e TCP_KEEPIDLE # int (seconds)
|
||||
.e TCP_KEEPINTVL # int (seconds)
|
||||
.e TCP_FASTOPEN # int
|
||||
.e TCP_KEEPCNT # int
|
||||
.e TCP_MAXSEG # int
|
||||
.e TCP_SYNCNT # int
|
||||
.e TCP_NOTSENT_LOWAT # int
|
||||
.e TCP_WINDOW_CLAMP # int
|
||||
.long -123
|
||||
.e TCP_NODELAY,"NODELAY" # bool32
|
||||
.e TCP_CORK,"CORK" # bool32
|
||||
.e TCP_QUICKACK,"QUICKACK" # bool32
|
||||
.e TCP_FASTOPEN_CONNECT,"FASTOPEN_CONNECT" # bool32
|
||||
.e TCP_DEFER_ACCEPT,"DEFER_ACCEPT" # bool32
|
||||
.e TCP_KEEPIDLE,"KEEPIDLE" # int (seconds)
|
||||
.e TCP_KEEPINTVL,"KEEPINTVL" # int (seconds)
|
||||
.e TCP_FASTOPEN,"FASTOPEN" # int
|
||||
.e TCP_KEEPCNT,"KEEPCNT" # int
|
||||
.e TCP_MAXSEG,"MAXSEG" # int
|
||||
.e TCP_SYNCNT,"SYNCNT" # int
|
||||
.e TCP_NOTSENT_LOWAT,"NOTSENT_LOWAT" # int
|
||||
.e TCP_WINDOW_CLAMP,"WINDOW_CLAMP" # int
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kTcpOptnames,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -19,16 +19,12 @@
|
|||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/struct/linger.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct linger_nt { /* Linux+XNU+BSD ABI */
|
||||
uint16_t l_onoff; /* on/off */
|
||||
uint16_t l_linger; /* seconds */
|
||||
};
|
||||
|
||||
textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
|
||||
const void *optval, uint32_t optlen) {
|
||||
int64_t ms;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.macro .e e s
|
||||
|
@ -65,6 +66,6 @@ kSignalNames:
|
|||
.e SIGRTMIN,"RTMIN"
|
||||
.e SIGEMT,"EMT"
|
||||
.e SIGPWR,"PWR"
|
||||
.long -123
|
||||
.long MAGNUM_TERMINATOR
|
||||
.endobj kSignalNames,globl,hidden
|
||||
.overrun
|
||||
|
|
|
@ -262,8 +262,8 @@ wint_t towctrans(wint_t, wctrans_t);
|
|||
|
||||
char *strsignal(int) returnsnonnull libcesque;
|
||||
char *strerror(int) returnsnonnull dontthrow nocallback;
|
||||
const char *strerrno(int) nosideeffect libcesque;
|
||||
const char *strerdoc(int) nosideeffect libcesque;
|
||||
char *strerrno(int) nosideeffect libcesque;
|
||||
char *strerdoc(int) nosideeffect libcesque;
|
||||
int strerror_r(int, char *, size_t) dontthrow nocallback;
|
||||
int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback;
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ syscon clock CLOCK_MONOTONIC_RAW 4 4 0x4000 0x4000 0x4000 4 # actu
|
|||
syscon clock CLOCK_REALTIME_COARSE 5 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5
|
||||
syscon clock CLOCK_MONOTONIC_COARSE 6 -1 -1 -1 -1 -1 # Linux 2.6.32+; bsd consensus; not available on RHEL5
|
||||
syscon clock CLOCK_PROF -1 -1 2 -1 2 -1 #
|
||||
syscon clock CLOCK_BOOTTIME 7 -1 -1 6 6 -1 #
|
||||
syscon clock CLOCK_BOOTTIME 7 -1 -1 6 -1 -1 #
|
||||
syscon clock CLOCK_REALTIME_ALARM 8 -1 -1 -1 -1 -1 #
|
||||
syscon clock CLOCK_BOOTTIME_ALARM 9 -1 -1 -1 -1 -1 #
|
||||
syscon clock CLOCK_TAI 11 -1 -1 -1 -1 -1 #
|
||||
|
@ -669,16 +669,19 @@ syscon epoll EPOLLET 0x80000000 0x80000000 0x80000000 0x80000000 0x80000
|
|||
# * -1 we define as no-op
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon so SO_DEBUG 1 1 1 1 1 1 # debugging is enabled; consensus
|
||||
syscon so SO_TYPE 3 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
|
||||
syscon so SO_ERROR 4 0x1007 0x1007 0x1007 0x1007 0x1007 # takes int pointer and stores/clears the pending error code; bsd consensus
|
||||
syscon so SO_ACCEPTCONN 30 2 2 2 2 2 # takes int pointer and stores boolean indicating if listen() was called on fd; bsd consensus
|
||||
syscon so SO_REUSEPORT 15 0x0200 0x0200 0x0200 0x0200 4 # bsd consensus (NT calls it SO_REUSEADDR)
|
||||
syscon so SO_REUSEADDR 2 4 4 4 4 0 # bsd consensus (default behavior on NT)
|
||||
syscon so SO_REUSEADDR 2 4 4 4 4 4 # bsd consensus (default behavior on NT)
|
||||
syscon so SO_EXCLUSIVEADDRUSE 0 0 0 0 0 ~4 # bsd consensus (default behavior on NT)
|
||||
syscon so SO_KEEPALIVE 9 8 8 8 8 8 # bsd consensus
|
||||
syscon so SO_DONTROUTE 5 0x10 0x10 0x10 0x10 0x10 # bsd consensus
|
||||
syscon so SO_BROADCAST 6 0x20 0x20 0x20 0x20 0x20 # bsd consensus
|
||||
syscon so SO_BROADCAST 6 0x20 0x20 0x20 0x20 0x20 # socket is configured for broadcast messages; bsd consensus
|
||||
syscon so SO_USELOOPBACK 0 0x40 0x40 0x40 0x40 0x40 # bsd consensus
|
||||
syscon so SO_LINGER 13 0x80 0x80 0x80 0x80 0x80 # takes struct linger; causes close() return value to actually mean something; bsd consensus
|
||||
syscon so SO_DEBUG 1 1 1 1 1 1 # consensus
|
||||
syscon so SO_ACCEPTCONN 30 2 2 2 2 2 # takes int pointer and stores boolean indicating if listen() was called on fd; bsd consensus
|
||||
syscon so SO_ERROR 4 0x1007 0x1007 0x1007 0x1007 0x1007 # takes int pointer and stores/clears the pending error code; bsd consensus
|
||||
syscon so SO_DONTLINGER 0 0 0 0 0 ~0x80 # disables so_linger on windows
|
||||
syscon so SO_OOBINLINE 10 0x0100 0x0100 0x0100 0x0100 0x0100 # bsd consensus
|
||||
syscon so SO_SNDBUF 7 0x1001 0x1001 0x1001 0x1001 0x1001 # bsd consensus
|
||||
syscon so SO_RCVBUF 8 0x1002 0x1002 0x1002 0x1002 0x1002 # bsd consensus
|
||||
|
@ -686,7 +689,6 @@ syscon so SO_RCVTIMEO 20 0x1006 0x1006 0x1006 0x100c 0x1006 # rec
|
|||
syscon so SO_SNDTIMEO 21 0x1005 0x1005 0x1005 0x100b 0x1005 # send timeout; takes struct timeval; bsd consensus
|
||||
syscon so SO_RCVLOWAT 18 0x1004 0x1004 0x1004 0x1004 0x1004 # bsd consensus
|
||||
syscon so SO_SNDLOWAT 19 0x1003 0x1003 0x1003 0x1003 0x1003 # bsd consensus
|
||||
syscon so SO_TYPE 3 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
|
||||
syscon so SO_TIMESTAMP 29 0x0400 0x0400 0x0800 0x2000 0
|
||||
syscon so SO_SETFIB 0 0 0x1014 0 0 0
|
||||
syscon so SO_DOMAIN 39 0 0x1019 0x1024 0 0
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon clock,CLOCK_BOOTTIME,7,-1,-1,6,6,-1
|
||||
.syscon clock,CLOCK_BOOTTIME,7,-1,-1,6,-1,-1
|
||||
|
|
2
libc/sysv/consts/SO_DONTLINGER.S
Normal file
2
libc/sysv/consts/SO_DONTLINGER.S
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon so,SO_DONTLINGER,0,0,0,0,0,~0x80
|
|
@ -1,2 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon so,SO_REUSEADDR,2,4,4,4,4,0
|
||||
.syscon so,SO_REUSEADDR,2,4,4,4,4,4
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
|
||||
#define COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/bench.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/testlib/bench.h"
|
||||
|
@ -9,151 +10,162 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define EZBENCH_COUNT 128
|
||||
#define EZBENCH_TRIES 10
|
||||
|
||||
#define EZBENCH(INIT, EXPR) EZBENCH2(#EXPR, INIT, EXPR)
|
||||
|
||||
#define EZBENCH2(NAME, INIT, EXPR) \
|
||||
do { \
|
||||
int Core, Tries, Interrupts; \
|
||||
int64_t Speculative, MemoryStrict; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, 128, ({ \
|
||||
INIT; \
|
||||
polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" speculative"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 32, ({ \
|
||||
INIT; \
|
||||
thrashcodecache(); \
|
||||
polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" memory strict"); \
|
||||
__testlib_ezbenchreport( \
|
||||
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
|
||||
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
|
||||
#define EZBENCH2(NAME, INIT, EXPR) \
|
||||
do { \
|
||||
int Core, Tries, Interrupts; \
|
||||
int64_t Speculative, MemoryStrict; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, ({ \
|
||||
INIT; \
|
||||
__polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" speculative"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 32, ({ \
|
||||
INIT; \
|
||||
thrashcodecache(); \
|
||||
__polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
|
||||
__testlib_ezbenchreport( \
|
||||
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
|
||||
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
|
||||
} while (0)
|
||||
|
||||
#define EZBENCH3(NAME, NUM, INIT, EXPR) \
|
||||
do { \
|
||||
int Core, Tries, Interrupts; \
|
||||
int64_t Speculative, MemoryStrict; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, NUM, ({ \
|
||||
INIT; \
|
||||
polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" speculative"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, NUM, ({ \
|
||||
INIT; \
|
||||
thrashcodecache(); \
|
||||
polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" memory strict"); \
|
||||
__testlib_ezbenchreport( \
|
||||
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
|
||||
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
|
||||
#define EZBENCH3(NAME, NUM, INIT, EXPR) \
|
||||
do { \
|
||||
int Core, Tries, Interrupts; \
|
||||
int64_t Speculative, MemoryStrict; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, NUM, ({ \
|
||||
INIT; \
|
||||
__polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" speculative"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
INIT; \
|
||||
EXPR; \
|
||||
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, NUM, ({ \
|
||||
INIT; \
|
||||
thrashcodecache(); \
|
||||
__polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
|
||||
__testlib_ezbenchreport( \
|
||||
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \
|
||||
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \
|
||||
} while (0)
|
||||
|
||||
#define EZBENCH_C(NAME, CONTROL, EXPR) \
|
||||
do { \
|
||||
int Core, Tries, Interrupts; \
|
||||
int64_t Control, Speculative, MemoryStrict; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
Control = BENCHLOOP(__startbench_m, __endbench_m, 128, ({ \
|
||||
thrashcodecache(); \
|
||||
polluteregisters(); \
|
||||
}), \
|
||||
(CONTROL)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" control"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, 128, \
|
||||
polluteregisters(), (EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" speculative"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
EXPR; \
|
||||
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 8, ({ \
|
||||
thrashcodecache(); \
|
||||
polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(" memory strict"); \
|
||||
__testlib_ezbenchreport(NAME, MAX(0, Speculative - Control), \
|
||||
MAX(0, MemoryStrict - Control)); \
|
||||
#define EZBENCH_C(NAME, CONTROL, EXPR) \
|
||||
do { \
|
||||
int Core, Tries, Interrupts; \
|
||||
int64_t Control, Speculative, MemoryStrict; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
Control = BENCHLOOP(__startbench_m, __endbench_m, EZBENCH_COUNT, ({ \
|
||||
thrashcodecache(); \
|
||||
__polluteregisters(); \
|
||||
}), \
|
||||
(CONTROL)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" control"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, \
|
||||
__polluteregisters(), (EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" speculative"); \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
EXPR; \
|
||||
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 8, ({ \
|
||||
thrashcodecache(); \
|
||||
__polluteregisters(); \
|
||||
}), \
|
||||
(EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
|
||||
__testlib_ezbenchreport(NAME, MAX(0, Speculative - Control), \
|
||||
MAX(0, MemoryStrict - Control)); \
|
||||
} while (0)
|
||||
|
||||
#define EZBENCH_N(NAME, N, EXPR) \
|
||||
do { \
|
||||
int64_t Speculative, Toto; \
|
||||
int Core, Tries, Interrupts; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
EXPR; \
|
||||
Speculative = \
|
||||
BENCHLOOP(__startbench, __endbench, 32, polluteregisters(), (EXPR)); \
|
||||
} while (++Tries < 10 && (__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == 10) __testlib_ezbenchwarn(""); \
|
||||
__testlib_ezbenchreport_n( \
|
||||
NAME, 'n', N, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
|
||||
#define EZBENCH_N(NAME, N, EXPR) \
|
||||
do { \
|
||||
int64_t Speculative, Toto; \
|
||||
int Core, Tries, Interrupts; \
|
||||
Tries = 0; \
|
||||
do { \
|
||||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
Interrupts = __testlib_getinterrupts(); \
|
||||
EXPR; \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, 32, \
|
||||
__polluteregisters(), (EXPR)); \
|
||||
} while (++Tries < EZBENCH_TRIES && \
|
||||
(__testlib_getcore() != Core && \
|
||||
__testlib_getinterrupts() > Interrupts)); \
|
||||
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(""); \
|
||||
__testlib_ezbenchreport_n( \
|
||||
NAME, 'n', N, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
|
||||
} while (0)
|
||||
|
||||
#define EZBENCH_K(NAME, K, EXPR) \
|
||||
|
@ -164,14 +176,14 @@ COSMOPOLITAN_C_START_
|
|||
__testlib_yield(); \
|
||||
Core = __testlib_getcore(); \
|
||||
EXPR; \
|
||||
Speculative = \
|
||||
BENCHLOOP(__startbench, __endbench, 128, donothing, (EXPR)); \
|
||||
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, \
|
||||
donothing, (EXPR)); \
|
||||
} while (Core != __testlib_getcore()); \
|
||||
__testlib_ezbenchreport_n( \
|
||||
NAME, 'k', K, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
|
||||
} while (0)
|
||||
|
||||
void polluteregisters(void);
|
||||
void __polluteregisters(void);
|
||||
void __testlib_yield(void);
|
||||
int __testlib_getcore(void);
|
||||
int64_t __testlib_getinterrupts(void);
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
polluteregisters:
|
||||
__polluteregisters:
|
||||
.leafprologue
|
||||
xor %eax,%eax
|
||||
mov %ecx,%ecx
|
||||
mov %edx,%edx
|
||||
mov %r8d,%r8d
|
||||
mov %r9d,%r9d
|
||||
mov %r10d,%r10d
|
||||
mov %r11d,%r11d
|
||||
xor %ecx,%ecx
|
||||
xor %edx,%edx
|
||||
xor %r8d,%r8d
|
||||
xor %r9d,%r9d
|
||||
xor %r10d,%r10d
|
||||
xor %r11d,%r11d
|
||||
testb X86_HAVE(AVX)+kCpuids(%rip)
|
||||
jz .Lsse
|
||||
vpxor %xmm0,%xmm0,%xmm0
|
||||
|
@ -48,13 +48,13 @@ polluteregisters:
|
|||
xorps %xmm6,%xmm6
|
||||
xorps %xmm7,%xmm7
|
||||
.leafepilogue
|
||||
.endfn polluteregisters,globl
|
||||
.endfn __polluteregisters,globl
|
||||
|
||||
.end
|
||||
// Fill registers with junk data to create false dependencies.
|
||||
// Which shall create the problem that happens w/o vzeroupper.
|
||||
// Or the Core Architecture errata regarding BSR/BSF w/ 64bit.
|
||||
polluteregisters:
|
||||
__polluteregisters:
|
||||
.leafprologue
|
||||
mov $-1,%rax
|
||||
mov %rax,%rcx
|
||||
|
@ -92,4 +92,4 @@ polluteregisters:
|
|||
punpcklqdq %xmm0,%xmm6
|
||||
punpcklqdq %xmm0,%xmm7
|
||||
.leafepilogue
|
||||
.endfn polluteregisters,globl
|
||||
.endfn __polluteregisters,globl
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -24,6 +26,7 @@
|
|||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
@ -68,18 +71,34 @@ static long Stat(const char *path, struct stat *st) {
|
|||
return ax;
|
||||
}
|
||||
|
||||
static long Fstatat(const char *path, struct stat *st) {
|
||||
long ax, di, si, dx;
|
||||
register long r10 asm("r10") = 0;
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx), "+r"(r10)
|
||||
: "0"(__NR_fstatat), "1"(AT_FDCWD), "2"(path), "3"(st)
|
||||
: "rcx", "r8", "r9", "r11", "memory", "cc");
|
||||
return ax;
|
||||
}
|
||||
|
||||
BENCH(stat, bench) {
|
||||
struct stat st;
|
||||
union metastat ms;
|
||||
EXPECT_SYS(0, 0, makedirs(".python/test", 0755));
|
||||
EZBENCH2("__stat2cosmo", donothing, __stat2cosmo(&st, &ms));
|
||||
EXPECT_SYS(0, 0,
|
||||
touch(".python/test/"
|
||||
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
|
||||
0644));
|
||||
if (!IsWindows()) {
|
||||
if (!IsWindows() && !IsFreebsd()) {
|
||||
EZBENCH2("stat syscall", donothing,
|
||||
Stat(".python/test/"
|
||||
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
|
||||
&st));
|
||||
EZBENCH2("fstatat syscall", donothing,
|
||||
Fstatat(".python/test/"
|
||||
"tokenize_tests-latin1-coding-cookie-and-utf8-bom-sig.txt",
|
||||
&st));
|
||||
}
|
||||
EZBENCH2("stat() fs", donothing,
|
||||
stat(".python/test/"
|
||||
|
|
|
@ -19,8 +19,11 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/xchg.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/linux/mmap.h"
|
||||
#include "libc/linux/munmap.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/rand/rand.h"
|
||||
|
@ -33,6 +36,7 @@
|
|||
#include "libc/sysv/consts/msync.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
|
@ -281,3 +285,57 @@ TEST(mmap, sharedFileMapFork) {
|
|||
EXPECT_NE(-1, close(fd));
|
||||
EXPECT_NE(-1, unlink(path));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// BENCHMARKS
|
||||
|
||||
#define N (EZBENCH_COUNT * EZBENCH_TRIES)
|
||||
|
||||
int count;
|
||||
void *ptrs[N];
|
||||
|
||||
void BenchUnmap(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (ptrs[i]) {
|
||||
ASSERT_EQ(0, munmap(ptrs[i], FRAMESIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BenchMmapPrivate(void) {
|
||||
void *p;
|
||||
p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1, 0);
|
||||
if (p == MAP_FAILED) abort();
|
||||
ptrs[count++] = p;
|
||||
}
|
||||
|
||||
BENCH(mmap, bench) {
|
||||
EZBENCH2("mmap", donothing, BenchMmapPrivate());
|
||||
BenchUnmap();
|
||||
}
|
||||
|
||||
void BenchUnmapLinux(void) {
|
||||
int i;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (ptrs[i]) {
|
||||
ASSERT_EQ(0, LinuxMunmap(ptrs[i], FRAMESIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BenchMmapPrivateLinux(void) {
|
||||
void *p;
|
||||
p = (void *)LinuxMmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (p == MAP_FAILED) abort();
|
||||
ptrs[count++] = p;
|
||||
}
|
||||
|
||||
BENCH(mmap, benchLinux) {
|
||||
void *p;
|
||||
if (!IsLinux()) return;
|
||||
EZBENCH2("mmap (linux)", donothing, BenchMmapPrivateLinux());
|
||||
BenchUnmapLinux();
|
||||
}
|
||||
|
|
22
third_party/linenoise/linenoise.c
vendored
22
third_party/linenoise/linenoise.c
vendored
|
@ -193,13 +193,14 @@ Copyright 2010-2013 Pieter Noordhuis <pcnoordhuis@gmail.com>\"");
|
|||
#define DEBUG(L, ...) (void)0
|
||||
#endif
|
||||
|
||||
#define DUFF_ROUTINE_LOOP 0
|
||||
#define DUFF_ROUTINE_START 5
|
||||
#define DUFF_ROUTINE_LOOP 0
|
||||
#define DUFF_ROUTINE_SEARCH 1
|
||||
#define DUFF_ROUTINE_START 5
|
||||
|
||||
#define DUFF_ROUTINE_LABEL(STATE) \
|
||||
case STATE: \
|
||||
linenoiseRefreshLineForce(l); \
|
||||
l->state = DUFF_ROUTINE_LOOP
|
||||
l->state = STATE
|
||||
|
||||
#define DUFF_ROUTINE_READ(STATE) \
|
||||
DUFF_ROUTINE_LABEL(STATE); \
|
||||
|
@ -469,11 +470,11 @@ static const char *FindSubstringReverse(const char *p, size_t n, const char *q,
|
|||
n -= m;
|
||||
do {
|
||||
for (i = 0; i < m; ++i) {
|
||||
if (p[n + i] != q[i]) {
|
||||
if (kToLower[p[n + i] & 255] != kToLower[q[i] & 255]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == m) {
|
||||
if (kToLower[i & 255] == kToLower[m & 255]) {
|
||||
return p + n;
|
||||
}
|
||||
} while (n--);
|
||||
|
@ -1852,7 +1853,8 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
char seq[16];
|
||||
|
||||
gotint = 0;
|
||||
if (prompt && (!l->prompt || strcmp(prompt, l->prompt))) {
|
||||
if (prompt && l->state != DUFF_ROUTINE_SEARCH &&
|
||||
(!l->prompt || strcmp(prompt, l->prompt))) {
|
||||
free(l->prompt);
|
||||
l->prompt = strdup(prompt);
|
||||
}
|
||||
|
@ -1885,7 +1887,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
for (fail = l->matlen = 0;;) {
|
||||
free(l->prompt);
|
||||
l->prompt = linenoiseMakeSearchPrompt(fail, l->ab.b, l->matlen);
|
||||
DUFF_ROUTINE_READ(1);
|
||||
DUFF_ROUTINE_READ(DUFF_ROUTINE_SEARCH);
|
||||
fail = 1;
|
||||
added = 0;
|
||||
l->j = l->pos;
|
||||
|
@ -1906,7 +1908,6 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
} else if (seq[0] == CTRL('G')) {
|
||||
linenoiseEditHistoryGoto(l, l->oldindex);
|
||||
l->pos = l->olderpos;
|
||||
rc = 0;
|
||||
break;
|
||||
} else if (iswcntrl(seq[0])) { // only sees canonical c0
|
||||
break;
|
||||
|
@ -1953,7 +1954,7 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
rc = 0;
|
||||
linenoiseFreeCompletions(&l->lc);
|
||||
i = Backwards(l, l->pos, iswname);
|
||||
j = Forwards(l, l->pos, iswname);
|
||||
j = l->pos;
|
||||
{
|
||||
char *s = strndup(l->buf + i, j - i);
|
||||
completionCallback(s, &l->lc);
|
||||
|
@ -1966,7 +1967,8 @@ ssize_t linenoiseEdit(struct linenoiseState *l, const char *prompt, char **obuf,
|
|||
if (linenoiseGrow(l, n + 1)) {
|
||||
memmove(l->buf + i + m, l->buf + i + j, l->len - j + 1);
|
||||
memcpy(l->buf + i, l->lc.cvec[0], m);
|
||||
l->len = l->pos = n;
|
||||
l->pos = i + m;
|
||||
l->len = n;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
4
third_party/lua/cosmo.h
vendored
4
third_party/lua/cosmo.h
vendored
|
@ -8,8 +8,8 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
char *LuaFormatStack(lua_State *) dontdiscard;
|
||||
int LuaCallWithTrace(lua_State *, int, int, lua_State *);
|
||||
int LuaEncodeJsonData(lua_State *, char **, int, char *);
|
||||
int LuaEncodeLuaData(lua_State *, char **, int, char *);
|
||||
int LuaEncodeJsonData(lua_State *, char **, int, char *, int);
|
||||
int LuaEncodeLuaData(lua_State *, char **, int, char *, int);
|
||||
int LuaEncodeUrl(lua_State *);
|
||||
int LuaParseUrl(lua_State *);
|
||||
int LuaPushHeader(lua_State *, struct HttpMessage *, char *, int);
|
||||
|
|
13
third_party/lua/escapeluastring.c
vendored
13
third_party/lua/escapeluastring.c
vendored
|
@ -16,20 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
void EscapeLuaString(char *s, size_t len, char **buf) {
|
||||
appendw(buf, '"');
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (s[i] == '\\' || s[i] == '\"' || s[i] == '\n' || s[i] == '\0' ||
|
||||
s[i] == '\r') {
|
||||
if (' ' <= s[i] && s[i] <= 0x7e) {
|
||||
appendw(buf, s[i]);
|
||||
} else if (s[i] == '\n') {
|
||||
appendw(buf, '\\' | 'n' << 8);
|
||||
} else if (s[i] == '\\' || s[i] == '\'' || s[i] == '\"') {
|
||||
appendw(buf, '\\' | s[i] << 8);
|
||||
} else {
|
||||
appendw(buf, '\\' | 'x' << 010 |
|
||||
"0123456789abcdef"[(s[i] & 0xF0) >> 4] << 020 |
|
||||
"0123456789abcdef"[(s[i] & 0x0F) >> 0] << 030);
|
||||
} else {
|
||||
appendd(buf, s + i, 1);
|
||||
}
|
||||
}
|
||||
appendw(buf, '"');
|
||||
|
|
57
third_party/lua/lrepl.c
vendored
57
third_party/lua/lrepl.c
vendored
|
@ -32,6 +32,7 @@
|
|||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
@ -50,6 +51,17 @@ Copyright 1994–2021 Lua.org, PUC-Rio.\"");
|
|||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
|
||||
static const char *const kKeywordHints[] = {
|
||||
"else", //
|
||||
"elseif", //
|
||||
"function", //
|
||||
"function", //
|
||||
"repeat", //
|
||||
"then", //
|
||||
"until", //
|
||||
"while", //
|
||||
};
|
||||
|
||||
bool lua_repl_blocking;
|
||||
bool lua_repl_isterminal;
|
||||
linenoiseCompletionCallback *lua_repl_completions_callback;
|
||||
|
@ -74,46 +86,59 @@ static const char *g_historypath;
|
|||
#define LUA_MAXINPUT 512
|
||||
#endif
|
||||
|
||||
static void lua_readline_addcompletion(linenoiseCompletions *c, char *s) {
|
||||
char **p = c->cvec;
|
||||
size_t n = c->len + 1;
|
||||
if ((p = realloc(p, n * sizeof(*p)))) {
|
||||
p[n - 1] = s;
|
||||
|
||||
static void lua_readline_addcompletion (linenoiseCompletions *c, const char *s) {
|
||||
char **p, *t;
|
||||
if ((p = realloc(c->cvec, (c->len + 1) * sizeof(*p)))) {
|
||||
c->cvec = p;
|
||||
c->len = n;
|
||||
if ((t = strdup(s))) {
|
||||
c->cvec[c->len++] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lua_readline_completions(const char *p, linenoiseCompletions *c) {
|
||||
|
||||
void lua_readline_completions (const char *p, linenoiseCompletions *c) {
|
||||
int i;
|
||||
lua_State *L;
|
||||
const char *name;
|
||||
for (i = 0; i < ARRAYLEN(kKeywordHints); ++i) {
|
||||
if (startswithi(kKeywordHints[i], p)) {
|
||||
lua_readline_addcompletion(c, kKeywordHints[i]);
|
||||
}
|
||||
}
|
||||
L = globalL;
|
||||
lua_pushglobaltable(L);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
name = lua_tostring(L, -2);
|
||||
if (startswithi(name, p)) {
|
||||
lua_readline_addcompletion(c, strdup(name));
|
||||
lua_readline_addcompletion(c, name);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_repl_completions_callback(p, c);
|
||||
if (lua_repl_completions_callback) {
|
||||
lua_repl_completions_callback(p, c);
|
||||
}
|
||||
}
|
||||
|
||||
char *lua_readline_hint(const char *p, const char **ansi1, const char **ansi2) {
|
||||
char *h = 0;
|
||||
|
||||
char *lua_readline_hint (const char *p, const char **ansi1, const char **ansi2) {
|
||||
char *h;
|
||||
linenoiseCompletions c = {0};
|
||||
lua_readline_completions(p, &c);
|
||||
if (c.len == 1) h = strdup(c.cvec[0] + strlen(p));
|
||||
h = c.len == 1 ? strdup(c.cvec[0] + strlen(p)) : 0;
|
||||
linenoiseFreeCompletions(&c);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
static void lua_freeline (lua_State *L, char *b) {
|
||||
free(b);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return the string to be used as a prompt by the interpreter. Leave
|
||||
** the string (or nil, if using the default value) on the stack, to keep
|
||||
|
@ -129,6 +154,7 @@ static const char *get_prompt (lua_State *L, int firstline) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* mark in error messages for incomplete statements */
|
||||
#define EOFMARK "<eof>"
|
||||
#define marklen (sizeof(EOFMARK)/sizeof(char) - 1)
|
||||
|
@ -165,7 +191,7 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
prmt = strdup(get_prompt(L, firstline));
|
||||
lua_pop(L, 1); /* remove prompt */
|
||||
LUA_REPL_UNLOCK;
|
||||
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
|
||||
rc = linenoiseEdit(lua_repl_linenoise, 0, &b, !firstline || lua_repl_blocking);
|
||||
free(prmt);
|
||||
if (rc != -1) {
|
||||
if (b && *b) {
|
||||
|
@ -187,10 +213,11 @@ static ssize_t pushline (lua_State *L, int firstline) {
|
|||
l = strlen(b);
|
||||
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
||||
b[--l] = '\0'; /* remove it */
|
||||
if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
|
||||
if (firstline && b[0] == '=') { /* for compatibility with 5.2, ... */
|
||||
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
|
||||
else
|
||||
} else {
|
||||
lua_pushlstring(L, b, l);
|
||||
}
|
||||
lua_freeline(L, b);
|
||||
return 1;
|
||||
}
|
||||
|
|
10
third_party/lua/lua.mk
vendored
10
third_party/lua/lua.mk
vendored
|
@ -80,6 +80,14 @@ o/$(MODE)/third_party/lua/lua.com: \
|
|||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \
|
||||
o/$(MODE)/third_party/lua/.lua/.symtab
|
||||
|
||||
o//third_party/lua/lgc.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
|
||||
o/$(MODE)/third_party/lua/lvm.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-fno-gcse
|
||||
|
||||
o/$(MODE)/third_party/lua/lauxlib.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
@ -89,6 +97,8 @@ $(THIRD_PARTY_LUA_OBJS): \
|
|||
-ffunction-sections \
|
||||
-fdata-sections
|
||||
|
||||
$(THIRD_PARTY_LUA_OBJS): third_party/lua/lua.mk
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/lua
|
||||
o/$(MODE)/third_party/lua: \
|
||||
$(THIRD_PARTY_LUA_BINS) \
|
||||
|
|
158
third_party/lua/luaencodejsondata.c
vendored
158
third_party/lua/luaencodejsondata.c
vendored
|
@ -16,6 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "net/http/escape.h"
|
||||
|
@ -23,63 +25,115 @@
|
|||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat) {
|
||||
size_t idx = -1;
|
||||
size_t tbllen, buflen;
|
||||
int LuaEncodeJsonData(lua_State *L, char **buf, int level, char *numformat,
|
||||
int idx) {
|
||||
char *s;
|
||||
bool isarray;
|
||||
int t = lua_type(L, idx);
|
||||
if (level < 0) return luaL_argerror(L, 1, "too many nested tables");
|
||||
if (LUA_TSTRING == t) {
|
||||
appendw(buf, '"');
|
||||
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, idx), -1, 0)));
|
||||
appendw(buf, '"');
|
||||
} else if (LUA_TNUMBER == t) {
|
||||
appendf(buf, numformat, lua_tonumber(L, idx));
|
||||
} else if (LUA_TBOOLEAN == t) {
|
||||
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
|
||||
} else if (LUA_TTABLE == t) {
|
||||
tbllen = lua_rawlen(L, idx);
|
||||
// encode tables with numeric indices and empty tables as arrays
|
||||
isarray = tbllen > 0 || // integer keys present
|
||||
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
|
||||
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
||||
appendw(buf, isarray ? '[' : '{');
|
||||
if (isarray) {
|
||||
for (int i = 1; i <= tbllen; i++) {
|
||||
if (i > 1) appendw(buf, ',');
|
||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
int i = 1;
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (!lua_isstring(L, -2))
|
||||
return luaL_argerror(L, 1, "expected number or string as key value");
|
||||
if (i++ > 1) appendw(buf, ',');
|
||||
size_t tbllen, z;
|
||||
char ibuf[21], fmt[] = "%.14g";
|
||||
if (level > 0) {
|
||||
switch (lua_type(L, idx)) {
|
||||
case LUA_TSTRING:
|
||||
s = lua_tolstring(L, idx, &z);
|
||||
s = EscapeJsStringLiteral(s, z, &z);
|
||||
appendw(buf, '"');
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
appends(buf, gc(EscapeJsStringLiteral(lua_tostring(L, -2), -1, 0)));
|
||||
appendd(buf, s, z);
|
||||
appendw(buf, '"');
|
||||
free(s);
|
||||
return 0;
|
||||
case LUA_TNIL:
|
||||
appendw(buf, READ32LE("null"));
|
||||
return 0;
|
||||
case LUA_TFUNCTION:
|
||||
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TUSERDATA:
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TTHREAD:
|
||||
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, idx)) {
|
||||
appendd(buf, ibuf,
|
||||
FormatInt64(ibuf, luaL_checkinteger(L, idx)) - ibuf);
|
||||
} else {
|
||||
// we'd still prefer to use lua_tostring on a numeric index, but can't
|
||||
// use it in-place, as it breaks lua_next (changes numeric key to a
|
||||
// string)
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
appends(buf, lua_tostring(L, idx)); // use the copy
|
||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||
// TODO(jart): replace this api
|
||||
while (*numformat == '%' || *numformat == '.' ||
|
||||
isdigit(*numformat)) {
|
||||
++numformat;
|
||||
}
|
||||
switch (*numformat) {
|
||||
case 'a':
|
||||
case 'g':
|
||||
case 'f':
|
||||
fmt[4] = *numformat;
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, "numformat string not allowed");
|
||||
}
|
||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
||||
}
|
||||
appendw(buf, '"' | ':' << 010);
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
return 0;
|
||||
case LUA_TBOOLEAN:
|
||||
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
|
||||
return 0;
|
||||
case LUA_TTABLE:
|
||||
tbllen = lua_rawlen(L, idx);
|
||||
// encode tables with numeric indices and empty tables as arrays
|
||||
isarray =
|
||||
tbllen > 0 || // integer keys present
|
||||
(lua_pushnil(L), lua_next(L, -2) == 0) || // no non-integer keys
|
||||
(lua_pop(L, 2), false); // pop key/value pushed by lua_next
|
||||
appendw(buf, isarray ? '[' : '{');
|
||||
if (isarray) {
|
||||
for (size_t i = 1; i <= tbllen; i++) {
|
||||
if (i > 1) appendw(buf, ',');
|
||||
lua_rawgeti(L, -1, i); // table/-2, value/-1
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
int i = 1;
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2)) {
|
||||
if (!lua_isstring(L, -2)) {
|
||||
luaL_error(L, "expected number or string as key value");
|
||||
unreachable;
|
||||
}
|
||||
if (i++ > 1) appendw(buf, ',');
|
||||
appendw(buf, '"');
|
||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||
s = lua_tolstring(L, -2, &z);
|
||||
s = EscapeJsStringLiteral(s, z, &z);
|
||||
appendd(buf, s, z);
|
||||
free(s);
|
||||
} else {
|
||||
// we'd still prefer to use lua_tostring on a numeric index, but
|
||||
// can't use it in-place, as it breaks lua_next (changes numeric
|
||||
// key to a string)
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
s = lua_tolstring(L, idx, &z);
|
||||
appendd(buf, s, z); // use the copy
|
||||
lua_remove(L, -1); // remove copied key: tab/-3, key/-2, val/-1
|
||||
}
|
||||
appendw(buf, '"' | ':' << 010);
|
||||
LuaEncodeJsonData(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
}
|
||||
appendw(buf, isarray ? ']' : '}');
|
||||
return 0;
|
||||
default:
|
||||
luaL_error(L, "can't serialize value of this type");
|
||||
unreachable;
|
||||
}
|
||||
appendw(buf, isarray ? ']' : '}');
|
||||
} else if (LUA_TNIL == t) {
|
||||
appendd(buf, "null", 4);
|
||||
} else {
|
||||
return luaL_argerror(L, 1, "can't serialize value of this type");
|
||||
luaL_error(L, "too many nested tables");
|
||||
unreachable;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
118
third_party/lua/luaencodeluadata.c
vendored
118
third_party/lua/luaencodeluadata.c
vendored
|
@ -16,51 +16,97 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
#include "third_party/lua/lua.h"
|
||||
|
||||
int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat) {
|
||||
size_t idx = -1;
|
||||
size_t tbllen, buflen, slen;
|
||||
int LuaEncodeLuaData(lua_State *L, char **buf, int level, char *numformat,
|
||||
int idx) {
|
||||
char *s;
|
||||
int ktype;
|
||||
int t = lua_type(L, idx);
|
||||
if (level < 0) return luaL_argerror(L, 1, "too many nested tables");
|
||||
if (LUA_TSTRING == t) {
|
||||
s = lua_tolstring(L, idx, &slen);
|
||||
EscapeLuaString(s, slen, buf);
|
||||
} else if (LUA_TNUMBER == t) {
|
||||
appendf(buf, numformat, lua_tonumber(L, idx));
|
||||
} else if (LUA_TBOOLEAN == t) {
|
||||
appends(buf, lua_toboolean(L, idx) ? "true" : "false");
|
||||
} else if (LUA_TTABLE == t) {
|
||||
appendw(buf, '{');
|
||||
int i = 0;
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2) != 0) {
|
||||
ktype = lua_type(L, -2);
|
||||
if (ktype == LUA_TTABLE)
|
||||
return luaL_argerror(L, 1, "can't serialize key of this type");
|
||||
if (i++ > 0) appendd(buf, ",", 1);
|
||||
if (ktype != LUA_TNUMBER || floor(lua_tonumber(L, -2)) != i) {
|
||||
appendw(buf, '[');
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
LuaEncodeLuaData(L, buf, level, numformat);
|
||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||
appendw(buf, ']' | '=' << 010);
|
||||
}
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
lua_Integer i;
|
||||
size_t tbllen, buflen, slen;
|
||||
char ibuf[21], fmt[] = "%.14g";
|
||||
if (level > 0) {
|
||||
switch (lua_type(L, idx)) {
|
||||
case LUA_TNIL:
|
||||
appendw(buf, READ32LE("nil"));
|
||||
return 0;
|
||||
case LUA_TSTRING:
|
||||
s = lua_tolstring(L, idx, &slen);
|
||||
EscapeLuaString(s, slen, buf);
|
||||
return 0;
|
||||
case LUA_TFUNCTION:
|
||||
appendf(buf, "\"func@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TUSERDATA:
|
||||
appendf(buf, "\"udata@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
appendf(buf, "\"light@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TTHREAD:
|
||||
appendf(buf, "\"thread@%p\"", lua_touserdata(L, idx));
|
||||
return 0;
|
||||
case LUA_TNUMBER:
|
||||
if (lua_isinteger(L, idx)) {
|
||||
appendd(buf, ibuf,
|
||||
FormatInt64(ibuf, luaL_checkinteger(L, idx)) - ibuf);
|
||||
} else {
|
||||
// TODO(jart): replace this api
|
||||
while (*numformat == '%' || *numformat == '.' ||
|
||||
isdigit(*numformat)) {
|
||||
++numformat;
|
||||
}
|
||||
switch (*numformat) {
|
||||
case 'a':
|
||||
case 'g':
|
||||
case 'f':
|
||||
fmt[4] = *numformat;
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, "numformat string not allowed");
|
||||
}
|
||||
appendf(buf, fmt, lua_tonumber(L, idx));
|
||||
}
|
||||
return 0;
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, idx)) {
|
||||
appendw(buf, READ32LE("true"));
|
||||
} else {
|
||||
appendw(buf, READ64LE("false\0\0"));
|
||||
}
|
||||
return 0;
|
||||
case LUA_TTABLE:
|
||||
i = 0;
|
||||
appendw(buf, '{');
|
||||
lua_pushnil(L); // push the first key
|
||||
while (lua_next(L, -2) != 0) {
|
||||
ktype = lua_type(L, -2);
|
||||
if (i++ > 0) appendw(buf, ',');
|
||||
if (ktype != LUA_TNUMBER || lua_tointeger(L, -2) != i) {
|
||||
appendw(buf, '[');
|
||||
lua_pushvalue(L, -2); // table/-4, key/-3, value/-2, key/-1
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat, -1);
|
||||
lua_remove(L, -1); // remove copied key: table/-3, key/-2, value/-1
|
||||
appendw(buf, ']' | '=' << 010);
|
||||
}
|
||||
LuaEncodeLuaData(L, buf, level - 1, numformat, -1);
|
||||
lua_pop(L, 1); // table/-2, key/-1
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
appendw(buf, '}');
|
||||
return 0;
|
||||
default:
|
||||
luaL_error(L, "can't serialize value of this type");
|
||||
unreachable;
|
||||
}
|
||||
// stack: table/-1, as the key was popped by lua_next
|
||||
appendw(buf, '}');
|
||||
} else if (LUA_TNIL == t) {
|
||||
appendd(buf, "nil", 3);
|
||||
} else {
|
||||
return luaL_argerror(L, 1, "can't serialize value of this type");
|
||||
luaL_error(L, "too many nested tables");
|
||||
unreachable;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
22
third_party/lua/luaformatstack.c
vendored
22
third_party/lua/luaformatstack.c
vendored
|
@ -18,31 +18,17 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/append.internal.h"
|
||||
#include "third_party/lua/cosmo.h"
|
||||
#include "third_party/lua/lauxlib.h"
|
||||
|
||||
dontdiscard char *LuaFormatStack(lua_State *L) {
|
||||
size_t l;
|
||||
int i, top;
|
||||
char *b = 0;
|
||||
char *p, *b = 0;
|
||||
top = lua_gettop(L);
|
||||
for (i = 1; i <= top; i++) {
|
||||
if (i > 1) appendw(&b, '\n');
|
||||
appendf(&b, "\t%d\t%s\t", i, luaL_typename(L, i));
|
||||
switch (lua_type(L, i)) {
|
||||
case LUA_TNUMBER:
|
||||
appendf(&b, "%g", lua_tonumber(L, i));
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
appends(&b, lua_tostring(L, i));
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
appends(&b, lua_toboolean(L, i) ? "true" : "false");
|
||||
break;
|
||||
case LUA_TNIL:
|
||||
appends(&b, "nil");
|
||||
break;
|
||||
default:
|
||||
appendf(&b, "%p", lua_topointer(L, i));
|
||||
break;
|
||||
}
|
||||
LuaEncodeLuaData(L, &b, 64, "g", -1);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
|
|
@ -2270,8 +2270,7 @@ static void OnVidyaServiceTeletypeOutput(void) {
|
|||
char buf[12];
|
||||
n = 0 /* FormatCga(m->bx[0], buf) */;
|
||||
w = tpenc(VidyaServiceXlatTeletype(m->ax[0]));
|
||||
do
|
||||
buf[n++] = w;
|
||||
do buf[n++] = w;
|
||||
while ((w >>= 8));
|
||||
PtyWrite(pty, buf, n);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ o/$(MODE)/tool/build/blinkenlights.com.dbg: \
|
|||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PRECIOUS: o/$(MODE)/tool/build/blinkenlights.com
|
||||
o/$(MODE)/tool/build/blinkenlights.com: \
|
||||
o/$(MODE)/tool/build/blinkenlights.com.dbg \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
|
|
|
@ -88,6 +88,14 @@ else
|
|||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
||||
errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)\r\n')
|
||||
if errno then
|
||||
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))})
|
||||
else
|
||||
Write('<dd>%s\r\n' % {enabled})
|
||||
end
|
||||
|
||||
errno, enabled = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)
|
||||
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)\r\n')
|
||||
if errno then
|
||||
|
|
|
@ -13,9 +13,9 @@ function main()
|
|||
syscall = 'pipe'
|
||||
reader, writer, errno = unix.pipe()
|
||||
if reader then
|
||||
-- oldint = unix.sigaction(unix.SIGINT, unix.SIG_IGN)
|
||||
-- oldquit = unix.sigaction(unix.SIGQUIT, unix.SIG_IGN)
|
||||
-- oldmask = unix.sigprocmask(unix.SIG_BLOCK, unix.SIGCHLD)
|
||||
oldint = unix.sigaction(unix.SIGINT, unix.SIG_IGN)
|
||||
oldquit = unix.sigaction(unix.SIGQUIT, unix.SIG_IGN)
|
||||
oldmask = unix.sigprocmask(unix.SIG_BLOCK, (1 << (unix.SIGCHLD - 1)))
|
||||
syscall = 'fork'
|
||||
child, errno = unix.fork()
|
||||
if child then
|
||||
|
|
|
@ -42,6 +42,7 @@ FLAGS
|
|||
-u uniprocess
|
||||
-z print port
|
||||
-m log messages
|
||||
-i interpreter mode
|
||||
-b log message bodies
|
||||
-a log resource usage
|
||||
-g log handler latency
|
||||
|
@ -236,9 +237,9 @@ USAGE
|
|||
|
||||
REPL
|
||||
|
||||
Your redbean displays a REPL that lets you modify the state of the
|
||||
main server process while your server is running. Any changes will
|
||||
propagate into forked clients.
|
||||
Your redbean displays a Read-Eval-Print-Loop that lets you modify the
|
||||
state of the main server process while your server is running. Any
|
||||
changes will propagate into forked clients.
|
||||
|
||||
Your REPL is displayed only when redbean is run as a non-daemon in a
|
||||
UNIX terminal or the Windows 10 command prompt or powershell. Since
|
||||
|
@ -250,6 +251,20 @@ REPL
|
|||
|
||||
A history of your commands is saved to `~/.redbean_history`.
|
||||
|
||||
If you love the redbean repl and want to use it as your language
|
||||
interpreter then you can pass the `-i` flag to put redbean into
|
||||
interpreter mode.
|
||||
|
||||
redbean.com -i binarytrees.lua 15
|
||||
|
||||
In this mode redbean won't start a web server and instead functions
|
||||
like the `lua` command. The first command line argument becomes the
|
||||
script you want to run. If you don't supply a script, then the repl
|
||||
without a web server is displayed.
|
||||
|
||||
This can be useful for testing, since the redbean extensions and
|
||||
modules for the Lua language are still made available.
|
||||
|
||||
|
||||
SECURITY
|
||||
|
||||
|
@ -357,12 +372,36 @@ SPECIAL PATHS
|
|||
|
||||
GLOBALS
|
||||
|
||||
argv: array[str]
|
||||
arg: array[str]
|
||||
|
||||
Array of command line arguments, excluding those parsed by
|
||||
getopt() in the C code, which stops parsing at the first
|
||||
non-hyphenated arg. In some cases you can use the magic --
|
||||
argument to delimit C from Lua arguments.
|
||||
|
||||
For example, if you launch your redbean as follows:
|
||||
|
||||
redbean.com -v arg1 arg2
|
||||
|
||||
Then your `/.init.lua` file will have the `arg` array like:
|
||||
|
||||
arg[-1] = '/usr/bin/redbean.com'
|
||||
arg[ 0] = '/zip/.init.lua'
|
||||
arg[ 1] = 'arg1'
|
||||
arg[ 2] = 'arg2'
|
||||
|
||||
If you launch redbean in interpreter mode (rather than web
|
||||
server) mode, then an invocation like this:
|
||||
|
||||
./redbean.com -i script.lua arg1 arg2
|
||||
|
||||
Would have an `arg` array like this:
|
||||
|
||||
arg[-1] = './redbean.com'
|
||||
arg[ 0] = 'script.lua'
|
||||
arg[ 1] = 'arg1'
|
||||
arg[ 2] = 'arg2'
|
||||
|
||||
|
||||
HOOKS
|
||||
|
||||
|
@ -522,7 +561,8 @@ FUNCTIONS
|
|||
- useoutput: (bool=false) encodes the result directly to the
|
||||
output buffer and returns `nil` value. This option is
|
||||
ignored if used outside of request handling code.
|
||||
- numformat: (string="%.14g") sets numeric format to be used.
|
||||
- numformat: sets numeric format to be used, which can be 'g',
|
||||
'f', or 'a' [experimental api]
|
||||
- maxdepth: (number=64) sets the max number of nested tables.
|
||||
|
||||
EncodeLua(value[,options:table]) → json:str
|
||||
|
@ -531,7 +571,6 @@ FUNCTIONS
|
|||
- useoutput: (bool=false) encodes the result directly to the
|
||||
output buffer and returns `nil` value. This option is
|
||||
ignored if used outside of request handling code.
|
||||
- numformat: (string="%.14g") sets numeric format to be used.
|
||||
- maxdepth: (number=64) sets the max number of nested tables.
|
||||
|
||||
EncodeLatin1(utf-8:str[,flags:int]) → iso-8859-1:str
|
||||
|
@ -1329,52 +1368,25 @@ MAXMIND MODULE
|
|||
|
||||
UNIX MODULE
|
||||
|
||||
This module exposes the low-level UNIX system call interface. The way
|
||||
these functions work is they'll only throw a Lua exception if there's
|
||||
some kind of error obtaining the required arguments. Once Lua reads
|
||||
the arguments and the call is delegated to the system call interface,
|
||||
all further errors won't be raised, but rather returned as errnos,
|
||||
which should always be checked. For example, most syscalls follow:
|
||||
This module exposes the low-level UNIX system call interface. This
|
||||
module works on all supported platforms, including Windows NT.
|
||||
|
||||
errno = unix.foo(...)
|
||||
if errno then
|
||||
Log(kLogWarn, 'foo() failed: %s' % {unix.strerror(errno)})
|
||||
end
|
||||
|
||||
Any POSIX API that's defined as returning 0 on success or -1 on error
|
||||
is wrapped here to return nil on success and an integer on error. To
|
||||
see which errnos are possible for which system calls, please see the
|
||||
comprehensive index at the bottom of this section.
|
||||
|
||||
In cases where POSIX defines an API as returning codes on success we
|
||||
wrap the APIs as follows:
|
||||
|
||||
rc, errno = unix.bar(...)
|
||||
if rc then
|
||||
Log(kLogWarn, 'foo() succeeded: %d' % {rc})
|
||||
else
|
||||
Log(kLogWarn, 'foo() failed: %s' % {unix.strerror(errno)})
|
||||
end
|
||||
|
||||
If the above code succeeds, `rc` will be non-nil and `errno` will be
|
||||
`nil`. If the above code fails, `rc` will be nil and `errno` will be
|
||||
an integer greater than zero.
|
||||
|
||||
UNIX FUNCTIONS
|
||||
|
||||
unix.read(fd:int[, bufsiz:int, offset:int]) → data:str[, errno:int]
|
||||
|
||||
Reads from file descriptor.
|
||||
|
||||
unix.write(fd:int, data[, offset:int]) → wrote:int[, errno:int]
|
||||
|
||||
Writes to file descriptor.
|
||||
|
||||
unix.open(path:str, flags:int[, mode:int]) → fd:int[, errno:int]
|
||||
unix.open(path:str, flags:int[, mode:int]) → fd:int, unix.Errno
|
||||
|
||||
Opens file.
|
||||
|
||||
`flags` should have one of `O_RDONLY`, `O_WRONLY`, or `O_RDWR`.
|
||||
Returns a file descriptor integer that needs to be closed, e.g.
|
||||
|
||||
fd = assert(open("/etc/passwd", unix.O_RDONLY))
|
||||
print(unix.read(fd))
|
||||
unix.close(fd)
|
||||
|
||||
`flags` should have one of:
|
||||
|
||||
- `O_RDONLY`: open for reading
|
||||
- `O_WRONLY`: open for writing
|
||||
- `O_RDWR`: open for reading and writing
|
||||
|
||||
The following values may also be OR'd into `flags`:
|
||||
|
||||
- `O_CREAT`: create file if it doesn't exist
|
||||
|
@ -1412,10 +1424,18 @@ UNIX MODULE
|
|||
already. If it does exist then `nil` is returned along with
|
||||
`errno` set to `EEXIST`.
|
||||
|
||||
unix.close(fd:int) → errno:int
|
||||
unix.close(fd:int) → ok:bool, unix.Errno
|
||||
|
||||
Closes file descriptor.
|
||||
|
||||
unix.read(fd:int[, bufsiz:int, offset:int]) → data:str, unix.Errno
|
||||
|
||||
Reads from file descriptor.
|
||||
|
||||
unix.write(fd:int, data[, offset:int]) → wrote:int, unix.Errno
|
||||
|
||||
Writes to file descriptor.
|
||||
|
||||
unix.exit([exitcode]) → ⊥
|
||||
|
||||
Invokes `_Exit(exitcode)` on the process. This will immediately
|
||||
|
@ -1443,21 +1463,27 @@ UNIX MODULE
|
|||
command prompt inserts multiple environment variables with empty
|
||||
string as keys, for its internal bookkeeping.
|
||||
|
||||
unix.fork() → childpid|0:int[, errno:int]
|
||||
unix.fork() → childpid|0:int, unix.Errno
|
||||
|
||||
Creates a new process mitosis style. This returns twice. The
|
||||
parent process gets the nonzero pid. The child gets zero.
|
||||
|
||||
unix.commandv(prog:str) → path:str[, errno:int]
|
||||
unix.commandv(prog:str) → path:str, unix.Errno
|
||||
|
||||
Performs `$PATH` lookup of executable. We automatically suffix
|
||||
`.com` and `.exe` for all platforms when path searching.
|
||||
By default, the current directory is not on the path.
|
||||
If `prog` is an absolute path, then it's returned as-is. If
|
||||
`prog` contains slashes then it's not path searched either and
|
||||
will be returned if it exists.
|
||||
Performs `$PATH` lookup of executable.
|
||||
|
||||
unix.execve(prog:str[, args:List<*>[, env:List<*>]]) → errno:int
|
||||
unix = require "unix"
|
||||
prog = assert(unix.commandv("ls"))
|
||||
unix.execve(prog, {prog, "-hal", "."}, {PATH="/bin"})
|
||||
unix.exit(127)
|
||||
|
||||
We automatically suffix `.com` and `.exe` for all platforms when
|
||||
path searching. By default, the current directory is not on the
|
||||
path. If `prog` is an absolute path, then it's returned as-is. If
|
||||
`prog` contains slashes then it's not path searched either and will
|
||||
be returned if it exists.
|
||||
|
||||
unix.execve(prog:str[, args:List<*>[, env:List<*>]]) → false, unix.Errno
|
||||
|
||||
Exits current process, replacing it with a new instance of the
|
||||
specified program. `prog` needs to be an absolute path, see
|
||||
|
@ -1490,7 +1516,7 @@ UNIX MODULE
|
|||
`EAGAIN` is returned if you've enforced a max number of
|
||||
processes using `setrlimit(RLIMIT_NPROC)`.
|
||||
|
||||
unix.dup(oldfd:int[, newfd:int[, flags:int]]) → newfd:int, errno:int
|
||||
unix.dup(oldfd:int[, newfd:int[, flags:int]]) → newfd:int, unix.Errno
|
||||
|
||||
Duplicates file descriptor.
|
||||
|
||||
|
@ -1501,7 +1527,7 @@ UNIX MODULE
|
|||
`flags` can have `O_CLOEXEC` which means the returned file
|
||||
descriptors will be automatically closed upon execve().
|
||||
|
||||
unix.pipe([flags:int]) → reader:int, writer:int[, errno:int]
|
||||
unix.pipe([flags:int]) → reader:int, unix.Errno, writer:int
|
||||
|
||||
Creates fifo which enables communication between processes.
|
||||
Returns two file descriptors: one for reading and one for
|
||||
|
@ -1537,7 +1563,7 @@ UNIX MODULE
|
|||
end
|
||||
|
||||
unix.wait([pid:int, options:int])
|
||||
→ pid:int, wstatus:int, nil, errno:int
|
||||
→ pid:int, unix.Errno, wstatus:int
|
||||
|
||||
Waits for subprocess to terminate.
|
||||
|
||||
|
@ -1590,22 +1616,22 @@ UNIX MODULE
|
|||
|
||||
This function does not fail.
|
||||
|
||||
unix.kill(pid, sig) → errno:int
|
||||
unix.kill(pid, sig) → ok:bool, unix.Errno
|
||||
|
||||
Returns process id of current process.
|
||||
|
||||
unix.raise(sig) → rc:int[, errno:int]
|
||||
unix.raise(sig) → rc:int, unix.Errno
|
||||
|
||||
Triggers signal in current process.
|
||||
This is pretty much the same as `kill(getpid(), sig)`.
|
||||
|
||||
unix.access(path:str, how) → errno:int
|
||||
unix.access(path:str, how) → ok:bool, unix.Errno
|
||||
|
||||
Checks if effective user of current process has permission to access
|
||||
file. `how` can be `R_OK`, `W_OK`, `X_OK`, or `F_OK` to check for
|
||||
read, write, execute, and existence respectively.
|
||||
|
||||
unix.mkdir(path:str, mode) → errno:int
|
||||
unix.mkdir(path:str, mode) → ok:bool, unix.Errno
|
||||
|
||||
Makes directory.
|
||||
|
||||
|
@ -1628,7 +1654,7 @@ UNIX MODULE
|
|||
|
||||
Fails with `ENAMETOOLONG` if the path is too long.
|
||||
|
||||
unix.makedirs(path:str, mode) → errno:int
|
||||
unix.makedirs(path:str, mode) → ok:bool, unix.Errno
|
||||
|
||||
Makes directories.
|
||||
|
||||
|
@ -1639,48 +1665,48 @@ UNIX MODULE
|
|||
Unlike mkdir() this convenience wrapper will automatically create
|
||||
parent parent directories as needed.
|
||||
|
||||
unix.chdir(path:str) → errno:int
|
||||
unix.chdir(path:str) → ok:bool, unix.Errno
|
||||
|
||||
Changes current directory to `path`.
|
||||
|
||||
unix.unlink(path:str) → errno:int
|
||||
unix.unlink(path:str) → ok:bool, unix.Errno
|
||||
|
||||
Removes file at `path`.
|
||||
|
||||
unix.rmdir(path:str) → errno:int
|
||||
unix.rmdir(path:str) → ok:bool, unix.Errno
|
||||
|
||||
Removes empty directory at `path`.
|
||||
|
||||
unix.rename(oldpath:str, newpath:str) → errno:int
|
||||
unix.rename(oldpath:str, newpath:str) → ok:bool, unix.Errno
|
||||
|
||||
Renames file or directory.
|
||||
|
||||
unix.link(existingpath:str, newpath:str) → errno:int
|
||||
unix.link(existingpath:str, newpath:str) → ok:bool, unix.Errno
|
||||
|
||||
Creates hard link, so your underlying inode has two names.
|
||||
|
||||
unix.symlink(target:str, linkpath:str) → errno:int
|
||||
unix.symlink(target:str, linkpath:str) → ok:bool, unix.Errno
|
||||
|
||||
Creates soft link, or a symbolic link.
|
||||
|
||||
unix.realpath(filename:str) → abspath:str[, errno:int]
|
||||
unix.realpath(filename:str) → abspath:str, unix.Errno
|
||||
|
||||
Returns absolute path of filename, with `.` and `..` components
|
||||
removed, and symlinks will be resolved.
|
||||
|
||||
unix.chown(path:str, uid, gid) → errno:int
|
||||
unix.chown(path:str, uid, gid) → ok:bool, unix.Errno
|
||||
|
||||
Changes user and gorup on file.
|
||||
|
||||
unix.chmod(path:str, mode) → errno:int
|
||||
unix.chmod(path:str, mode) → ok:bool, unix.Errno
|
||||
|
||||
Changes mode bits on file.
|
||||
|
||||
unix.getcwd() → path:str[, errno:int]
|
||||
unix.getcwd() → path:str, unix.Errno
|
||||
|
||||
Returns current working directory.
|
||||
|
||||
unix.fcntl(fd:int, cmd:int[, arg:int]) → rc:int[, errno:int]
|
||||
unix.fcntl(fd:int, cmd:int[, arg:int]) → rc:int, unix.Errno
|
||||
|
||||
Manipulates file descriptor.
|
||||
|
||||
|
@ -1691,27 +1717,27 @@ UNIX MODULE
|
|||
POSIX advisory locks can be controlled by setting `cmd` to
|
||||
`F_UNLCK`, `F_RDLCK`, `F_WRLCK`, `F_SETLK`, or `F_SETLKW`.
|
||||
|
||||
unix.getsid(pid:int) → sid:int[, errno:int]
|
||||
unix.getsid(pid:int) → sid:int, unix.Errno
|
||||
|
||||
Gets session id.
|
||||
|
||||
unix.getpgrp() → pgid:int[, errno:int]
|
||||
unix.getpgrp() → pgid:int, unix.Errno
|
||||
|
||||
Gets process group id.
|
||||
|
||||
unix.setpgrp() → pgid:int[, errno:int]
|
||||
unix.setpgrp() → pgid:int, unix.Errno
|
||||
|
||||
Sets process group id. This is the same as `setpgid(0,0)`.
|
||||
|
||||
unix.setpgid(pid:int, pgid:int) → pgid:int[, errno:int]
|
||||
unix.setpgid(pid:int, pgid:int) → pgid:int, unix.Errno
|
||||
|
||||
Sets process group id the modern way.
|
||||
|
||||
unix.getpgid(pid) → pgid:int[, errno:int]
|
||||
unix.getpgid(pid) → pgid:int, unix.Errno
|
||||
|
||||
Gets process group id the modern wayp.
|
||||
|
||||
unix.setsid() → sid:int[, errno:int]
|
||||
unix.setsid() → sid:int, unix.Errno
|
||||
|
||||
Sets session id.
|
||||
|
||||
|
@ -1756,13 +1782,13 @@ UNIX MODULE
|
|||
|
||||
This function does not fail.
|
||||
|
||||
unix.chroot(path:str) → errno:int
|
||||
unix.chroot(path:str) → ok:bool, unix.Errno
|
||||
|
||||
Changes root directory.
|
||||
|
||||
Returns `ENOSYS` on Windows NT.
|
||||
|
||||
unix.setuid(uid:int) → errno:int
|
||||
unix.setuid(uid:int) → ok:bool, unix.Errno
|
||||
|
||||
Sets user id.
|
||||
|
||||
|
@ -1798,13 +1824,13 @@ UNIX MODULE
|
|||
|
||||
Returns `ENOSYS` on Windows NT if `uid` isn't `getuid()`.
|
||||
|
||||
unix.setgid(gid:int) → errno:int
|
||||
unix.setgid(gid:int) → ok:bool, unix.Errno
|
||||
|
||||
Sets group id.
|
||||
|
||||
Returns `ENOSYS` on Windows NT if `gid` isn't `getgid()`.
|
||||
|
||||
unix.setresuid(real:int, effective:int, saved:int) → errno:int
|
||||
unix.setresuid(real:int, effective:int, saved:int) → ok:bool, unix.Errno
|
||||
|
||||
Sets real, effective, and saved user ids.
|
||||
|
||||
|
@ -1813,7 +1839,7 @@ UNIX MODULE
|
|||
Returns `ENOSYS` on Windows NT.
|
||||
Returns `ENOSYS` on Macintosh and NetBSD if `saved` isn't -1.
|
||||
|
||||
unix.setresgid(real:int, effective:int, saved:int) → errno:int
|
||||
unix.setresgid(real:int, effective:int, saved:int) → ok:bool, unix.Errno
|
||||
|
||||
Sets real, effective, and saved group ids.
|
||||
|
||||
|
@ -1854,30 +1880,40 @@ UNIX MODULE
|
|||
This function currently works on Linux, Windows, and NetBSD. On
|
||||
WIN32 it uses the ReportEvent() facility.
|
||||
|
||||
unix.clock_gettime([clock]) → seconds, nanos, errno:int
|
||||
unix.clock_gettime([clock:int]) → seconds:int, unix.Errno, nanos:int
|
||||
|
||||
Returns nanosecond precision timestamp from the system.
|
||||
|
||||
`clock` should be `CLOCK_REALTIME`, `CLOCK_MONOTONIC`, or
|
||||
`CLOCK_MONOTONIC_RAW` since they work across platforms.
|
||||
You may also try your luck with `CLOCK_REALTIME_COARSE`,
|
||||
`CLOCK_MONOTONIC_COARSE`, `CLOCK_PROCESS_CPUTIME_ID`,
|
||||
`CLOCK_TAI`, `CLOCK_PROF`, `CLOCK_BOOTTIME`,
|
||||
`CLOCK_REALTIME_ALARM`, and `CLOCK_BOOTTIME_ALARM`,
|
||||
`clock` can be any one of of:
|
||||
|
||||
- `CLOCK_REALTIME`: universally supported
|
||||
- `CLOCK_MONOTONIC`: universally supported
|
||||
- `CLOCK_MONOTONIC_RAW`: nearly universally supported
|
||||
- `CLOCK_PROCESS_CPUTIME_ID`: linux and bsd
|
||||
- `CLOCK_THREAD_CPUTIME_ID`: linux and bsd
|
||||
- `CLOCK_REALTIME_COARSE`: : linux and openbsd
|
||||
- `CLOCK_MONOTONIC_COARSE`: linux
|
||||
- `CLOCK_PROF`: linux and netbsd
|
||||
- `CLOCK_BOOTTIME`: linux and openbsd
|
||||
- `CLOCK_REALTIME_ALARM`: linux-only
|
||||
- `CLOCK_BOOTTIME_ALARM`: linux-only
|
||||
- `CLOCK_TAI`: ilnux-only
|
||||
|
||||
Returns `EINVAL` if clock isn't supported on platform.
|
||||
|
||||
unix.nanosleep(seconds:int[, nanos:int])
|
||||
→ remseconds:int, remnanos:int[, errno:int]
|
||||
→ remseconds:int, unix.Errno, remnanos:int
|
||||
|
||||
Sleeps with nanosecond precision.
|
||||
|
||||
unix.sync()
|
||||
unix.fsync(fd:int) → errno:int
|
||||
unix.fdatasync(fd:int) → errno:int
|
||||
unix.fsync(fd:int) → ok:bool, unix.Errno
|
||||
unix.fdatasync(fd:int) → ok:bool, unix.Errno
|
||||
|
||||
These functions are used to make programs slower by asking the
|
||||
operating system to flush data to the physical medium.
|
||||
|
||||
unix.lseek(fd:int, offset:int, whence:int) → newpos:int[, errno:int]
|
||||
unix.lseek(fd:int, offset:int, whence:int) → newpos:int, unix.Errno
|
||||
|
||||
Seeks to file position.
|
||||
|
||||
|
@ -1889,21 +1925,21 @@ UNIX MODULE
|
|||
|
||||
Returns the new position relative to the start of the file.
|
||||
|
||||
unix.truncate(path:str[, length:int]) → errno:int
|
||||
unix.truncate(path:str[, length:int]) → ok:bool, unix.Errno
|
||||
|
||||
Reduces or extends underlying physical medium of file.
|
||||
If file was originally larger, content >length is lost.
|
||||
|
||||
`length` defaults to zero.
|
||||
|
||||
unix.ftruncate(fd:int[, length:int]) → errno:int
|
||||
unix.ftruncate(fd:int[, length:int]) → ok:bool, unix.Errno
|
||||
|
||||
Reduces or extends underlying physical medium of open file.
|
||||
If file was originally larger, content >length is lost.
|
||||
|
||||
`length` defaults to zero.
|
||||
|
||||
unix.socket([family:int[, type:int[, protocol:int]]]) → fd:int[, errno:int]
|
||||
unix.socket([family:int[, type:int[, protocol:int]]]) → fd:int, unix.Errno
|
||||
|
||||
`family` defaults to `AF_INET` and can be:
|
||||
|
||||
|
@ -1929,14 +1965,14 @@ UNIX MODULE
|
|||
`SOCK_CLOEXEC` may be bitwise or'd into `type`.
|
||||
|
||||
unix.socketpair([family:int[, type:int[, protocol:int]]])
|
||||
→ fd1:int, fd2:int[, errno:int]
|
||||
→ fd1:int, unix.Errno, fd2:int
|
||||
|
||||
`SOCK_CLOEXEC` may be or'd into type
|
||||
`family` defaults to `AF_INET`
|
||||
`type` defaults to `SOCK_STREAM`
|
||||
`protocol` defaults to `IPPROTO_TCP`
|
||||
|
||||
unix.bind(fd:int[, ip:uint32, port:uint16]) → errno:int
|
||||
unix.bind(fd:int[, ip:uint32, port:uint16]) → ok:bool, unix.Errno
|
||||
|
||||
Binds socket.
|
||||
|
||||
|
@ -1970,19 +2006,21 @@ UNIX MODULE
|
|||
Further note that calling `unix.bind(sock)` is equivalent to not
|
||||
calling bind() at all, since the above behavior is the default.
|
||||
|
||||
unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, errno:int]
|
||||
unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}, unix.Errno
|
||||
|
||||
Returns list of network adapter addresses.
|
||||
|
||||
unix.getsockopt(fd:int, level:int, optname:int) → errno:int, ...
|
||||
unix.setsockopt(fd:int, level:int, optname:int, ...) → errno:int
|
||||
unix.getsockopt(fd:int, level:int, optname:int) → ok:bool, unix.Errno, ...
|
||||
unix.setsockopt(fd:int, level:int, optname:int, ...) → ok:bool, unix.Errno
|
||||
|
||||
Tunes networking parameters.
|
||||
|
||||
`level` and `optname` may be one of the following. Please note the
|
||||
type signature for getsockopt() changes depending on these values:
|
||||
`level` and `optname` may be one of the following. The ellipses type
|
||||
signature above changes depending on which options are used.
|
||||
|
||||
- `SOL_SOCKET` + `SO_TYPE`: bool
|
||||
- `SOL_SOCKET` + `SO_DEBUG`: bool
|
||||
- `SOL_SOCKET` + `SO_ACCEPTCONN`: bool
|
||||
- `SOL_SOCKET` + `SO_BROADCAST`: bool
|
||||
- `SOL_SOCKET` + `SO_REUSEADDR`: bool
|
||||
- `SOL_SOCKET` + `SO_REUSEPORT`: bool
|
||||
|
@ -2016,15 +2054,8 @@ UNIX MODULE
|
|||
|
||||
Returns `ENOSYS` if setting isn't supported by the host o/s.
|
||||
|
||||
NOTE: The API for this function diverges from the the norm. `errno`
|
||||
needs to come first in the results, because otherwise we
|
||||
wouldn't know the arity of items to push before it. It's
|
||||
because Cosmopolitan Libc polyfills the magic numbers above as
|
||||
zero if the host operating system doesn't support them. If
|
||||
there's no error, then `errno` will be set to nil.
|
||||
|
||||
unix.poll({fd:int=events:int, ...}[, timeoutms:int])
|
||||
→ {fd:int=revents:int, ...}[, errno:int]
|
||||
→ {fd:int=revents:int, ...}, unix.Errno
|
||||
|
||||
Checks for events on a set of file descriptors.
|
||||
|
||||
|
@ -2037,19 +2068,25 @@ UNIX MODULE
|
|||
then that means block as long as it takes until there's an event or
|
||||
an interrupt. If the timeout expires, an empty table is returned.
|
||||
|
||||
unix.gethostname() → host:str[, errno:int]
|
||||
unix.gethostname() → host:str, unix.Errno
|
||||
|
||||
Returns hostname of system.
|
||||
|
||||
unix.listen(fd:int[, backlog]) → errno:int
|
||||
unix.listen(fd:int[, backlog:int]) → ok:bool, unix.Errno
|
||||
|
||||
Begins listening for incoming connections on a socket.
|
||||
|
||||
unix.accept(serverfd) → clientfd:int, ip:uint32, port:uint16[, errno:int]
|
||||
unix.accept(serverfd:int[, flags:int])
|
||||
→ clientfd:int, unix.Errno, ip:uint32, port:uint16
|
||||
|
||||
Accepts new client socket descriptor for a listening tcp socket.
|
||||
|
||||
unix.connect(fd:int, ip:uint32, port:uint16) → rc:int[, errno:int]
|
||||
`flags` can have any of:
|
||||
|
||||
- `SOCK_CLOEXEC`
|
||||
- `SOCK_NONBLOCK`
|
||||
|
||||
unix.connect(fd:int, ip:uint32, port:uint16) → ok:bool, unix.Errno
|
||||
|
||||
Connects a TCP socket to a remote host.
|
||||
|
||||
|
@ -2057,24 +2094,34 @@ UNIX MODULE
|
|||
remembers the intended address so that send() or write() may be used
|
||||
rather than sendto().
|
||||
|
||||
unix.getsockname(fd:int) → ip:uint32, port:uint16[, errno:int]
|
||||
unix.getsockname(fd:int) → ip:uint32, unix.Errno, port:uint16
|
||||
|
||||
Retrieves the local address of a socket.
|
||||
|
||||
unix.getpeername(fd:int) → ip:uint32, port:uint16[, errno:int]
|
||||
unix.getpeername(fd:int) → ip:uint32, unix.Errno, port:uint16
|
||||
|
||||
Retrieves the remote address of a socket.
|
||||
|
||||
unix.recv(fd:int[, bufsiz:int[, flags:int]]) → data:str[, errno:int]
|
||||
unix.recv(fd:int[, bufsiz:int[, flags:int]]) → data:str, unix.Errno
|
||||
|
||||
`flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
`flags` can have:
|
||||
|
||||
- `MSG_WAITALL`
|
||||
- `MSG_DONTROUTE`
|
||||
- `MSG_PEEK`
|
||||
- `MSG_OOB`
|
||||
|
||||
unix.recvfrom(fd:int[, bufsiz:int[, flags:int]])
|
||||
→ data:str, ip:uint32, port:uint16, errno:int
|
||||
→ data:str, unix.Errno, ip:uint32, port:uint16
|
||||
|
||||
`flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||
`flags` can have:
|
||||
|
||||
unix.send(fd:int, data:str[, flags:int]) → sent:int[, errno:int]
|
||||
- `MSG_WAITALL`
|
||||
- `MSG_DONTROUTE`
|
||||
- `MSG_PEEK`
|
||||
- `MSG_OOB`
|
||||
|
||||
unix.send(fd:int, data:str[, flags:int]) → sent:int, unix.Errno
|
||||
|
||||
This is the same as `write` except it has a `flags` argument
|
||||
that's intended for sockets.
|
||||
|
@ -2082,24 +2129,36 @@ UNIX MODULE
|
|||
`flags` can have `MSG_OOB`, `MSG_DONTROUTE`, or `MSG_NOSIGNAL`.
|
||||
|
||||
unix.sendto(fd:int, data:str, ip:int, port:int[, flags:int])
|
||||
→ sent:int, errno:int
|
||||
→ sent:int, unix.Errno
|
||||
|
||||
This is useful for sending messages over UDP sockets to specific
|
||||
addresses.
|
||||
|
||||
`flags` can have `MSG_OOB`, `MSG_DONTROUTE`, or `MSG_NOSIGNAL`.
|
||||
|
||||
unix.shutdown(fd:int, how:int) → errno:int
|
||||
unix.shutdown(fd:int, how:int) → ok:bool, unix.Errno
|
||||
|
||||
Partially closes socket. `how` can be `SHUT_RD`, `SHUT_WR`, or
|
||||
`SHUT_RDWR`.
|
||||
|
||||
unix.sigprocmask(how[, mask]) → oldmask, errno:int
|
||||
unix.sigprocmask(how:int[, mask:int]) → oldmask:int, unix.Errno
|
||||
|
||||
`how` can be `SIG_BLOCK`, `SIG_UNBLOCK`, `SIG_SETMASK`
|
||||
Manipulates bitset of signals blocked by process.
|
||||
|
||||
`how` can be one of:
|
||||
|
||||
- `SIG_BLOCK`: bitwise ors `mask` into set of blocked signals
|
||||
- `SIG_UNBLOCK`: removes bits in `mask` from set of blocked signals
|
||||
- `SIG_SETMASK`: replaces process signal mask with `mask`
|
||||
|
||||
`mask` is a word encoded bitset of signals. Valid signal numbers
|
||||
start at 1 and vary between platforms. The most famous `SIGKILL`
|
||||
can't be masked, but if it could, it's assigned the number `9`
|
||||
across all platforms, so if you wanted to add it to a bitset, you
|
||||
would say, `1 << 8` or in general terms `1 << (sig - 1)`.
|
||||
|
||||
unix.sigaction(sig:int[, handler:func|int[, flags:int[, mask:int]]])
|
||||
→ oldhandler:func|int, flags:int, mask:int, errno:int
|
||||
→ oldhandler:func|int, unix.Errno, flags:int, mask:int
|
||||
|
||||
`handler` can be `SIG_IGN`, `SIG_DFL`, `intptr_t`, or a Lua
|
||||
function. `sig` can be `SIGINT`, `SIGQUIT`, `SIGTERM`, etc.
|
||||
|
@ -2115,7 +2174,7 @@ UNIX MODULE
|
|||
|
||||
It's a good idea to not do too much work in a signal handler.
|
||||
|
||||
unix.sigsuspend([mask:int]) → errno:int
|
||||
unix.sigsuspend([mask]) → false, unix.Errno
|
||||
|
||||
Waits for signal to be delivered.
|
||||
|
||||
|
@ -2123,7 +2182,7 @@ UNIX MODULE
|
|||
system call. `mask` specifies which signals should be blocked.
|
||||
|
||||
unix.setitimer(which[, intsec, intmicros, valsec, valmicros])
|
||||
→ intsec, intns, valsec, valns, errno:int
|
||||
→ intsec, unix.Errno, intns, valsec, valns
|
||||
|
||||
Causes `SIGALRM` signals to be generated at some point(s) in the
|
||||
future. The `which` parameter should be `ITIMER_REAL`.
|
||||
|
@ -2145,17 +2204,17 @@ UNIX MODULE
|
|||
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
||||
unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0)
|
||||
|
||||
unix.strerrno(errno:int) → str
|
||||
unix.strerrno(unix.Errno) → str
|
||||
|
||||
Turns `errno` code into its symbolic name, e.g. `"EINTR"`. If
|
||||
`errno` isn't known, this function returns nil.
|
||||
|
||||
unix.strerdoc(errno:int) → str
|
||||
unix.strerdoc(unix.Errno) → str
|
||||
|
||||
Turns `errno` code into a descriptive string. If `errno` isn't
|
||||
known, this function returns nil.
|
||||
|
||||
unix.strerror(errno:int) → str
|
||||
unix.strerror(unix.Errno) → str
|
||||
|
||||
Turns `errno` code into longest string describing the error. This
|
||||
includes the output of both strerrno() and strerror() as well as the
|
||||
|
@ -2167,7 +2226,7 @@ UNIX MODULE
|
|||
Turns platform-specific `sig` code into its name, e.g.
|
||||
`strsignal(9)` always returns `"SIGKILL"`.
|
||||
|
||||
unix.setrlimit(resource:int, soft:int[, hard:int]) → errno:int
|
||||
unix.setrlimit(resource:int, soft:int[, hard:int]) → ok:bool, unix.Errno
|
||||
|
||||
Changes resource limit.
|
||||
|
||||
|
@ -2198,72 +2257,79 @@ UNIX MODULE
|
|||
127. On most platforms these limits are enforced by the kernel and
|
||||
as such are inherited by subprocesses.
|
||||
|
||||
unix.getrlimit(resource:int) → soft:int, hard:int[, errno:int]
|
||||
unix.getrlimit(resource:int) → soft:int, unix.Errno, hard:int
|
||||
|
||||
Returns information about resource limit.
|
||||
|
||||
unix.stat(x) → UnixStat*[, errno:int]
|
||||
unix.stat(x) → unix.Stat, Errno*
|
||||
|
||||
Gets information about file or directory. `x` may be a file or
|
||||
directory path string, or it may be a file descriptor int that
|
||||
was made by open().
|
||||
|
||||
unix.opendir(path:str) → UnixDir*[, errno:int]
|
||||
unix.opendir(path:str) → unix.Dir, Errno*
|
||||
|
||||
Opens directory for listing its contents.
|
||||
|
||||
unix.fdopendir(fd:int) → UnixDir*[, errno:int]
|
||||
unix.fdopendir(fd:int) → unix.Dir, Errno*
|
||||
|
||||
Opens directory for listing its contents, via an fd.
|
||||
|
||||
`fd` should be created by `open(path, O_RDONLY|O_DIRECTORY)`. The
|
||||
returned UnixDir* ownership takes ownership of the file descriptor
|
||||
returned unix.Dir ownership takes ownership of the file descriptor
|
||||
and will close it automatically when garbage collected.
|
||||
|
||||
UNIX DIR OBJECT
|
||||
|
||||
UnixDir* objects are created by opendir() or fdopendir(). The
|
||||
unix.Dir objects are created by opendir() or fdopendir(). The
|
||||
following methods are available:
|
||||
|
||||
UnixDir:close() → errno:int
|
||||
unix.Dir:close() → ok:bool, unix.Errno
|
||||
|
||||
may be called multiple times
|
||||
called by the garbage collector too
|
||||
|
||||
UnixDir:read() → name:str, kind:int, ino:int, off:int[, errno:int]
|
||||
unix.Dir:read() → name:str, unix.Errno, kind:int, ino:int, off:int
|
||||
|
||||
Returns `nil` if there are no more entries. Or error, `nil` will
|
||||
be returned and `errno` will be non-nil.
|
||||
|
||||
`kind` can be `DT_UNKNOWN`, `DT_REG`, `DT_DIR`, `DT_BLK`,
|
||||
`DT_LNK`, `DT_CHR`, `DT_FIFO`, or `DT_SOCK`.
|
||||
`kind` can be any of:
|
||||
|
||||
UnixDir:fd() → fd:int[, errno:int]
|
||||
- `DT_UNKNOWN`
|
||||
- `DT_REG`
|
||||
- `DT_DIR`
|
||||
- `DT_BLK`
|
||||
- `DT_LNK`
|
||||
- `DT_CHR`
|
||||
- `DT_FIFO`
|
||||
- `DT_SOCK`
|
||||
|
||||
unix.Dir:fd() → fd:int, unix.Errno
|
||||
|
||||
Returns file descriptor of open directory object.
|
||||
|
||||
Returns `EOPNOTSUPP` if using a `/zip/...` path.
|
||||
|
||||
Returns `EOPNOTSUPP` if using Windows NT.
|
||||
|
||||
UnixDir:tell() → offset:int
|
||||
unix.Dir:tell() → offset:int
|
||||
|
||||
Returns current arbitrary offset into stream.
|
||||
|
||||
UnixDir:rewind()
|
||||
unix.Dir:rewind()
|
||||
|
||||
Resets stream back to beginning.
|
||||
|
||||
UNIX STAT OBJECT
|
||||
|
||||
UnixStat* objects are created by stat() or fstat(). The following
|
||||
unix.Stat objects are created by stat() or fstat(). The following
|
||||
methods are available:
|
||||
|
||||
UnixStat:size() → bytes:int
|
||||
unix.Stat:size() → bytes:int
|
||||
|
||||
Size of file in bytes.
|
||||
|
||||
UnixStat:mode() → mode:int
|
||||
unix.Stat:mode() → mode:int
|
||||
|
||||
Contains file type and permissions.
|
||||
|
||||
|
@ -2280,49 +2346,49 @@ UNIX MODULE
|
|||
- `(st:mode() & 0170000) == 0120000` means symbolic link
|
||||
- `(st:mode() & 0170000) == 0140000` means socket
|
||||
|
||||
UnixStat:atim() → secs:int, nanos:int
|
||||
unix.Stat:atim() → secs:int, nanos:int
|
||||
|
||||
Size of file in bytes.
|
||||
|
||||
UnixStat:uid() → int
|
||||
unix.Stat:uid() → int
|
||||
|
||||
User ID of file owner.
|
||||
|
||||
UnixStat:gid() → int
|
||||
unix.Stat:gid() → int
|
||||
|
||||
Group ID of file owner.
|
||||
|
||||
UnixStat:mtim() → secs:int, nanos:int
|
||||
unix.Stat:mtim() → secs:int, nanos:int
|
||||
|
||||
Last modified time.
|
||||
|
||||
UnixStat:birthtim() → secs:int, nanos:int
|
||||
unix.Stat:birthtim() → secs:int, nanos:int
|
||||
|
||||
Creation time. Note that on Linux this is the mimimum of
|
||||
atom/mtim/ctim.
|
||||
|
||||
UnixStat:ctim() → secs:int, nanos:int
|
||||
unix.Stat:ctim() → secs:int, nanos:int
|
||||
|
||||
Complicated time. Means time file status was last changed on
|
||||
UNIX. Means creation time on Windows.
|
||||
|
||||
UnixStat:blocks() → int
|
||||
unix.Stat:blocks() → int
|
||||
|
||||
Number of blocks used by storage medium.
|
||||
|
||||
UnixStat:blksize() → int
|
||||
unix.Stat:blksize() → int
|
||||
|
||||
Block size is usually 4096 for file system files.
|
||||
|
||||
UnixStat:dev() → int
|
||||
unix.Stat:dev() → int
|
||||
|
||||
ID of device containing file.
|
||||
|
||||
UnixStat:ino() → int
|
||||
unix.Stat:ino() → int
|
||||
|
||||
Inode number.
|
||||
|
||||
UnixStat:rdev() → int
|
||||
unix.Stat:rdev() → int
|
||||
|
||||
Device ID (if special file)
|
||||
|
||||
|
|
|
@ -531,16 +531,16 @@ luaopen_argon2(lua_State *L)
|
|||
largon2_push_argon2_variants_table(L);
|
||||
lua_setfield(L, -2, "variants");
|
||||
|
||||
lua_pushstring(L, "3.0.1");
|
||||
lua_pushliteral(L, "3.0.1");
|
||||
lua_setfield(L, -2, "_VERSION");
|
||||
|
||||
lua_pushstring(L, "Thibault Charbonnier");
|
||||
lua_pushliteral(L, "Thibault Charbonnier");
|
||||
lua_setfield(L, -2, "_AUTHOR");
|
||||
|
||||
lua_pushstring(L, "MIT");
|
||||
lua_pushliteral(L, "MIT");
|
||||
lua_setfield(L, -2, "_LICENSE");
|
||||
|
||||
lua_pushstring(L, "https://github.com/thibaultcha/lua-argon2");
|
||||
lua_pushliteral(L, "https://github.com/thibaultcha/lua-argon2");
|
||||
lua_setfield(L, -2, "_URL");
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -18,10 +18,14 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/scale/cdecimate2xuint8x8.h"
|
||||
#include "libc/bits/popcnt.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bench.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
|
@ -31,6 +35,7 @@
|
|||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
@ -48,6 +53,10 @@
|
|||
#include "third_party/mbedtls/sha512.h"
|
||||
#include "tool/net/lfuncs.h"
|
||||
|
||||
static int Rdpid(void) {
|
||||
return rdpid();
|
||||
}
|
||||
|
||||
int LuaGetTime(lua_State *L) {
|
||||
lua_pushnumber(L, nowl());
|
||||
return 1;
|
||||
|
@ -64,12 +73,12 @@ int LuaRdtsc(lua_State *L) {
|
|||
}
|
||||
|
||||
int LuaGetCpuNode(lua_State *L) {
|
||||
lua_pushinteger(L, TSC_AUX_NODE(rdpid()));
|
||||
lua_pushinteger(L, TSC_AUX_NODE(Rdpid()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaGetCpuCore(lua_State *L) {
|
||||
lua_pushinteger(L, TSC_AUX_CORE(rdpid()));
|
||||
lua_pushinteger(L, TSC_AUX_CORE(Rdpid()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -560,3 +569,44 @@ void LuaPushUrlView(lua_State *L, struct UrlView *v) {
|
|||
lua_pushnil(L);
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t GetInterrupts(void) {
|
||||
struct rusage ru;
|
||||
if (!getrusage(RUSAGE_SELF, &ru)) {
|
||||
return ru.ru_nivcsw;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int LuaBenchmark(lua_State *L) {
|
||||
double avgticks;
|
||||
uint64_t t1, t2;
|
||||
int64_t interrupts;
|
||||
int core, iter, count, tries, attempts, maxattempts;
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
count = luaL_optinteger(L, 2, 100);
|
||||
maxattempts = luaL_optinteger(L, 3, 10);
|
||||
for (attempts = 0;;) {
|
||||
sched_yield();
|
||||
core = TSC_AUX_CORE(Rdpid());
|
||||
interrupts = GetInterrupts();
|
||||
for (avgticks = iter = 1; iter < count; ++iter) {
|
||||
t1 = __startbench();
|
||||
lua_pushvalue(L, 1);
|
||||
lua_call(L, 0, 0);
|
||||
t2 = __endbench();
|
||||
avgticks += 1. / iter * ((int)(t2 - t1) - avgticks);
|
||||
}
|
||||
++attempts;
|
||||
if (TSC_AUX_CORE(Rdpid()) == core && GetInterrupts() == interrupts) {
|
||||
break;
|
||||
} else if (attempts >= maxattempts) {
|
||||
return luaL_error(L, "system is under too much load to run benchmark");
|
||||
}
|
||||
}
|
||||
lua_pushnumber(L, ConvertTicksToNanos(avgticks));
|
||||
lua_pushinteger(L, avgticks);
|
||||
lua_pushinteger(L, attempts);
|
||||
return 3;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ int LuaUnix(lua_State *);
|
|||
int luaopen_argon2(lua_State *);
|
||||
int luaopen_lsqlite3(lua_State *);
|
||||
|
||||
int LuaBenchmark(lua_State *);
|
||||
int LuaBsf(lua_State *);
|
||||
int LuaBsr(lua_State *);
|
||||
int LuaCategorizeIp(lua_State *);
|
||||
|
|
|
@ -1936,7 +1936,7 @@ static const luaL_Reg sqlitelib[] = {
|
|||
|
||||
static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
|
||||
luaL_newmetatable(L, name);
|
||||
lua_pushstring(L, "__index");
|
||||
lua_pushliteral(L, "__index");
|
||||
lua_pushvalue(L, -2); /* push metatable */
|
||||
lua_rawset(L, -3); /* metatable.__index = metatable */
|
||||
|
||||
|
|
877
tool/net/lunix.c
877
tool/net/lunix.c
File diff suppressed because it is too large
Load diff
|
@ -191,10 +191,10 @@ STATIC_YOINK("zip_uri_support");
|
|||
#define HeaderEqualCase(H, S) \
|
||||
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
||||
|
||||
// letters not used: EIJNOQWXYinoqwxy
|
||||
// letters not used: EIJNOQWXYnoqwxy
|
||||
// digits not used: 0123456789
|
||||
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
|
||||
#define GETOPTS "BSVZabdfghjkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:c:e:l:p:r:t:"
|
||||
#define GETOPTS "BSVZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:c:e:l:p:r:t:"
|
||||
|
||||
static const uint8_t kGzipHeader[] = {
|
||||
0x1F, // MAGNUM
|
||||
|
@ -379,6 +379,7 @@ static bool checkedmethod;
|
|||
static bool sslinitialized;
|
||||
static bool sslfetchverify;
|
||||
static bool hascontenttype;
|
||||
static bool interpretermode;
|
||||
static bool sslclientverify;
|
||||
static bool connectionclose;
|
||||
static bool hasonworkerstop;
|
||||
|
@ -1185,10 +1186,10 @@ static void ReportWorkerExit(int pid, int ws) {
|
|||
static void ReportWorkerResources(int pid, struct rusage *ru) {
|
||||
char *s, *b = 0;
|
||||
if (logrusage || LOGGABLE(kLogDebug)) {
|
||||
AppendResourceReport(&b, ru, "\r\n");
|
||||
AppendResourceReport(&b, ru, "\n");
|
||||
if (b) {
|
||||
if ((s = IndentLines(b, appendz(b).i - 1, 0, 1))) {
|
||||
LOGF(kLogDebug, "(stat) resource report for pid %d\r\n%s", pid, s);
|
||||
LOGF(kLogDebug, "(stat) resource report for pid %d\n%s", pid, s);
|
||||
free(s);
|
||||
}
|
||||
free(b);
|
||||
|
@ -4116,7 +4117,7 @@ static int LuaLog(lua_State *L) {
|
|||
}
|
||||
|
||||
static int LuaEncodeSmth(lua_State *L,
|
||||
int Encoder(lua_State *, char **, int, char *)) {
|
||||
int Encoder(lua_State *, char **, int, char *, int)) {
|
||||
int useoutput = false;
|
||||
int maxdepth = 64;
|
||||
char *numformat = "%.14g";
|
||||
|
@ -4133,7 +4134,7 @@ static int LuaEncodeSmth(lua_State *L,
|
|||
numformat = luaL_optstring(L, -1, numformat);
|
||||
}
|
||||
lua_settop(L, 1); // keep the passed argument on top
|
||||
Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat);
|
||||
Encoder(L, useoutput ? &outbuf : &p, maxdepth, numformat, -1);
|
||||
if (useoutput) {
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
|
@ -4920,6 +4921,7 @@ static const char *const kDontAutoComplete[] = {
|
|||
// </SORTED>
|
||||
|
||||
static const luaL_Reg kLuaFuncs[] = {
|
||||
{"Benchmark", LuaBenchmark}, //
|
||||
{"Bsf", LuaBsf}, //
|
||||
{"Bsr", LuaBsr}, //
|
||||
{"CategorizeIp", LuaCategorizeIp}, //
|
||||
|
@ -5085,13 +5087,21 @@ static const luaL_Reg kLuaLibs[] = {
|
|||
};
|
||||
|
||||
static void LuaSetArgv(lua_State *L) {
|
||||
size_t i;
|
||||
int i, j = -1;
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, __argv[0]);
|
||||
lua_seti(L, -2, j++);
|
||||
if (!interpretermode) {
|
||||
lua_pushstring(L, "/zip/.init.lua");
|
||||
lua_seti(L, -2, j++);
|
||||
}
|
||||
for (i = optind; i < __argc; ++i) {
|
||||
lua_pushstring(L, __argv[i]);
|
||||
lua_seti(L, -2, i - optind + 1);
|
||||
lua_seti(L, -2, j++);
|
||||
}
|
||||
lua_setglobal(L, "argv");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, "argv"); // deprecated
|
||||
lua_setglobal(L, "arg");
|
||||
}
|
||||
|
||||
static void LuaSetConstant(lua_State *L, const char *s, long x) {
|
||||
|
@ -5133,10 +5143,111 @@ static void LuaStart(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool ShouldAutocomplete(const char *s) {
|
||||
int c, m, l, r;
|
||||
l = 0;
|
||||
r = ARRAYLEN(kDontAutoComplete) - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
c = strcmp(kDontAutoComplete[m], s);
|
||||
if (c < 0) {
|
||||
l = m + 1;
|
||||
} else if (c > 0) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HandleCompletions(const char *p, linenoiseCompletions *c) {
|
||||
size_t i, j;
|
||||
for (j = i = 0; i < c->len; ++i) {
|
||||
if (ShouldAutocomplete(c->cvec[i])) {
|
||||
c->cvec[j++] = c->cvec[i];
|
||||
} else {
|
||||
free(c->cvec[i]);
|
||||
}
|
||||
}
|
||||
c->len = j;
|
||||
}
|
||||
|
||||
static void LuaPrint(lua_State *L) {
|
||||
int i, n;
|
||||
char *b = 0;
|
||||
const char *s;
|
||||
n = lua_gettop(L);
|
||||
for (i = 1; i <= n; i++) {
|
||||
if (i > 1) appendw(&b, '\t');
|
||||
LuaEncodeLuaData(L, &b, 64, "g", i);
|
||||
}
|
||||
appendw(&b, '\n');
|
||||
WRITE(1, b, appendz(b).i);
|
||||
free(b);
|
||||
}
|
||||
|
||||
static void LuaInterpreter(lua_State *L) {
|
||||
int i, n, sig, status;
|
||||
const char *script;
|
||||
if (optind < __argc) {
|
||||
script = __argv[optind];
|
||||
if (!strcmp(script, "-")) script = 0;
|
||||
if ((status = luaL_loadfile(L, script)) == LUA_OK) {
|
||||
lua_getglobal(L, "arg");
|
||||
n = luaL_len(L, -1);
|
||||
luaL_checkstack(L, n + 3, "too many script args");
|
||||
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
|
||||
lua_remove(L, -i); // remove arg table from stack
|
||||
status = lua_runchunk(L, n, LUA_MULTRET);
|
||||
}
|
||||
lua_report(L, status);
|
||||
} else {
|
||||
lua_repl_blocking = true;
|
||||
lua_repl_completions_callback = HandleCompletions;
|
||||
lua_initrepl(GL, "redbean");
|
||||
if (lua_repl_isterminal) {
|
||||
linenoiseEnableRawMode(0);
|
||||
}
|
||||
for (;;) {
|
||||
status = lua_loadline(L);
|
||||
write(1, "\n", 1);
|
||||
if (status == -1) break; // eof
|
||||
if (status == -2) {
|
||||
if (errno == EINTR) {
|
||||
if ((sig = linenoiseGetInterrupt())) {
|
||||
raise(sig);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "i/o error: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
if (status == LUA_OK) {
|
||||
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
||||
}
|
||||
if (status == LUA_OK) {
|
||||
LuaPrint(GL);
|
||||
} else {
|
||||
lua_report(GL, status);
|
||||
}
|
||||
}
|
||||
linenoiseDisableRawMode();
|
||||
lua_freerepl();
|
||||
lua_settop(GL, 0); // clear stack
|
||||
if ((sig = linenoiseGetInterrupt())) {
|
||||
raise(sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LuaInit(void) {
|
||||
#ifndef STATIC
|
||||
lua_State *L = GL;
|
||||
LuaSetArgv(L);
|
||||
if (interpretermode) {
|
||||
LuaInterpreter(L);
|
||||
exit(0);
|
||||
}
|
||||
if (LuaRunAsset("/.init.lua", true)) {
|
||||
hasonhttprequest = IsHookDefined("OnHttpRequest");
|
||||
hasonclientconnection = IsHookDefined("OnClientConnection");
|
||||
|
@ -6369,34 +6480,6 @@ static void RestoreApe(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool ShouldAutocomplete(const char *s) {
|
||||
int c, m, l, r;
|
||||
l = 0;
|
||||
r = ARRAYLEN(kDontAutoComplete) - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
c = strcmp(kDontAutoComplete[m], s);
|
||||
if (c < 0) {
|
||||
l = m + 1;
|
||||
} else if (c > 0) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HandleCompletions(const char *p, linenoiseCompletions *c) {
|
||||
size_t i, j;
|
||||
for (j = i = 0; i < c->len; ++i) {
|
||||
if (ShouldAutocomplete(c->cvec[i])) {
|
||||
c->cvec[j++] = c->cvec[i];
|
||||
}
|
||||
}
|
||||
c->len = j;
|
||||
}
|
||||
|
||||
static int HandleReadline(void) {
|
||||
int status;
|
||||
for (;;) {
|
||||
|
@ -6405,7 +6488,7 @@ static int HandleReadline(void) {
|
|||
if (status == -1) {
|
||||
OnTerm(SIGHUP); // eof
|
||||
INFOF("got repl eof");
|
||||
write(1, "\r\n", 2);
|
||||
write(1, "\n", 1);
|
||||
return -1;
|
||||
} else if (errno == EINTR) {
|
||||
errno = 0;
|
||||
|
@ -6419,14 +6502,14 @@ static int HandleReadline(void) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
write(1, "\r\n", 2);
|
||||
write(1, "\n", 1);
|
||||
linenoiseDisableRawMode();
|
||||
LUA_REPL_LOCK;
|
||||
if (status == LUA_OK) {
|
||||
status = lua_runchunk(GL, 0, LUA_MULTRET);
|
||||
}
|
||||
if (status == LUA_OK) {
|
||||
lua_l_print(GL);
|
||||
LuaPrint(GL);
|
||||
} else {
|
||||
lua_report(GL, status);
|
||||
}
|
||||
|
@ -6781,6 +6864,7 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
#ifndef STATIC
|
||||
CASE('e', LuaEvalCode(optarg));
|
||||
CASE('F', LuaEvalFile(optarg));
|
||||
CASE('i', interpretermode = true);
|
||||
CASE('E', leakcrashreports = true);
|
||||
CASE('A', storeasset = true; StorePath(optarg));
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue