Do code cleanup use duff device linenoise i/o

This commit is contained in:
Justine Tunney 2022-04-22 18:55:28 -07:00
parent 6ff46ca373
commit 2f56ebfe78
79 changed files with 1393 additions and 1484 deletions

View file

@ -14,11 +14,11 @@
int main(int argc, char *argv[]) {
int c, n;
char a[22];
char a[22], *p;
if ((c = GetCpuCount())) {
n = int64toarray_radix10(c, a);
a[n++] = '\n';
return write(1, a, n) == n ? 0 : 1;
p = FormatInt64(a, c);
*p++ = '\n';
return write(1, a, p - a) == p - a ? 0 : 1;
} else {
return 1;
}

View file

@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
}
}
if (isprime) {
int64toarray_radix10(i, buf);
FormatInt64(buf, i);
fputs(buf, stdout);
fputc('\n', stdout);
if (k++ % 100 == 0) {

View file

@ -47,8 +47,8 @@ void PrintMetric(const char *name, long double d) {
mils = fmodl(d * 1000, 1000);
mics = fmodl(d * 1000000, 1000);
p = stpcpy(p, name), *p++ = '\t';
p += int64toarray_radix10(mins, p), *p++ = 'm';
p += int64toarray_radix10(secs, p), *p++ = '.';
p = FormatInt64(p, mins), *p++ = 'm';
p = FormatInt64(p, secs), *p++ = '.';
*p++ = '0' + mils / 100;
*p++ = '0' + mils / 10 % 10;
*p++ = '0' + mils % 10;

View file

@ -28,31 +28,30 @@
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
static noasan bool IsExePath(const char *s, size_t n) {
static bool IsExePath(const char *s, size_t n) {
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
READ32LE(s + n - 4) == READ32LE(".EXE"));
}
static noasan bool IsComPath(const char *s, size_t n) {
static bool IsComPath(const char *s, size_t n) {
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
READ32LE(s + n - 4) == READ32LE(".COM"));
}
static noasan bool IsComDbgPath(const char *s, size_t n) {
static bool IsComDbgPath(const char *s, size_t n) {
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
}
static noasan bool AccessCommand(const char *name,
char path[hasatleast PATH_MAX], size_t namelen,
int *err, const char *suffix, size_t pathlen) {
static bool AccessCommand(const char *name, char path[hasatleast PATH_MAX],
size_t namelen, int *err, const char *suffix,
size_t pathlen) {
size_t suffixlen;
suffixlen = strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/'
: memchr(path, '\\', pathlen) ? '\\'
: '/';
path[pathlen] =
!IsWindows() ? '/' : memchr(path, '\\', pathlen) ? '\\' : '/';
pathlen++;
}
memcpy(path + pathlen, name, namelen);
@ -62,7 +61,7 @@ static noasan bool AccessCommand(const char *name,
return false;
}
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
static bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
size_t namelen, int *err, const char *suffix) {
char sep;
size_t i;
@ -87,10 +86,9 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
return false;
}
static noasan bool FindCommand(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly,
const char *suffix, int *err) {
static bool FindCommand(const char *name, char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, const char *suffix,
int *err) {
if (priorityonly &&
(memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
pathbuf[0] = 0;
@ -107,14 +105,12 @@ static noasan bool FindCommand(const char *name,
SearchPath(name, pathbuf, namelen, err, suffix);
}
static noasan bool FindVerbatim(const char *name,
char pathbuf[hasatleast PATH_MAX],
static bool FindVerbatim(const char *name, char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, int *err) {
return FindCommand(name, pathbuf, namelen, priorityonly, "", err);
}
static noasan bool FindSuffixed(const char *name,
char pathbuf[hasatleast PATH_MAX],
static bool FindSuffixed(const char *name, char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, int *err) {
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
!IsComDbgPath(name, namelen) &&
@ -131,7 +127,7 @@ static noasan bool FindSuffixed(const char *name,
* @asyncsignalsafe
* @vforksafe
*/
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
int e, f;
char *res;
size_t namelen;

View file

@ -73,7 +73,7 @@ int ioctl_tcgets(int fd, ...) {
tio = va_arg(va, struct termios *);
va_end(va);
if (fd >= 0) {
if (!tio) {
if (!tio || (IsAsan() && !__asan_is_valid(tio, sizeof(*tio)))) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = enotty();

View file

@ -68,7 +68,7 @@ int ioctl_tcsets(int fd, uint64_t request, ...) {
va_start(va, request);
tio = va_arg(va, const struct termios *);
va_end(va);
if (!tio) {
if (!tio || (IsAsan() && !__asan_is_valid(tio, sizeof(*tio)))) {
rc = efault();
} else if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {

View file

@ -29,7 +29,7 @@ errno_t ptsname_r(int fd, char *buf, size_t size) {
if (size) {
if (!buf) return einval();
if (ioctl(fd, TIOCGPTN, &pty) == -1) return errno;
int64toarray_radix10(pty, stpcpy(tb, "/dev/pts/"));
FormatInt32(stpcpy(tb, "/dev/pts/"), pty);
if (strlen(tb) + 1 >= size) return (errno = ERANGE);
stpcpy(buf, tb);
/* TODO(jart): OpenBSD OMG */

View file

@ -5,10 +5,10 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _KERNTRACE 1 /* not configurable w/ flag yet */
#define _POLLTRACE 1 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %5P %'18T "

View file

@ -64,7 +64,7 @@ static int ttyname_linux(int fd, char *buf, size_t size) {
struct stat st1, st2;
if (!isatty(fd)) return errno;
char name[PATH_MAX];
int64toarray_radix10(fd, stpcpy(name, "/proc/self/fd/"));
FormatInt32(stpcpy(name, "/proc/self/fd/"), fd);
ssize_t got;
got = readlink(name, buf, size);
if (got == -1) return errno;

View file

@ -73,10 +73,10 @@ int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *name,
ip = (uint8_t *)&(((struct sockaddr_in *)addr)->sin_addr);
p = rdomain;
p += int64toarray_radix10(ip[3], p), *p++ = '.';
p += int64toarray_radix10(ip[2], p), *p++ = '.';
p += int64toarray_radix10(ip[1], p), *p++ = '.';
p += int64toarray_radix10(ip[0], p), stpcpy(p, ".in-addr.arpa");
p = FormatUint32(p, ip[3]), *p++ = '.';
p = FormatUint32(p, ip[2]), *p++ = '.';
p = FormatUint32(p, ip[1]), *p++ = '.';
p = FormatUint32(p, ip[0]), stpcpy(p, ".in-addr.arpa");
info[0] = '\0';
if (name != NULL && namelen != 0) {
if ((flags & NI_NUMERICHOST) && (flags & NI_NAMEREQD)) return EAI_NONAME;

View file

@ -147,12 +147,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
continue;
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
d = va_arg(va, int);
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
if (out(ibuf, arg, FormatInt64(ibuf, d) - ibuf) == -1) return -1;
format += 2;
continue;
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
u = va_arg(va, unsigned);
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
if (out(ibuf, arg, FormatUint64(ibuf, u) - ibuf) == -1) return -1;
format += 2;
continue;
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
@ -167,12 +167,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
continue;
} else if (format[1] == 'l' && format[2] == 'd') {
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
if (out(ibuf, arg, FormatInt64(ibuf, ld) - ibuf) == -1) return -1;
format += 3;
continue;
} else if (format[1] == 'l' && format[2] == 'u') {
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
if (out(ibuf, arg, uint64toarray_radix10(lu, ibuf)) == -1) return -1;
if (out(ibuf, arg, FormatUint64(ibuf, lu) - ibuf) == -1) return -1;
format += 3;
continue;
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {

View file

@ -24,7 +24,7 @@
* @param p needs at least 12 bytes
* @return pointer to nul byte
*/
dontinline char *FormatUint32(char p[static 12], uint32_t x) {
dontinline char *FormatUint32(char p[hasatleast 12], uint32_t x) {
char t;
size_t i, a, b;
i = 0;
@ -49,7 +49,7 @@ dontinline char *FormatUint32(char p[static 12], uint32_t x) {
* @param p needs at least 12 bytes
* @return pointer to nul byte
*/
char *FormatInt32(char p[static 12], int32_t x) {
char *FormatInt32(char p[hasatleast 12], int32_t x) {
if (x < 0) *p++ = '-', x = -(uint32_t)x;
return FormatUint32(p, x);
}

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,34 +16,32 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/alg/reverse.internal.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/limits.h"
/**
* Converts unsigned 64-bit integer to string.
* @param a needs at least 21 bytes
* @return bytes written w/o nul
* Converts unsigned 32-bit integer to octal string.
*
* @param p needs at least 12 bytes
* @param z ensures it starts with zero
* @return pointer to nul byte
*/
dontinline size_t uint64toarray_radix10(uint64_t i, char a[hasatleast 21]) {
size_t j = 0;
char *FormatOctal32(char p[hasatleast 13], uint32_t x, bool z) {
char t;
size_t i, a, b;
i = 0;
z = x && z;
do {
a[j++] = i % 10 + '0';
i = i / 10;
} while (i > 0);
a[j] = '\0';
reverse(a, j);
return j;
p[i++] = x % 8 + '0';
x = x / 8;
} while (x > 0);
if (z) p[i++] = '0';
p[i] = '\0';
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
/**
* Converts signed 64-bit integer to string.
* @param a needs at least 21 bytes
* @return bytes written w/o nul
*/
size_t int64toarray_radix10(int64_t i, char a[hasatleast 21]) {
if (i >= 0) return uint64toarray_radix10(i, a);
*a++ = '-';
return 1 + uint64toarray_radix10(-(uint64_t)i, a);
}
return p + i;
}

47
libc/fmt/formatoctal64.c Normal file
View file

@ -0,0 +1,47 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/itoa.h"
/**
* Converts unsigned 64-bit integer to octal string.
*
* @param p needs at least 12 bytes
* @param z ensures it starts with zero
* @return pointer to nul byte
*/
char *FormatOctal64(char p[hasatleast 24], uint64_t x, bool z) {
char t;
size_t i, a, b;
i = 0;
z = x && z;
do {
p[i++] = x % 8 + '0';
x = x / 8;
} while (x > 0);
if (z) p[i++] = '0';
p[i] = '\0';
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}

View file

@ -2,19 +2,6 @@
#define COSMOPOLITAN_LIBC_FMT_ITOA_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § integer conversion
FASTEST + TINY
- uint64toarray_radix10(0x31337, a) l: 68 (20ns) m: 112 (33ns)
- int64toarray_radix10(0x31337, a) l: 69 (20ns) m: 134 (39ns)
FAST + AWESOME
- snprintf(a, sizeof(a), "%d", 0x31337) l: 199 (58ns) m: 421 (123ns)
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
unsigned LengthInt64(int64_t) pureconst;
unsigned LengthUint64(uint64_t) pureconst;
@ -26,8 +13,8 @@ char *FormatInt64(char[hasatleast 21], int64_t);
char *FormatUint64(char[hasatleast 21], uint64_t);
char *FormatInt64Thousands(char[hasatleast 27], int64_t);
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
size_t int64toarray_radix10(int64_t, char[hasatleast 21]);
size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
char *FormatOctal32(char[hasatleast 13], uint32_t, bool);
char *FormatOctal64(char[hasatleast 24], uint64_t, bool);
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);

View file

@ -722,7 +722,7 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size,
if (_base <= addr && addr < _end) {
__asan_report_memory_origin_image((intptr_t)addr, size);
} else if (IsAutoFrame((intptr_t)addr >> 16)) {
__asan_report_memory_origin_heap(addr, size);
/* __asan_report_memory_origin_heap(addr, size); */
}
}
@ -1202,8 +1202,9 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
struct AsanTrace tr;
__asan_rawtrace(&tr, __builtin_frame_address(0));
kprintf("WARNING: ASAN error during %s bad %d byte %s at %p bt %p %p %p %p%n",
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3]);
kprintf(
"WARNING: ASAN error during %s bad %d byte %s at %x bt %x %x %x %x %x%n",
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3], tr.p[4], tr.p[5]);
}
void __asan_report_load(uint8_t *addr, int size) {

View file

@ -149,7 +149,7 @@ void(bzero)(void *p, size_t n) {
} while (n);
}
} else if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "a"(0));
return;
} else if (X86_HAVE(AVX)) {
bzero_avx(b, n);

View file

@ -116,7 +116,7 @@ o//libc/intrin/memcmp.o \
o//libc/intrin/memset.o \
o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-O2
-O2 -finline
o/$(MODE)/libc/intrin/bzero.o \
o/$(MODE)/libc/intrin/memcmp.o \

View file

@ -56,11 +56,11 @@ relegated int(AttachDebugger)(intptr_t continuetoaddr) {
struct StackFrame *bp;
char pidstr[11], breakcmd[40];
const char *se, *elf, *gdb, *rewind, *layout;
__restore_tty();
if (IsGenuineCosmo() || !(gdb = GetGdbPath()) || !isatty(0) || !isatty(1) ||
(ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) {
return -1;
}
__restore_tty(ttyfd);
ksnprintf(pidstr, sizeof(pidstr), "%u", getpid());
layout = "layout asm";
if ((elf = FindDebugBinary())) {

View file

@ -59,11 +59,12 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
size_t i, j, gi;
int ws, pid, pipefds[2];
struct Garbages *garbage;
sigset_t chldmask, savemask;
const struct StackFrame *frame;
char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
return -1;
if (!(debugbin = FindDebugBinary())) {
return -1;
}
@ -105,19 +106,15 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
argv[i++] = buf + j;
buf[j++] = '0';
buf[j++] = 'x';
j += uint64toarray_radix16(addr, buf + j) + 1;
j += uint64toarray_radix16(addr - 1, buf + j) + 1;
}
argv[i++] = NULL;
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
pipe(pipefds);
if (!(pid = vfork())) {
sigprocmask(SIG_SETMASK, &savemask, NULL);
dup2(pipefds[1], 1);
if (pipefds[0] != 1) close(pipefds[0]);
if (pipefds[1] != 1) close(pipefds[1]);
execvp(addr2line, argv);
execve(addr2line, argv, environ);
_exit(127);
}
close(pipefds[1]);
@ -150,7 +147,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
if (errno == EINTR) continue;
return -1;
}
sigprocmask(SIG_SETMASK, &savemask, NULL);
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
return 0;
} else {

View file

@ -35,7 +35,7 @@
*/
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) {
__restore_tty(1);
__restore_tty();
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
!__nocolor ? "\e[J" : "", program_invocation_name, want, opchar, got,
strerror(errno));

View file

@ -35,7 +35,7 @@ relegated wontreturn void __die(void) {
int rc;
static bool once;
if (_lockcmpxchg(&once, false, true)) {
__restore_tty(1);
__restore_tty();
if (IsDebuggerPresent(false)) {
DebugBreak();
}

View file

@ -10,12 +10,11 @@ COSMOPOLITAN_C_START_
extern hidden bool __nocolor;
extern hidden int kCrashSigs[7];
extern hidden bool g_isrunningundermake;
extern hidden struct termios g_oldtermios;
extern hidden struct sigaction g_oldcrashacts[7];
void __start_fatal(const char *, int) hidden;
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;
void __restore_tty(int);
void __restore_tty(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -77,15 +77,15 @@ extern unsigned __log_level; /* log level for runtime check */
// log a message with the specified log level (not checking if LOGGABLE)
#define LOGF(LEVEL, FMT, ...) \
do { \
++g_ftrace; \
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} while (0)
// die with an error message without backtrace and debugger invocation
#define DIEF(FMT, ...) \
do { \
++g_ftrace; \
--g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
exit(1); \
unreachable; \
@ -93,7 +93,7 @@ extern unsigned __log_level; /* log level for runtime check */
#define FATALF(FMT, ...) \
do { \
++g_ftrace; \
--g_ftrace; \
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
unreachable; \
} while (0)
@ -101,78 +101,78 @@ extern unsigned __log_level; /* log level for runtime check */
#define ERRORF(FMT, ...) \
do { \
if (LOGGABLE(kLogError)) { \
++g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define WARNF(FMT, ...) \
do { \
if (LOGGABLE(kLogWarn)) { \
++g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define INFOF(FMT, ...) \
do { \
if (LOGGABLE(kLogInfo)) { \
++g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define VERBOSEF(FMT, ...) \
do { \
if (LOGGABLE(kLogVerbose)) { \
++g_ftrace; \
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define DEBUGF(FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
++g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define NOISEF(FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
++g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
--g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define FLOGF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogInfo)) { \
++g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--g_ftrace; \
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define FWARNF(F, FMT, ...) \
do { \
if (LOGGABLE(kLogWarn)) { \
++g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--g_ftrace; \
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define FFATALF(F, FMT, ...) \
do { \
++g_ftrace; \
--g_ftrace; \
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
unreachable; \
} while (0)
@ -180,18 +180,18 @@ extern unsigned __log_level; /* log level for runtime check */
#define FDEBUGF(F, FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
++g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--g_ftrace; \
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
#define FNOISEF(F, FMT, ...) \
do { \
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
++g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
--g_ftrace; \
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
++g_ftrace; \
} \
} while (0)
@ -204,9 +204,9 @@ extern unsigned __log_level; /* log level for runtime check */
int e = errno; \
autotype(FORM) Ax = (FORM); \
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
++g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \
--g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \
++g_ftrace; \
errno = e; \
} \
Ax; \
@ -217,9 +217,9 @@ extern unsigned __log_level; /* log level for runtime check */
int e = errno; \
autotype(FORM) Ax = (FORM); \
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
++g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \
--g_ftrace; \
__logerrno(__FILE__, __LINE__, #FORM); \
++g_ftrace; \
errno = e; \
} \
Ax; \

View file

@ -41,6 +41,7 @@ LIBC_LOG_A_DIRECTDEPS = \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_UNICODE \
@ -58,8 +59,8 @@ $(LIBC_LOG_A).pkg: \
$(LIBC_LOG_A_OBJS) \
$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/log/backtrace2.o \
o/$(MODE)/libc/log/backtrace3.o: \
o/$(MODE)/libc/log/backtrace2.greg.o \
o/$(MODE)/libc/log/backtrace3.greg.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all
@ -67,6 +68,7 @@ o/$(MODE)/libc/log/checkfail.o: \
OVERRIDE_CFLAGS += \
-mgeneral-regs-only
o/$(MODE)/libc/log/restoretty.greg.o \
o/$(MODE)/libc/log/attachdebugger.o \
o/$(MODE)/libc/log/backtrace2.o \
o/$(MODE)/libc/log/backtrace3.o \

View file

@ -296,7 +296,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
: 0);
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty(1);
__restore_tty();
ShowCrashReport(err, sig, si, ctx);
__restorewintty();
_Exit(128 + sig);

View file

@ -17,8 +17,11 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/metatermios.internal.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/termios.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
@ -26,7 +29,7 @@
#include "libc/sysv/consts/termios.h"
/**
* @fileoverview Terminal Restoration Helper
* @fileoverview Terminal Restoration Helper for System Five.
*
* This is used by the crash reporting functions, e.g. __die(), to help
* ensure the terminal is in an unborked state after a crash happens.
@ -37,26 +40,28 @@
#define DISABLE_MOUSE "\e[?1000;1002;1015;1006l"
#define ANSI_RESTORE RESET_COLOR SHOW_CURSOR DISABLE_MOUSE
struct termios g_oldtermios;
static bool __isrestorable;
static union metatermios __oldtermios;
static textstartup void g_oldtermios_init() {
int e = errno;
tcgetattr(1, &g_oldtermios);
static textstartup void __oldtermios_init() {
int e;
e = errno;
if (sys_ioctl(0, TCGETS, &__oldtermios) != -1) {
__isrestorable = true;
}
errno = e;
}
const void *const g_oldtermios_ctor[] initarray = {
g_oldtermios_init,
const void *const __oldtermios_ctor[] initarray = {
__oldtermios_init,
};
void __restore_tty(int fd) {
void __restore_tty(void) {
int e;
if (!__isworker) {
if (__isrestorable && !__isworker && !__nocolor) {
e = errno;
if (g_oldtermios.c_lflag && !__nocolor && isatty(fd)) {
write(fd, ANSI_RESTORE, strlen(ANSI_RESTORE));
tcsetattr(fd, TCSAFLUSH, &g_oldtermios);
}
sys_write(0, ANSI_RESTORE, strlen(ANSI_RESTORE));
sys_ioctl(0, TCSETSF, &__oldtermios);
errno = e;
}
}

View file

@ -27,7 +27,7 @@
* @note this is support code for __check_fail(), __assert_fail(), etc.
*/
relegated void __start_fatal(const char *file, int line) {
__restore_tty(1);
__restore_tty();
kprintf("%r%serror%s:%s:%d:%s%s: ", !__nocolor ? "\e[J\e[30;101m" : "",
!__nocolor ? "\e[94;49m" : "", file, line,
program_invocation_short_name, !__nocolor ? "\e[0m" : "");

View file

@ -249,7 +249,7 @@ textwindows int sys_fork_nt(void) {
kNtFileFlagOverlapped, 0);
if (pid != -1 && reader != -1 && writer != -1) {
p = stpcpy(forkvar, "_FORK=");
p += uint64toarray_radix10(reader, p);
p = FormatUint64(p, reader);
bzero(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;

View file

@ -31,6 +31,7 @@
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/time/clockstonanos.internal.h"
#pragma weak stderr
@ -89,7 +90,7 @@ privileged noinstrument noasan noubsan void ftracer(void) {
frame = frame->next;
if (frame->addr != g_lastaddr) {
kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr,
(long)(unsignedsubtract(stamp, g_laststamp) / 3.3));
ClocksToNanos(stamp, g_laststamp));
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
g_lastaddr = frame->addr;
}
@ -97,14 +98,15 @@ privileged noinstrument noasan noubsan void ftracer(void) {
noreentry = 0;
}
textstartup void ftrace_install(void) {
textstartup int ftrace_install(void) {
if (GetSymbolTable()) {
g_lastaddr = -1;
g_laststamp = kStartTsc;
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
ftrace_enabled = 1;
__hook(ftrace_hook, GetSymbolTable());
return __hook(ftrace_hook, GetSymbolTable());
} else {
kprintf("error: --ftrace failed to open symbol table\r\n");
return -1;
}
}

View file

@ -0,0 +1,31 @@
/*-*- 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/runtime/memtrack.internal.h"
bool IsMemtracked(int x, int y) {
unsigned i;
i = FindMemoryInterval(&_mmi, x);
if (i == _mmi.i) return false;
if (x < _mmi.p[i].x) return false;
for (;;) {
if (y <= _mmi.p[i].y) return true;
if (++i == _mmi.i) return false;
if (_mmi.p[i].x != _mmi.p[i - 1].y + 1) return false;
}
}

View file

@ -36,7 +36,7 @@
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
static noasan void *MoveMemoryIntervals(struct MemoryInterval *d,
static void *MoveMemoryIntervals(struct MemoryInterval *d,
const struct MemoryInterval *s, int n) {
/* asan runtime depends on this function */
int i;
@ -53,8 +53,7 @@ static noasan void *MoveMemoryIntervals(struct MemoryInterval *d,
return d;
}
static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
int n) {
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
/* asan runtime depends on this function */
assert(i >= 0);
assert(i + n <= mm->i);
@ -62,7 +61,7 @@ static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
mm->i -= n;
}
static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
int prot, flags;
char *base, *shad;
size_t gran, size;
@ -99,7 +98,7 @@ static noasan bool ExtendMemoryIntervals(struct MemoryIntervals *mm) {
return true;
}
noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
/* asan runtime depends on this function */
int rc;
rc = 0;
@ -111,14 +110,14 @@ noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
return 0;
}
static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].y = x - 1;
mm->p[i + 1].x = y + 1;
return 0;
}
noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
void wf(struct MemoryIntervals *, int, int)) {
unsigned l, r;
assert(y >= x);
@ -158,9 +157,9 @@ noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
return 0;
}
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags, bool readonlyfile,
bool iscow, long offset, long size) {
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags, bool readonlyfile, bool iscow,
long offset, long size) {
/* asan runtime depends on this function */
unsigned i;
assert(y >= x);

View file

@ -50,8 +50,9 @@ struct MemoryIntervals {
extern hidden struct MemoryIntervals _mmi;
const char *DescribeFrame(int);
bool IsMemtracked(int, int) hidden;
void PrintSystemMappings(int) hidden;
const char *DescribeFrame(int) hidden;
char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
@ -175,18 +176,6 @@ forceinline unsigned FindMemoryInterval(const struct MemoryIntervals *mm,
return l;
}
forceinline bool IsMemtracked(int x, int y) {
unsigned i;
i = FindMemoryInterval(&_mmi, x);
if (i == _mmi.i) return false;
if (x < _mmi.p[i].x) return false;
for (;;) {
if (y <= _mmi.p[i].y) return true;
if (++i == _mmi.i) return false;
if (_mmi.p[i].x != _mmi.p[i - 1].y + 1) return false;
}
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ */

View file

@ -204,8 +204,7 @@ textstartup void __printargs(const char *prologue) {
"%,u sets of %,u byte lines shared across %u threads%s",
CPUID4_CACHE_LEVEL,
CPUID4_CACHE_TYPE == 1 ? " data"
: CPUID4_CACHE_TYPE == 2 ? " code"
: "",
: CPUID4_CACHE_TYPE == 2 ? " code" : "",
CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "",
CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES,
CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "",
@ -245,8 +244,8 @@ textstartup void __printargs(const char *prologue) {
if ((n = poll(pfds, ARRAYLEN(pfds), 0)) != -1) {
for (i = 0; i < ARRAYLEN(pfds); ++i) {
if (i && (pfds[i].revents & POLLNVAL)) continue;
PRINT(" ☼ %d (revents=%#hx F_GETFL=%#x)", i, pfds[i].revents,
fcntl(i, F_GETFL));
PRINT(" ☼ %d (revents=%#hx fcntl(F_GETFL)=%#x isatty()=%hhhd)", i,
pfds[i].revents, fcntl(i, F_GETFL), isatty(i));
}
} else {
PRINT(" poll() returned %d %m", n);

View file

@ -98,7 +98,7 @@ void _weakfree(void *);
void free_s(void *) paramsnonnull() libcesque;
int close_s(int *) paramsnonnull() libcesque;
int OpenExecutable(void);
void ftrace_install(void);
int ftrace_install(void);
long GetResourceLimit(int);
long GetMaxFd(void);
char *GetProgramExecutableName(void);

View file

@ -70,8 +70,9 @@ o/$(MODE)/libc/runtime/getdosargv.o \
o/$(MODE)/libc/runtime/getdosenviron.o \
o/$(MODE)/libc/runtime/hook.greg.o \
o/$(MODE)/libc/runtime/isheap.o \
o/$(MODE)/libc/runtime/memtrack.o \
o/$(MODE)/libc/runtime/memtracknt.o \
o/$(MODE)/libc/runtime/memtrack.greg.o \
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
o/$(MODE)/libc/runtime/metalprintf.greg.o \
o/$(MODE)/libc/runtime/printargs.greg.o \
o/$(MODE)/libc/runtime/mman.greg.o \

View file

@ -25,12 +25,12 @@
char *inet_ntoa(struct in_addr in) {
static char buf[16];
char *p = buf;
p += int64toarray_radix10((in.s_addr >> 000) & 255, p);
p = FormatUint32(p, (in.s_addr >> 000) & 255);
*p++ = '.';
p += int64toarray_radix10((in.s_addr >> 010) & 255, p);
p = FormatUint32(p, (in.s_addr >> 010) & 255);
*p++ = '.';
p += int64toarray_radix10((in.s_addr >> 020) & 255, p);
p = FormatUint32(p, (in.s_addr >> 020) & 255);
*p++ = '.';
p += int64toarray_radix10((in.s_addr >> 030) & 255, p);
p = FormatUint32(p, (in.s_addr >> 030) & 255);
return buf;
}

View file

@ -53,19 +53,19 @@ static relegated void DieBecauseOfQuota(int rc, const char *message) {
}
static relegated void OnXcpu(int sig) {
__restore_tty(2);
__restore_tty();
DieBecauseOfQuota(23, "\n\nSIGXCPU: ran out of cpu");
}
static relegated void OnXfsz(int sig) {
__restore_tty(2);
__restore_tty();
DieBecauseOfQuota(25, "\n\nSIGXFSZ: exceeded maximum file size");
}
relegated void __oom_hook(size_t request) {
int e;
uint64_t toto, newlim;
__restore_tty(2);
__restore_tty();
e = errno;
toto = CountMappedBytes();
kprintf("\n\nWE REQUIRE MORE VESPENE GAS");

View file

@ -48,7 +48,7 @@ static char *strftime_secs(char *p, const char *pe, const struct tm *t) {
int64_t s;
tmp = *t; /* Make a copy, mktime(3) modifies the tm struct. */
s = mktime(&tmp);
int64toarray_radix10(s, ibuf);
FormatInt64(ibuf, s);
return strftime_add(p, pe, ibuf);
}

View file

@ -46,6 +46,13 @@ TEST(open, eexist) {
ASSERT_SYS(EEXIST, -1, open("exists", O_WRONLY | O_CREAT | O_EXCL));
}
TEST(open, enametoolong) {
size_t n = 260;
char *s = gc(xcalloc(1, n + 1));
memset(s, 'J', n);
ASSERT_SYS(ENAMETOOLONG, -1, creat(s, 0644));
}
TEST(open, testOpenExistingForWriteOnly_seeksToStart) {
char buf[8] = {0};
ASSERT_SYS(0, 0, xbarf("hello.txt", "hello", -1));

View file

@ -22,29 +22,29 @@
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
TEST(int64toarray_radix10, test) {
TEST(FormatInt64, test) {
char buf[21];
EXPECT_EQ(1, int64toarray_radix10(0, buf));
EXPECT_EQ(1, FormatInt64(buf, 0) - buf);
EXPECT_STREQ("0", buf);
EXPECT_EQ(1, int64toarray_radix10(1, buf));
EXPECT_EQ(1, FormatInt64(buf, 1) - buf);
EXPECT_STREQ("1", buf);
EXPECT_EQ(2, int64toarray_radix10(-1, buf));
EXPECT_EQ(2, FormatInt64(buf, -1) - buf);
EXPECT_STREQ("-1", buf);
EXPECT_EQ(19, int64toarray_radix10(INT64_MAX, buf));
EXPECT_EQ(19, FormatInt64(buf, INT64_MAX) - buf);
EXPECT_STREQ("9223372036854775807", buf);
EXPECT_EQ(20, int64toarray_radix10(INT64_MIN, buf));
EXPECT_EQ(20, FormatInt64(buf, INT64_MIN) - buf);
EXPECT_STREQ("-9223372036854775808", buf);
}
TEST(uint64toarray_radix10, test) {
TEST(FormatUint64, test) {
char buf[21];
EXPECT_EQ(1, uint64toarray_radix10(0, buf));
EXPECT_EQ(1, FormatUint64(buf, 0) - buf);
EXPECT_STREQ("0", buf);
EXPECT_EQ(4, uint64toarray_radix10(1024, buf));
EXPECT_EQ(4, FormatUint64(buf, 1024) - buf);
EXPECT_STREQ("1024", buf);
EXPECT_EQ(20, uint64toarray_radix10(UINT64_MAX, buf));
EXPECT_EQ(20, FormatUint64(buf, UINT64_MAX) - buf);
EXPECT_STREQ("18446744073709551615", buf);
EXPECT_EQ(19, uint64toarray_radix10(INT64_MIN, buf));
EXPECT_EQ(19, FormatUint64(buf, INT64_MIN) - buf);
EXPECT_STREQ("9223372036854775808", buf);
}
@ -70,5 +70,5 @@ TEST(uint128toarray_radix10, test) {
BENCH(itoa64radix10, bench) {
char b[21];
EZBENCH2("itoa64radix10", donothing, uint64toarray_radix10(UINT64_MAX, b));
EZBENCH2("itoa64radix10", donothing, FormatUint64(b, UINT64_MAX));
}

View file

@ -76,8 +76,6 @@ TEST(FormatInt64Thousands, testNegative) {
BENCH(FormatInt64Thousands, bench) {
char s[27];
EZBENCH2("int64toarray_radix10(MAX)", donothing,
int64toarray_radix10(INT64_MAX, s));
EZBENCH2("FormatInt64Thousands(MAX)", donothing,
FormatInt64Thousands(s, INT64_MAX));
EZBENCH2("FormatInt64Thousands(MIN)", donothing,

View file

@ -0,0 +1,57 @@
/*-*- 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/str/str.h"
#include "libc/testlib/testlib.h"
char buf[13];
void SetUp(void) {
memset(buf, 0x55, sizeof(buf));
}
TEST(FormatOctal32, test1) {
EXPECT_EQ(1, FormatOctal32(buf, 0, true) - buf);
EXPECT_STREQ("0", buf);
}
TEST(FormatOctal32, test2) {
EXPECT_EQ(1, FormatOctal32(buf, 0, false) - buf);
EXPECT_STREQ("0", buf);
}
TEST(FormatOctal32, test3) {
EXPECT_EQ(2, FormatOctal32(buf, 1, true) - buf);
EXPECT_STREQ("01", buf);
}
TEST(FormatOctal32, test4) {
EXPECT_EQ(1, FormatOctal32(buf, 1, false) - buf);
EXPECT_STREQ("1", buf);
}
TEST(FormatOctal32, test5) {
EXPECT_EQ(12, FormatOctal32(buf, 037777777777, true) - buf);
EXPECT_STREQ("037777777777", buf);
}
TEST(FormatOctal32, test6) {
EXPECT_EQ(11, FormatOctal32(buf, 037777777777, false) - buf);
EXPECT_STREQ("37777777777", buf);
}

View file

@ -0,0 +1,66 @@
/*-*- 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/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
char buf[25];
void SetUp(void) {
memset(buf, 0x55, sizeof(buf));
}
TEST(FormatOctal64, test1) {
EXPECT_EQ(1, FormatOctal64(buf, 0, true) - buf);
EXPECT_STREQ("0", buf);
}
TEST(FormatOctal64, test2) {
EXPECT_EQ(1, FormatOctal64(buf, 0, false) - buf);
EXPECT_STREQ("0", buf);
}
TEST(FormatOctal64, test3) {
EXPECT_EQ(2, FormatOctal64(buf, 1, true) - buf);
EXPECT_STREQ("01", buf);
}
TEST(FormatOctal64, test4) {
EXPECT_EQ(1, FormatOctal64(buf, 1, false) - buf);
EXPECT_STREQ("1", buf);
}
TEST(FormatOctal64, test5) {
EXPECT_EQ(23, FormatOctal64(buf, 01777777777777777777777UL, true) - buf);
EXPECT_STREQ("01777777777777777777777", buf);
}
TEST(FormatOctal64, test6) {
EXPECT_EQ(22, FormatOctal64(buf, 01777777777777777777777UL, false) - buf);
EXPECT_STREQ("1777777777777777777777", buf);
}
BENCH(FormatOctal64, bench) {
EZBENCH2("FormatUint64", donothing,
FormatUint64(buf, 01777777777777777777777UL));
EZBENCH2("FormatOctal64", donothing,
FormatOctal64(buf, 01777777777777777777777UL, true));
EZBENCH2("FormatOctal32", donothing, FormatOctal32(buf, 037777777777U, true));
}

View file

@ -641,6 +641,7 @@ BENCH(palandprintf, bench) {
EZBENCH2("%g M_PI", donothing, Format("%g", VEIL("x", M_PI)));
EZBENCH2("%a M_PI", donothing, Format("%a", VEIL("x", M_PI)));
EZBENCH2("%e M_PI", donothing, Format("%e", VEIL("x", M_PI)));
EZBENCH2("ULONG_MAX %lo", donothing, Format("%lo", VEIL("r", ULONG_MAX)));
EZBENCH2("INT_MIN %x", donothing, Format("%x", VEIL("r", INT_MIN)));
EZBENCH2("INT_MIN %d", donothing, Format("%d", VEIL("r", INT_MIN)));
EZBENCH2("INT_MIN %,d", donothing, Format("%,d", VEIL("r", INT_MIN)));
@ -649,7 +650,6 @@ BENCH(palandprintf, bench) {
EZBENCH2("LONG_MIN %ld", donothing, Format("%ld", VEIL("r", LONG_MIN)));
EZBENCH2("INT128_MIN %jjd", donothing, Format("%jjd", INT128_MIN));
EZBENCH2("INT128_MIN %jjx", donothing, Format("%jjx", INT128_MIN));
EZBENCH2("int64toarray 23", donothing, int64toarray_radix10(23, buffer));
EZBENCH2("int64toarray min", donothing,
int64toarray_radix10(INT_MIN, buffer));
EZBENCH2("int64toarray 23", donothing, FormatInt64(buffer, 23));
EZBENCH2("int64toarray min", donothing, FormatInt64(buffer, INT_MIN));
}

View file

@ -43,7 +43,8 @@
*/
static uint64_t Rando(void) {
uint64_t x;
do x = lemur64();
do
x = lemur64();
while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) &
~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080);
return x;
@ -375,6 +376,8 @@ BENCH(printf, bench) {
kusnprintf(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
EZBENCH2("snprintf astral", donothing,
snprintf_(b, 128, "%hs\n", u"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷"));
EZBENCH2("kusnprintf octal", donothing,
kusnprintf(b, 128, "%#lo", ULONG_MAX));
EZBENCH2("kusnprintf long", donothing, kusnprintf(b, 128, "%ld", LONG_MAX));
EZBENCH2("snprintf long", donothing, snprintf_(b, 128, "%ld", LONG_MAX));
EZBENCH2("kusnprintf thou", donothing, kusnprintf(b, 128, "%'ld", LONG_MAX));

View file

@ -33,6 +33,14 @@ STATIC_YOINK("usr/share/zoneinfo/New_York");
char testlib_enable_tmp_setup_teardown;
DIR *dir;
struct dirent *ent;
void SetUp(void) {
dir = 0;
ent = 0;
}
TEST(opendir, efault) {
ASSERT_SYS(EFAULT, NULL, opendir(0));
if (!IsAsan()) return; // not possible
@ -50,10 +58,8 @@ TEST(opendir, enotdir) {
}
TEST(dirstream, testDots) {
DIR *dir;
int hasdot = 0;
int hasdotdot = 0;
struct dirent *ent;
ASSERT_SYS(0, 0, close(creat("foo", 0644)));
ASSERT_NE(NULL, (dir = opendir(".")));
while ((ent = readdir(dir))) {
@ -72,8 +78,6 @@ TEST(dirstream, testDots) {
}
TEST(dirstream, test) {
DIR *dir;
struct dirent *ent;
bool hasfoo = false;
bool hasbar = false;
char *dpath, *file1, *file2;
@ -104,21 +108,17 @@ TEST(dirstream, test) {
TEST(dirstream, zipTest) {
bool foundNewYork = false;
DIR *d;
struct dirent *e;
const char *path = "/zip/usr/share/zoneinfo/";
ASSERT_NE(0, _gc(xiso8601ts(NULL)));
ASSERT_NE(NULL, (d = opendir(path)));
while ((e = readdir(d))) {
foundNewYork |= !strcmp(e->d_name, "New_York");
ASSERT_NE(NULL, (dir = opendir(path)));
while ((ent = readdir(dir))) {
foundNewYork |= !strcmp(ent->d_name, "New_York");
}
closedir(d);
closedir(dir);
EXPECT_TRUE(foundNewYork);
}
TEST(rewinddir, test) {
DIR *dir;
struct dirent *ent;
bool hasfoo = false;
bool hasbar = false;
char *dpath, *file1, *file2;

View file

@ -19,7 +19,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/goodsocket.internal.h"
@ -91,7 +90,7 @@ char *SendHttpRequest(const char *s) {
bool Matches(const char *regex, const char *str) {
bool r;
regex_t re;
CHECK_EQ(REG_OK, regcomp(&re, regex, 0));
EXPECT_EQ(REG_OK, regcomp(&re, regex, 0));
r = regexec(&re, str, 0, 0, 0) == REG_OK;
regfree(&re);
return r;
@ -103,15 +102,22 @@ TEST(redbean, testOptions) {
int pid, pipefds[2];
sigset_t chldmask, savemask;
sigaddset(&chldmask, SIGCHLD);
CHECK_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
ASSERT_NE(-1, pipe(pipefds));
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
setpgrp();
close(0);
open("/dev/null", O_RDWR);
close(1);
dup(0);
close(2);
open("log", O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644);
close(pipefds[0]);
dup2(pipefds[1], 1);
sigprocmask(SIG_SETMASK, &savemask, NULL);
execv("bin/redbean.com",
(char *const[]){"bin/redbean.com", "-szp0", "-l127.0.0.1", 0});
(char *const[]){"bin/redbean.com", "-vvszp0", "-l127.0.0.1", 0});
_exit(127);
}
EXPECT_NE(-1, close(pipefds[1]));
@ -129,7 +135,8 @@ TEST(redbean, testOptions) {
EXPECT_EQ(0, close(pipefds[0]));
EXPECT_NE(-1, kill(pid, SIGTERM));
EXPECT_NE(-1, wait(0));
CHECK_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
if (g_testlib_failed) fputs(gc(xslurp("log", 0)), stderr);
}
TEST(redbean, testPipeline) {
@ -138,15 +145,20 @@ TEST(redbean, testPipeline) {
int pid, pipefds[2];
sigset_t chldmask, savemask;
sigaddset(&chldmask, SIGCHLD);
CHECK_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &chldmask, &savemask));
ASSERT_NE(-1, pipe(pipefds));
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
setpgrp();
close(0);
open("/dev/null", O_RDWR);
close(2);
open("log", O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644);
close(pipefds[0]);
dup2(pipefds[1], 1);
sigprocmask(SIG_SETMASK, &savemask, NULL);
execv("bin/redbean.com",
(char *const[]){"bin/redbean.com", "-szp0", "-l127.0.0.1", 0});
(char *const[]){"bin/redbean.com", "-vvszp0", "-l127.0.0.1", 0});
_exit(127);
}
EXPECT_NE(-1, close(pipefds[1]));
@ -173,5 +185,6 @@ TEST(redbean, testPipeline) {
EXPECT_EQ(0, close(pipefds[0]));
EXPECT_NE(-1, kill(pid, SIGTERM));
EXPECT_NE(-1, wait(0));
CHECK_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0));
if (g_testlib_failed) fputs(gc(xslurp("log", 0)), stderr);
}

View file

@ -17,6 +17,7 @@
#include "libc/bits/weaken.h"
#include "libc/intrin/kprintf.h"
#include "libc/mem/mem.h"
#include "third_party/dlmalloc/dlmalloc.h"
// clang-format off
#define FOOTERS 0
@ -100,7 +101,7 @@
#define FOOTERS 0
#endif /* FOOTERS */
#ifndef ABORT
#define ABORT abort()
#define ABORT dlmalloc_abort()
#endif /* ABORT */
#ifndef ABORT_ON_ASSERT_FAILURE
#define ABORT_ON_ASSERT_FAILURE 1
@ -215,588 +216,6 @@
#define FORCEINLINE forceinline
#define NOINLINE dontinline
#if !ONLY_MSPACES
/* ------------------- Declarations of public routines ------------------- */
/*
malloc(size_t n)
Returns a pointer to a newly allocated chunk of at least n bytes, or
null if no space is available, in which case errno is set to ENOMEM
on ANSI C systems.
If n is zero, malloc returns a minimum-sized chunk. (The minimum
size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
systems.) Note that size_t is an unsigned type, so calls with
arguments that would be negative if signed are interpreted as
requests for huge amounts of space, which will often fail. The
maximum supported value of n differs across systems, but is in all
cases less than the maximum representable value of a size_t.
*/
DLMALLOC_EXPORT void* dlmalloc(size_t);
/*
free(void* p)
Releases the chunk of memory pointed to by p, that had been previously
allocated using malloc or a related routine such as realloc.
It has no effect if p is null. If p was not malloced or already
freed, free(p) will by default cause the current program to abort.
*/
DLMALLOC_EXPORT void dlfree(void*);
/*
calloc(size_t n_elements, size_t element_size);
Returns a pointer to n_elements * element_size bytes, with all locations
set to zero.
*/
DLMALLOC_EXPORT void* dlcalloc(size_t, size_t);
/*
realloc(void* p, size_t n)
Returns a pointer to a chunk of size n that contains the same data
as does chunk p up to the minimum of (n, p's size) bytes, or null
if no space is available.
The returned pointer may or may not be the same as p. The algorithm
prefers extending p in most cases when possible, otherwise it
employs the equivalent of a malloc-copy-free sequence.
If p is null, realloc is equivalent to malloc.
If space is not available, realloc returns null, errno is set (if on
ANSI) and p is NOT freed.
if n is for fewer bytes than already held by p, the newly unused
space is lopped off and freed if possible. realloc with a size
argument of zero (re)allocates a minimum-sized chunk.
The old unix realloc convention of allowing the last-free'd chunk
to be used as an argument to realloc is not supported.
*/
DLMALLOC_EXPORT void* dlrealloc(void*, size_t);
/*
realloc_in_place(void* p, size_t n)
Resizes the space allocated for p to size n, only if this can be
done without moving p (i.e., only if there is adjacent space
available if n is greater than p's current allocated size, or n is
less than or equal to p's size). This may be used instead of plain
realloc if an alternative allocation strategy is needed upon failure
to expand space; for example, reallocation of a buffer that must be
memory-aligned or cleared. You can use realloc_in_place to trigger
these alternatives only when needed.
Returns p if successful; otherwise null.
*/
DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);
/*
memalign(size_t alignment, size_t n);
Returns a pointer to a newly allocated chunk of n bytes, aligned
in accord with the alignment argument.
The alignment argument should be a power of two. If the argument is
not a power of two, the nearest greater power is used.
8-byte alignment is guaranteed by normal malloc calls, so don't
bother calling memalign with an argument of 8 or less.
Overreliance on memalign is a sure way to fragment space.
*/
DLMALLOC_EXPORT void* dlmemalign(size_t, size_t);
/*
int posix_memalign(void** pp, size_t alignment, size_t n);
Allocates a chunk of n bytes, aligned in accord with the alignment
argument. Differs from memalign only in that it (1) assigns the
allocated memory to *pp rather than returning it, (2) fails and
returns EINVAL if the alignment is not a power of two (3) fails and
returns ENOMEM if memory cannot be allocated.
*/
DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);
/*
valloc(size_t n);
Equivalent to memalign(pagesize, n), where pagesize is the page
size of the system. If the pagesize is unknown, 4096 is used.
*/
DLMALLOC_EXPORT void* dlvalloc(size_t);
/*
mallopt(int parameter_number, int parameter_value)
Sets tunable parameters The format is to provide a
(parameter-number, parameter-value) pair. mallopt then sets the
corresponding parameter to the argument value if it can (i.e., so
long as the value is meaningful), and returns 1 if successful else
0. To workaround the fact that mallopt is specified to use int,
not size_t parameters, the value -1 is specially treated as the
maximum unsigned size_t value.
SVID/XPG/ANSI defines four standard param numbers for mallopt,
normally defined in malloc.h. None of these are use in this malloc,
so setting them has no effect. But this malloc also supports other
options in mallopt. See below for details. Briefly, supported
parameters are as follows (listed defaults are for "typical"
configurations).
Symbol param # default allowed param values
M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables)
M_GRANULARITY -2 page size any power of 2 >= page size
M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
*/
DLMALLOC_EXPORT int dlmallopt(int, int);
/*
malloc_footprint();
Returns the number of bytes obtained from the system. The total
number of bytes allocated by malloc, realloc etc., is less than this
value. Unlike mallinfo, this function returns only a precomputed
result, so can be called frequently to monitor memory consumption.
Even if locks are otherwise defined, this function does not use them,
so results might not be up to date.
*/
DLMALLOC_EXPORT size_t dlmalloc_footprint(void);
/*
malloc_max_footprint();
Returns the maximum number of bytes obtained from the system. This
value will be greater than current footprint if deallocated space
has been reclaimed by the system. The peak number of bytes allocated
by malloc, realloc etc., is less than this value. Unlike mallinfo,
this function returns only a precomputed result, so can be called
frequently to monitor memory consumption. Even if locks are
otherwise defined, this function does not use them, so results might
not be up to date.
*/
DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);
/*
malloc_footprint_limit();
Returns the number of bytes that the heap is allowed to obtain from
the system, returning the last value returned by
malloc_set_footprint_limit, or the maximum size_t value if
never set. The returned value reflects a permission. There is no
guarantee that this number of bytes can actually be obtained from
the system.
*/
DLMALLOC_EXPORT size_t dlmalloc_footprint_limit();
/*
malloc_set_footprint_limit();
Sets the maximum number of bytes to obtain from the system, causing
failure returns from malloc and related functions upon attempts to
exceed this value. The argument value may be subject to page
rounding to an enforceable limit; this actual value is returned.
Using an argument of the maximum possible size_t effectively
disables checks. If the argument is less than or equal to the
current malloc_footprint, then all future allocations that require
additional system memory will fail. However, invocation cannot
retroactively deallocate existing used memory.
*/
DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);
#if MALLOC_INSPECT_ALL
/*
malloc_inspect_all(void(*handler)(void *start,
void *end,
size_t used_bytes,
void* callback_arg),
void* arg);
Traverses the heap and calls the given handler for each managed
region, skipping all bytes that are (or may be) used for bookkeeping
purposes. Traversal does not include include chunks that have been
directly memory mapped. Each reported region begins at the start
address, and continues up to but not including the end address. The
first used_bytes of the region contain allocated data. If
used_bytes is zero, the region is unallocated. The handler is
invoked with the given callback argument. If locks are defined, they
are held during the entire traversal. It is a bad idea to invoke
other malloc functions from within the handler.
For example, to count the number of in-use chunks with size greater
than 1000, you could write:
static int count = 0;
void count_chunks(void* start, void* end, size_t used, void* arg) {
if (used >= 1000) ++count;
}
then:
malloc_inspect_all(count_chunks, NULL);
malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
*/
DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
void* arg);
#endif /* MALLOC_INSPECT_ALL */
/*
mallinfo()
Returns (by copy) a struct containing various summary statistics:
arena: current total non-mmapped bytes allocated from system
ordblks: the number of free chunks
smblks: always zero.
hblks: current number of mmapped regions
hblkhd: total bytes held in mmapped regions
usmblks: the maximum total allocated space. This will be greater
than current total if trimming has occurred.
fsmblks: always zero
uordblks: current total allocated space (normal or mmapped)
fordblks: total free space
keepcost: the maximum number of bytes that could ideally be released
back to system via malloc_trim. ("ideally" means that
it ignores page restrictions etc.)
Because these fields are ints, but internal bookkeeping may
be kept as longs, the reported values may wrap around zero and
thus be inaccurate.
*/
DLMALLOC_EXPORT struct mallinfo dlmallinfo(void);
/*
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
independent_calloc is similar to calloc, but instead of returning a
single cleared space, it returns an array of pointers to n_elements
independent elements that can hold contents of size elem_size, each
of which starts out cleared, and can be independently freed,
realloc'ed etc. The elements are guaranteed to be adjacently
allocated (this is not guaranteed to occur with multiple callocs or
mallocs), which may also improve cache locality in some
applications.
The "chunks" argument is optional (i.e., may be null, which is
probably the most typical usage). If it is null, the returned array
is itself dynamically allocated and should also be freed when it is
no longer needed. Otherwise, the chunks array must be of at least
n_elements in length. It is filled in with the pointers to the
chunks.
In either case, independent_calloc returns this pointer array, or
null if the allocation failed. If n_elements is zero and "chunks"
is null, it returns a chunk representing an array with zero elements
(which should be freed if not wanted).
Each element must be freed when it is no longer needed. This can be
done all at once using bulk_free.
independent_calloc simplifies and speeds up implementations of many
kinds of pools. It may also be useful when constructing large data
structures that initially have a fixed number of fixed-sized nodes,
but the number is not known at compile time, and some of the nodes
may later need to be freed. For example:
struct Node { int item; struct Node* next; };
struct Node* build_list() {
struct Node** pool;
int n = read_number_of_nodes_needed();
if (n <= 0) return 0;
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
if (pool == 0) die();
// organize into a linked list...
struct Node* first = pool[0];
for (i = 0; i < n-1; ++i)
pool[i]->next = pool[i+1];
free(pool); // Can now free the array (or not, if it is needed later)
return first;
}
*/
DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);
/*
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
independent_comalloc allocates, all at once, a set of n_elements
chunks with sizes indicated in the "sizes" array. It returns
an array of pointers to these elements, each of which can be
independently freed, realloc'ed etc. The elements are guaranteed to
be adjacently allocated (this is not guaranteed to occur with
multiple callocs or mallocs), which may also improve cache locality
in some applications.
The "chunks" argument is optional (i.e., may be null). If it is null
the returned array is itself dynamically allocated and should also
be freed when it is no longer needed. Otherwise, the chunks array
must be of at least n_elements in length. It is filled in with the
pointers to the chunks.
In either case, independent_comalloc returns this pointer array, or
null if the allocation failed. If n_elements is zero and chunks is
null, it returns a chunk representing an array with zero elements
(which should be freed if not wanted).
Each element must be freed when it is no longer needed. This can be
done all at once using bulk_free.
independent_comallac differs from independent_calloc in that each
element may have a different size, and also that it does not
automatically clear elements.
independent_comalloc can be used to speed up allocation in cases
where several structs or objects must always be allocated at the
same time. For example:
struct Head { ... }
struct Foot { ... }
void send_message(char* msg) {
int msglen = strlen(msg);
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
void* chunks[3];
if (independent_comalloc(3, sizes, chunks) == 0)
die();
struct Head* head = (struct Head*)(chunks[0]);
char* body = (char*)(chunks[1]);
struct Foot* foot = (struct Foot*)(chunks[2]);
// ...
}
In general though, independent_comalloc is worth using only for
larger values of n_elements. For small values, you probably won't
detect enough difference from series of malloc calls to bother.
Overuse of independent_comalloc can increase overall memory usage,
since it cannot reuse existing noncontiguous small chunks that
might be available for some of the elements.
*/
DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);
/*
bulk_free(void* array[], size_t n_elements)
Frees and clears (sets to null) each non-null pointer in the given
array. This is likely to be faster than freeing them one-by-one.
If footers are used, pointers that have been allocated in different
mspaces are not freed or cleared, and the count of all such pointers
is returned. For large arrays of pointers with poor locality, it
may be worthwhile to sort this array before calling bulk_free.
*/
DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements);
/*
pvalloc(size_t n);
Equivalent to valloc(minimum-page-that-holds(n)), that is,
round up n to nearest pagesize.
*/
DLMALLOC_EXPORT void* dlpvalloc(size_t);
/*
malloc_trim(size_t pad);
If possible, gives memory back to the system (via negative arguments
to sbrk) if there is unused memory at the `high' end of the malloc
pool or in unused MMAP segments. You can call this after freeing
large blocks of memory to potentially reduce the system-level memory
requirements of a program. However, it cannot guarantee to reduce
memory. Under some allocation patterns, some large free blocks of
memory will be locked between two used chunks, so they cannot be
given back to the system.
The `pad' argument to malloc_trim represents the amount of free
trailing space to leave untrimmed. If this argument is zero, only
the minimum amount of memory to maintain internal data structures
will be left. Non-zero arguments can be supplied to maintain enough
trailing space to service future expected allocations without having
to re-obtain memory from the system.
Malloc_trim returns 1 if it actually released any memory, else 0.
*/
DLMALLOC_EXPORT int dlmalloc_trim(size_t);
/*
malloc_stats();
Prints on stderr the amount of space obtained from the system (both
via sbrk and mmap), the maximum amount (which may be more than
current if malloc_trim and/or munmap got called), and the current
number of bytes allocated via malloc (or realloc, etc) but not yet
freed. Note that this is the number of bytes allocated, not the
number requested. It will be larger than the number requested
because of alignment and bookkeeping overhead. Because it includes
alignment wastage as being in use, this figure may be greater than
zero even when no user-level chunks are allocated.
The reported current and maximum system memory can be inaccurate if
a program makes other calls to system memory allocation functions
(normally sbrk) outside of malloc.
malloc_stats prints only the most commonly interesting statistics.
More information can be obtained by calling mallinfo.
*/
DLMALLOC_EXPORT void dlmalloc_stats(void);
/*
malloc_usable_size(void* p);
Returns the number of bytes you can actually use in
an allocated chunk, which may be more than you requested (although
often not) due to alignment and minimum size constraints.
You can use this many bytes without worrying about
overwriting other allocated objects. This is not a particularly great
programming practice. malloc_usable_size can be more useful in
debugging and assertions, for example:
p = malloc(n);
assert(malloc_usable_size(p) >= 256);
*/
size_t dlmalloc_usable_size(void*);
#endif /* ONLY_MSPACES */
#if MSPACES
/*
mspace is an opaque type representing an independent
region of space that supports mspace_malloc, etc.
*/
typedef void* mspace;
/*
create_mspace creates and returns a new independent space with the
given initial capacity, or, if 0, the default granularity size. It
returns null if there is no system memory available to create the
space. If argument locked is non-zero, the space uses a separate
lock to control access. The capacity of the space will grow
dynamically as needed to service mspace_malloc requests. You can
control the sizes of incremental increases of this space by
compiling with a different DEFAULT_GRANULARITY or dynamically
setting with mallopt(M_GRANULARITY, value).
*/
DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);
/*
destroy_mspace destroys the given space, and attempts to return all
of its memory back to the system, returning the total number of
bytes freed. After destruction, the results of access to all memory
used by the space become undefined.
*/
DLMALLOC_EXPORT size_t destroy_mspace(mspace msp);
/*
create_mspace_with_base uses the memory supplied as the initial base
of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
space is used for bookkeeping, so the capacity must be at least this
large. (Otherwise 0 is returned.) When this initial space is
exhausted, additional memory will be obtained from the system.
Destroying this space will deallocate all additionally allocated
space (if possible) but not the initial base.
*/
DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);
/*
mspace_track_large_chunks controls whether requests for large chunks
are allocated in their own untracked mmapped regions, separate from
others in this mspace. By default large chunks are not tracked,
which reduces fragmentation. However, such chunks are not
necessarily released to the system upon destroy_mspace. Enabling
tracking by setting to true may increase fragmentation, but avoids
leakage when relying on destroy_mspace to release all memory
allocated using this space. The function returns the previous
setting.
*/
DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);
/*
mspace_malloc behaves as malloc, but operates within
the given space.
*/
DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);
/*
mspace_free behaves as free, but operates within
the given space.
If compiled with FOOTERS==1, mspace_free is not actually needed.
free may be called instead of mspace_free because freed chunks from
any space are handled by their originating spaces.
*/
DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);
/*
mspace_realloc behaves as realloc, but operates within
the given space.
If compiled with FOOTERS==1, mspace_realloc is not actually
needed. realloc may be called instead of mspace_realloc because
realloced chunks from any space are handled by their originating
spaces.
*/
DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);
/*
mspace_calloc behaves as calloc, but operates within
the given space.
*/
DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
/*
mspace_memalign behaves as memalign, but operates within
the given space.
*/
DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
/*
mspace_independent_calloc behaves as independent_calloc, but
operates within the given space.
*/
DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,
size_t elem_size, void* chunks[]);
/*
mspace_independent_comalloc behaves as independent_comalloc, but
operates within the given space.
*/
DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,
size_t sizes[], void* chunks[]);
/*
mspace_footprint() returns the number of bytes obtained from the
system for this space.
*/
DLMALLOC_EXPORT size_t mspace_footprint(mspace msp);
/*
mspace_max_footprint() returns the peak number of bytes obtained from the
system for this space.
*/
DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);
#if !NO_MALLINFO
/*
mspace_mallinfo behaves as mallinfo, but reports properties of
the given space.
*/
DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);
#endif /* NO_MALLINFO */
/*
malloc_usable_size(void* p) behaves the same as malloc_usable_size;
*/
DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);
/*
mspace_malloc_stats behaves as malloc_stats, but reports
properties of the given space.
*/
DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);
/*
mspace_trim behaves as malloc_trim, but
operates within the given space.
*/
DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);
/*
An alias for mallopt.
*/
DLMALLOC_EXPORT int mspace_mallopt(int, int);
#endif /* MSPACES */
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
/*
========================================================================
To make a fully customizable malloc.h header file, cut everything
@ -4364,7 +3783,7 @@ int dlmallopt(int param_number, int value) {
return change_mparam(param_number, value);
}
size_t dlmalloc_usable_size(void* mem) {
size_t dlmalloc_usable_size(const void* mem) {
mchunkptr p;
size_t bytes;
if (mem) {

View file

@ -505,6 +505,8 @@ void mspace_inspect_all(mspace msp,
void (*handler)(void*, void*, size_t, void*),
void* arg);
void dlmalloc_abort(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_DLMALLOC_DLMALLOC_H_ */

View file

@ -52,6 +52,7 @@ $(THIRD_PARTY_DLMALLOC_A).pkg: \
$(THIRD_PARTY_DLMALLOC_A_OBJS): \
OVERRIDE_CFLAGS += \
$(NO_MAGIC) \
-ffreestanding \
-ffunction-sections \
-fdata-sections

View file

@ -0,0 +1,29 @@
/*-*- 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/bits/weaken.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "third_party/dlmalloc/dlmalloc.h"
void dlmalloc_abort(void) {
kprintf("dlmalloc_abort()%n");
if (weaken(__die)) weaken(__die)();
_Exit(44);
}

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,11 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
#define COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
#include "libc/calls/struct/winsize.h"
#include "libc/stdio/stdio.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct linenoiseState;
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
@ -13,17 +16,14 @@ typedef char *(linenoiseHintsCallback)(const char *, const char **,
const char **);
typedef void(linenoiseFreeHintsCallback)(void *);
typedef wint_t(linenoiseXlatCallback)(wint_t);
typedef int(linenoisePollCallback)(int, int);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
void linenoiseSetXlatCallback(linenoiseXlatCallback *);
void linenoiseSetPollCallback(linenoisePollCallback *);
char *linenoise(const char *) dontdiscard;
char *linenoiseRaw(const char *, int, int) dontdiscard;
char *linenoiseWithHistory(const char *, const char *) dontdiscard;
int linenoiseHistoryAdd(const char *);
int linenoiseHistorySave(const char *);
@ -33,8 +33,22 @@ void linenoiseHistoryFree(void);
void linenoiseClearScreen(int);
void linenoiseMaskModeEnable(void);
void linenoiseMaskModeDisable(void);
int linenoiseEnableRawMode(int);
void linenoiseDisableRawMode(void);
void linenoiseFree(void *);
int linenoiseIsTerminal(void);
int linenoiseIsTeletype(void);
char *linenoiseGetHistoryPath(const char *);
struct linenoiseState *linenoiseBegin(const char *, int, int);
ssize_t linenoiseEdit(struct linenoiseState *, const char *, char **, bool);
int linenoiseGetInterrupt(void);
void linenoiseEnd(struct linenoiseState *);
char *linenoiseGetLine(FILE *);
struct winsize linenoiseGetTerminalSize(struct winsize, int, int);
void linenoiseRefreshLine(struct linenoiseState *);
char *linenoiseRaw(const char *, int, int) dontdiscard;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -25,6 +25,7 @@ THIRD_PARTY_LINENOISE_A_DIRECTDEPS = \
LIBC_SOCK \
LIBC_STDIO \
LIBC_RUNTIME \
LIBC_LOG \
LIBC_SYSV_CALLS \
LIBC_STR \
LIBC_UNICODE \

View file

@ -1,6 +1,9 @@
#define lua_c
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/check.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h"
@ -13,8 +16,13 @@
#include "third_party/lua/lualib.h"
// clang-format off
bool lua_repl_blocking;
bool lua_repl_isterminal;
_Alignas(64) char lualock;
struct linenoiseState *lua_repl_linenoise;
static lua_State *globalL;
static const char *g_progname;
static const char *g_historypath;
/*
** {==================================================================
@ -111,14 +119,35 @@ static int incomplete (lua_State *L, int status) {
/*
** Prompt the user, read a line, and push it into the Lua stack.
*/
static int pushline (lua_State *L, int firstline) {
static ssize_t pushline (lua_State *L, int firstline) {
char *b;
size_t l;
ssize_t rc;
char *prmt;
globalL = L;
const char *prmt = get_prompt(L, firstline);
if (!(b = linenoiseWithHistory(prmt, g_progname)))
return 0; /* no input (prompt will be popped by caller) */
if (lua_repl_isterminal) {
prmt = strdup(get_prompt(L, firstline));
lua_pop(L, 1); /* remove prompt */
_spunlock(&lualock);
rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking);
free(prmt);
if (rc != -1) {
if (b && *b) {
linenoiseHistoryLoad(g_historypath);
linenoiseHistoryAdd(b);
linenoiseHistorySave(g_historypath);
}
}
_spinlock(&lualock);
} else {
_spunlock(&lualock);
b = linenoiseGetLine(stdin);
_spinlock(&lualock);
rc = b ? 1 : -1;
}
if (rc == -1 || (!rc && !b)) {
return rc;
}
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
b[--l] = '\0'; /* remove it */
@ -164,9 +193,10 @@ static void lstop (lua_State *L, lua_Debug *ar) {
static int multiline (lua_State *L) {
for (;;) { /* repeat until gets a complete statement */
size_t len;
ssize_t rc;
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
if (!incomplete(L, status) || !pushline(L, 0)) {
if (!incomplete(L, status) || pushline(L, 0) != 1) {
return status; /* cannot or should not try to add continuation line */
}
lua_pushliteral(L, "\n"); /* add newline... */
@ -176,11 +206,38 @@ static int multiline (lua_State *L) {
}
void lua_initrepl(const char *progname) {
void lua_initrepl(lua_State *L, const char *progname) {
const char *prompt;
_spinlock(&lualock);
g_progname = progname;
if ((lua_repl_isterminal = linenoiseIsTerminal())) {
linenoiseSetCompletionCallback(lua_readline_completions);
linenoiseSetHintsCallback(lua_readline_hint);
linenoiseSetFreeHintsCallback(free);
prompt = get_prompt(L, 1);
if ((g_historypath = linenoiseGetHistoryPath(progname))) {
if (linenoiseHistoryLoad(g_historypath) == -1) {
kprintf("%r%s: failed to load history: %m%n", g_historypath);
free(g_historypath);
g_historypath = 0;
}
}
lua_repl_linenoise = linenoiseBegin(prompt, 0, 1);
lua_pop(L, 1); /* remove prompt */
__nomultics = 2;
__replmode = true;
}
_spunlock(&lualock);
}
void lua_freerepl(void) {
_spinlock(&lualock);
__nomultics = false;
__replmode = false;
linenoiseEnd(lua_repl_linenoise);
free(g_historypath);
_spunlock(&lualock);
}
@ -189,16 +246,24 @@ void lua_initrepl(const char *progname) {
** adding "return " in front of it) and second as a statement. Return
** the final status of load/call with the resulting function (if any)
** in the top of the stack.
**
** returns -1 on eof
** returns -2 on error
*/
int lua_loadline (lua_State *L) {
ssize_t rc;
int status;
lua_settop(L, 0);
if (!pushline(L, 1))
return -1; /* no input */
_spinlock(&lualock);
if ((rc = pushline(L, 1)) != 1) {
_spunlock(&lualock);
return rc - 1; /* eof or error */
}
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
status = multiline(L); /* try as command, maybe with continuation lines */
lua_remove(L, 1); /* remove line from the stack */
lua_assert(lua_gettop(L) == 1);
_spunlock(&lualock);
return status;
}

View file

@ -5,9 +5,15 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern char lualock;
extern bool lua_repl_blocking;
extern bool lua_repl_isterminal;
extern struct linenoiseState *lua_repl_linenoise;
void lua_freerepl(void);
int lua_loadline(lua_State *);
void lua_l_print(lua_State *);
void lua_initrepl(const char *);
void lua_initrepl(lua_State *, const char *);
int lua_report(lua_State *, int);
int lua_runchunk(lua_State *, int, int);
void lua_l_message(const char *, const char *);

View file

@ -10,14 +10,19 @@
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/stack.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sa.h"
#include "libc/x/x.h"
#include "third_party/linenoise/linenoise.h"
#include "third_party/lua/cosmo.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lprefix.h"
#include "third_party/lua/lrepl.h"
@ -275,8 +280,27 @@ static void doREPL (lua_State *L) {
int status;
const char *oldprogname = progname;
progname = NULL; /* no 'progname' on errors in interactive mode */
lua_initrepl(LUA_PROGNAME);
while ((status = lua_loadline(L)) != -1) {
lua_initrepl(L, LUA_PROGNAME);
for (;;) {
linenoiseEnableRawMode(0);
TryAgain:
status = lua_loadline(L);
if (status == -2 && errno == EAGAIN) {
errno = 0;
poll(&(struct pollfd){0, POLLIN}, 1, -1);
goto TryAgain;
}
linenoiseDisableRawMode();
if (status == -1) {
break;
} else if (status == -2) {
lua_pushfstring(L, "read error: %s", strerror(errno));
lua_report(L, status);
lua_freerepl();
progname = oldprogname;
return;
}
lua_writeline();
if (status == LUA_OK)
status = lua_runchunk(L, 0, LUA_MULTRET);
if (status == LUA_OK) {
@ -285,6 +309,7 @@ static void doREPL (lua_State *L) {
lua_report(L, status);
}
}
lua_freerepl();
lua_settop(L, 0); /* clear stack */
lua_writeline();
progname = oldprogname;
@ -343,7 +368,7 @@ static int pmain (lua_State *L) {
int main (int argc, char **argv) {
int status, result;
lua_State *L;
if (!IsModeDbg()) {
if (IsModeDbg()) {
ShowCrashReports();
}
/* if (IsModeDbg()) ShowCrashReports(); */

View file

@ -103,22 +103,21 @@ static void AppendArg(struct Args *l, char *s) {
static void MakeHeader(struct Header *h, const char *name, int ref, int mode,
int size) {
size_t n;
char buf[24];
memset(h, ' ', sizeof(*h));
n = strlen(name);
memcpy(h->name, name, n);
if (ref != -1) {
memcpy(h->name + n, buf, uint64toarray_radix10(ref, buf));
FormatUint32(h->name + n, ref);
}
if (strcmp(name, "//") != 0) {
h->date[0] = '0';
h->uid[0] = '0';
h->gid[0] = '0';
memcpy(h->mode, buf, uint64toarray_radix8(mode & 0777, buf));
FormatOctal32(h->mode, mode & 0777, false);
}
h->fmag[0] = '`';
h->fmag[1] = '\n';
memcpy(h->size, buf, uint64toarray_radix10(size, buf));
FormatUint32(h->size, size);
}
int main(int argc, char *argv[]) {

View file

@ -1271,7 +1271,7 @@ static void DrawXmm(struct Panel *p, long i, long r) {
uint64toarray_fixed16(ival, buf, xmmtype.size[r] * 8);
}
} else {
int64toarray_radix10(SignExtend(ival, xmmtype.size[r] * 8), buf);
FormatInt64(buf, SignExtend(ival, xmmtype.size[r] * 8));
}
break;
default:
@ -2270,7 +2270,8 @@ 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);
}

View file

@ -30,9 +30,9 @@ size_t FormatCga(uint8_t bgfg, char buf[hasatleast 11]) {
char *p = buf;
*p++ = '\e';
*p++ = '[';
p += uint64toarray_radix10(kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10, p);
p = FormatUint32(p, kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10);
*p++ = ';';
p += uint64toarray_radix10(kCgaToAnsi[bgfg & 0x0F], p);
p = FormatUint32(p, kCgaToAnsi[bgfg & 0x0F]);
*p++ = 'm';
*p = '\0';
return p - buf;

View file

@ -128,7 +128,7 @@ static char *DisRegisterWord(struct Dis *d, uint32_t rde, char *p, bool g,
static char *DisInt(char *p, int64_t x) {
if (-15 <= x && x <= 15) {
p += int64toarray_radix10(x, p);
p = FormatInt64(p, x);
} else if (x == INT64_MIN) {
p = stpcpy(p, "-0x");
p += uint64toarray_radix16(INT64_MIN, p);
@ -319,7 +319,8 @@ static char *DisRegMem(struct Dis *d, uint32_t rde, char *p,
}
static dontinline char *DisE(struct Dis *d, uint32_t rde, char *p,
char *f(struct Dis *, uint32_t, char *, bool, int)) {
char *f(struct Dis *, uint32_t, char *, bool,
int)) {
if (IsModrmRegister(rde)) {
return f(d, rde, p, Rexb(rde), ModrmRm(rde));
} else {
@ -471,13 +472,13 @@ static char *DisOne(struct Dis *d, uint32_t rde, char *p) {
static char *DisJbs(struct Dis *d, uint32_t rde, char *p) {
if (d->xedd->op.disp > 0) *p++ = '+';
p += int64toarray_radix10(d->xedd->op.disp, p);
p = FormatInt64(p, d->xedd->op.disp);
return p;
}
static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
if (d->xedd->op.disp > 0) *p++ = '+';
p += uint64toarray_radix10(d->xedd->op.disp & 0xff, p);
p = FormatUint32(p, d->xedd->op.disp & 0xff);
return p;
}
@ -522,7 +523,7 @@ static char *DisXmm(struct Dis *d, uint32_t rde, char *p, const char *s,
p = HighStart(p, g_high.reg);
*p++ = '%';
p = stpcpy(p, s);
p += uint64toarray_radix10(reg, p);
p = FormatUint32(p, reg);
p = HighEnd(p);
return p;
}

View file

@ -25,7 +25,7 @@ struct High g_high;
char *HighStart(char *p, int h) {
if (h) {
p = stpcpy(p, "\e[38;5;");
p += uint64toarray_radix10(h, p);
p = FormatUint32(p, h);
p = stpcpy(p, "m");
g_high.active = true;
}

View file

@ -693,9 +693,9 @@ static void PtyReportCursorPosition(struct Pty *pty) {
p = buf;
*p++ = '\e';
*p++ = '[';
p += uint64toarray_radix10((pty->y + 1) & 0x7fff, p);
p = FormatInt32(p, (pty->y + 1) & 0x7fff);
*p++ = ';';
p += uint64toarray_radix10((pty->x + 1) & 0x7fff, p);
p = FormatInt32(p, (pty->x + 1) & 0x7fff);
*p++ = 'R';
PtyWriteInput(pty, buf, p - buf);
}
@ -1178,7 +1178,8 @@ ssize_t PtyWriteInput(struct Pty *pty, const void *data, size_t n) {
m = pty->input.n;
if (i + n * 2 + 1 > m) {
m = MAX(m, 8);
do m += m >> 1;
do
m += m >> 1;
while (i + n * 2 + 1 > m);
if (!(p = realloc(p, m))) {
return -1;
@ -1229,18 +1230,18 @@ ssize_t PtyRead(struct Pty *pty, void *buf, size_t size) {
static char *PtyEncodeRgb(char *p, int rgb) {
*p++ = '2';
*p++ = ';';
p += uint64toarray_radix10((rgb & 0x0000ff) >> 000, p);
p = FormatUint32(p, (rgb & 0x0000ff) >> 000);
*p++ = ';';
p += uint64toarray_radix10((rgb & 0x00ff00) >> 010, p);
p = FormatUint32(p, (rgb & 0x00ff00) >> 010);
*p++ = ';';
p += uint64toarray_radix10((rgb & 0xff0000) >> 020, p);
p = FormatUint32(p, (rgb & 0xff0000) >> 020);
return p;
}
static char *PtyEncodeXterm256(char *p, int xt) {
*p++ = '5';
*p++ = ';';
p += uint64toarray_radix10(xt, p);
p = FormatUint32(p, xt);
return p;
}

View file

@ -661,7 +661,7 @@ static const char *GetErrnoName(int x) {
const char *s;
static char buf[16];
if ((s = strerror_short(x))) return s;
int64toarray_radix10(x, buf);
FormatInt64(buf, x);
return buf;
}

View file

@ -58,7 +58,7 @@ void PrintClosure(struct Closure *c, const char *name, int indent, FILE *f) {
fputs(": ", f);
Print(c->term, 0, GetDepth(c->envp), f);
fputs(" +", f);
int64toarray_radix10(c->refs, ibuf);
FormatInt64(ibuf, c->refs);
fputs(ibuf, f);
fputc('\n', f);
PrintClosure(c->envp, "envp", indent + 1, f);

View file

@ -632,7 +632,7 @@ void PrintVar(int i, FILE* f) {
char ibuf[22];
switch (style) {
case 0:
int64toarray_radix10(i, ibuf);
FormatInt64(ibuf, i);
fputs(ibuf, f);
break;
case 1:
@ -642,7 +642,7 @@ void PrintVar(int i, FILE* f) {
fputwc(FREEBIES[~i], f);
} else {
ibuf[0] = '?';
int64toarray_radix10(i, ibuf + 1);
FormatInt64(ibuf + 1, i);
fputs(ibuf, f);
}
break;
@ -889,7 +889,7 @@ void PrintDebruijn(int x, int head, int depth, FILE* f) {
PrintVar(mem[x + 1], f);
} else {
fputc(L'', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
} else if (mem[x] == IOP) {
@ -905,19 +905,19 @@ void PrintDebruijn(int x, int head, int depth, FILE* f) {
fputs(asciiname ? "gro" : "", f);
} else {
fputc(L'!', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
} else {
fputc(L'!', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
return;
}
Overflow:
fputc(L'', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
@ -1172,7 +1172,7 @@ void PrintLambda(int x, int head, int depth, int apps, FILE* f) {
PrintVar(depth - 1 - mem[x + 1], f);
} else {
fputc(L'', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
} else if (mem[x] == APP) {
@ -1198,12 +1198,12 @@ void PrintLambda(int x, int head, int depth, int apps, FILE* f) {
fputs(asciiname ? "gro" : "", f);
} else {
fputc(L'!', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
} else {
fputc(L'!', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
if (close) {
@ -1213,7 +1213,7 @@ void PrintLambda(int x, int head, int depth, int apps, FILE* f) {
}
Overflow:
fputc(L'', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
@ -1239,7 +1239,7 @@ void PrintBinary(int x, int head, int depth, FILE* f) {
PrintVar(mem[x + 1], f);
} else {
fputc(L'', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
} else if (mem[x] == APP) {
@ -1263,14 +1263,14 @@ void PrintBinary(int x, int head, int depth, FILE* f) {
fputwc(L'', f);
} else {
fputc(L'!', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}
return;
}
Overflow:
fputc(L'', f);
int64toarray_radix10(x, ibuf);
FormatInt64(ibuf, x);
fputs(ibuf, f);
}

View file

@ -20,17 +20,17 @@ db:exec[[
INSERT INTO test (content) VALUES ('Hello Sqlite3');
]]
-- this intercepts all requests if it's defined
function OnHttpRequest()
if HasParam('magic') then
Write('<p>\r\n')
Write('OnHttpRequest() has intercepted your request<br>\r\n')
Write('because you specified the magic parameter\r\n')
Write('<pre>\r\n')
Write(EscapeHtml(LoadAsset('/.init.lua')))
Write('</pre>\r\n')
else
Route() -- this asks redbean to do the default thing
end
SetHeader('Server', 'redbean!')
end
-- -- this intercepts all requests if it's defined
-- function OnHttpRequest()
-- if HasParam('magic') then
-- Write('<p>\r\n')
-- Write('OnHttpRequest() has intercepted your request<br>\r\n')
-- Write('because you specified the magic parameter\r\n')
-- Write('<pre>\r\n')
-- Write(EscapeHtml(LoadAsset('/.init.lua')))
-- Write('</pre>\r\n')
-- else
-- Route() -- this asks redbean to do the default thing
-- end
-- SetHeader('Server', 'redbean!')
-- end

View file

@ -39,6 +39,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
@ -50,10 +51,12 @@
#include "libc/nexgen32e/bsf.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/crc32.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/rdtscp.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/rand/rand.h"
#include "libc/runtime/clktck.h"
#include "libc/runtime/directmap.internal.h"
@ -362,6 +365,7 @@ static bool printport;
static bool daemonize;
static bool logrusage;
static bool logbodies;
static bool isterminal;
static bool sslcliused;
static bool loglatency;
static bool terminated;
@ -835,12 +839,13 @@ static void DescribeAddress(char buf[40], uint32_t addr, uint16_t port) {
char *p;
const char *s;
p = buf;
p += uint64toarray_radix10((addr & 0xFF000000) >> 030, p), *p++ = '.';
p += uint64toarray_radix10((addr & 0x00FF0000) >> 020, p), *p++ = '.';
p += uint64toarray_radix10((addr & 0x0000FF00) >> 010, p), *p++ = '.';
p += uint64toarray_radix10((addr & 0x000000FF) >> 000, p), *p++ = ':';
p += uint64toarray_radix10(port, p);
*p++ = '\0';
p = FormatUint64(p, (addr & 0xFF000000) >> 030), *p++ = '.';
p = FormatUint64(p, (addr & 0x00FF0000) >> 020), *p++ = '.';
p = FormatUint64(p, (addr & 0x0000FF00) >> 010), *p++ = '.';
p = FormatUint64(p, (addr & 0x000000FF) >> 000), *p++ = ':';
p = FormatUint64(p, port);
*p = '\0';
assert(p - buf < 40);
}
static inline void GetServerAddr(uint32_t *ip, uint16_t *port) {
@ -1029,7 +1034,7 @@ static void Daemonize(void) {
umask(0);
if (pidpath) {
fd = open(pidpath, O_CREAT | O_WRONLY, 0644);
WRITE(fd, ibuf, uint64toarray_radix10(getpid(), ibuf));
WRITE(fd, ibuf, FormatInt32(ibuf, getpid()) - ibuf);
close(fd);
}
if (!logpath) ProgramLogPath("/dev/null");
@ -1486,6 +1491,7 @@ static void CertsDestroy(void) {
static void WipeServingKeys(void) {
size_t i;
long double t = nowl();
if (uniprocess) return;
mbedtls_ssl_ticket_free(&ssltick);
mbedtls_ssl_key_cert_free(conf.key_cert), conf.key_cert = 0;
@ -2083,7 +2089,7 @@ static char *AppendExpires(char *p, int64_t t) {
static char *AppendCache(char *p, int64_t seconds) {
if (seconds < 0) return p;
p = stpcpy(p, "Cache-Control: max-age=");
p += uint64toarray_radix10(seconds, p);
p = FormatUint64(p, seconds);
if (seconds) {
p = stpcpy(p, ", public");
} else {
@ -2095,21 +2101,21 @@ static char *AppendCache(char *p, int64_t seconds) {
static inline char *AppendContentLength(char *p, size_t n) {
p = stpcpy(p, "Content-Length: ");
p += uint64toarray_radix10(n, p);
p = FormatUint64(p, n);
return AppendCrlf(p);
}
static char *AppendContentRange(char *p, long a, long b, long c) {
p = stpcpy(p, "Content-Range: bytes ");
if (a >= 0 && b > 0) {
p += uint64toarray_radix10(a, p);
p = FormatUint64(p, a);
*p++ = '-';
p += uint64toarray_radix10(a + b - 1, p);
p = FormatUint64(p, a + b - 1);
} else {
*p++ = '*';
}
*p++ = '/';
p += uint64toarray_radix10(c, p);
p = FormatUint64(p, c);
return AppendCrlf(p);
}
@ -6396,6 +6402,7 @@ static bool StreamResponse(char *p) {
static bool HandleMessageActual(void) {
int rc;
char *p;
long double now;
if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) {
if (!rc) return false;
hdrsize = rc;
@ -6437,8 +6444,11 @@ static bool HandleMessageActual(void) {
LockInc(&shared->c.messageshandled);
++messageshandled;
if (loglatency || LOGGABLE(kLogDebug)) {
LOGF(kLogDebug, "(stat) %`'.*s latency %,ldµs", msg.uri.b - msg.uri.a,
inbuf.p + msg.uri.a, (long)((nowl() - startrequest) * 1e6L));
now = nowl();
LOGF(kLogDebug, "(stat) %`'.*s latency r: %,ldµs c: %,ldµs",
msg.uri.b - msg.uri.a, inbuf.p + msg.uri.a,
(long)((now - startrequest) * 1e6L),
(long)((now - startconnection) * 1e6L));
}
if (!generator) {
return TransmitResponse(p);
@ -6702,7 +6712,6 @@ static int EnableSandbox(void) {
}
}
// returns 0 otherwise -1 if worker needs to unwind stack and exit
static int HandleConnection(size_t i) {
int pid, rc = 0;
clientaddrsize = sizeof(clientaddr);
@ -6731,10 +6740,16 @@ static int HandleConnection(size_t i) {
__kbirth = rdtsc();
}
if (funtrace) {
ftrace_install();
if (ftrace_install() != -1) {
g_ftrace = 1;
} else {
WARNF("ftrace failed to install %m");
}
}
}
if (sandboxed) {
CHECK_NE(-1, EnableSandbox());
}
if (hasonworkerstart) {
CallSimpleHook("OnWorkerStart");
}
@ -6824,45 +6839,6 @@ static int HandleConnection(size_t i) {
return rc;
}
// returns 2 if we should stay in the redbean event loop
// returns 1 if poll() says stdin has user input available
// returns 0 if poll() timed out after ms
// returns -1 if worker is unwinding exit
static int HandlePoll(int ms) {
size_t i;
int nfds;
if ((nfds = poll(polls, 1 + servers.n, ms)) != -1) {
for (i = 0; i < servers.n; ++i) {
if (polls[1 + i].revents) {
serveraddr = &servers.p[i].addr;
ishandlingconnection = true;
if (HandleConnection(i) == -1) return -1;
ishandlingconnection = false;
}
}
// are we polling stdin for the repl?
if (polls[0].fd >= 0) {
if (polls[0].revents) {
return 1; // user entered a keystroke
} else if (!nfds) {
return 0; // let linenoise know it timed out
}
}
} else {
if (errno == EINTR || errno == EAGAIN) {
LockInc(&shared->c.pollinterrupts);
} else if (errno == ENOMEM) {
LockInc(&shared->c.enomems);
WARNF("(srvr) %s ran out of memory");
meltdown = true;
} else {
DIEF("(srvr) poll error: %m");
}
errno = 0;
}
return 2;
}
static void RestoreApe(void) {
char *p;
size_t n;
@ -6883,6 +6859,97 @@ static void RestoreApe(void) {
}
}
static int HandleReadline(void) {
int status;
for (;;) {
status = lua_loadline(GL);
if (status < 0) {
if (status == -1) {
OnTerm(SIGHUP); // eof
INFOF("got repl eof");
write(1, "\r\n", 2);
return -1;
} else if (errno == EINTR) {
errno = 0;
OnInt(SIGINT);
INFOF("got repl interrupt");
return 0;
} else if (errno == EAGAIN) {
errno = 0;
return 0;
} else {
OnTerm(SIGIO); // error
return -1;
}
}
write(1, "\r\n", 2);
linenoiseDisableRawMode();
_spinlock(&lualock);
if (status == LUA_OK) {
status = lua_runchunk(GL, 0, LUA_MULTRET);
}
if (status == LUA_OK) {
lua_l_print(GL);
} else {
lua_report(GL, status);
}
_spunlock(&lualock);
if (lua_repl_isterminal) {
linenoiseEnableRawMode(0);
}
}
}
static int HandlePoll(int ms) {
int rc, nfds;
size_t pollid, serverid;
if ((nfds = poll(polls, 1 + servers.n, ms)) != -1) {
if (nfds) {
// handle pollid/o events
for (pollid = 0; pollid < 1 + servers.n; ++pollid) {
if (!polls[pollid].revents) continue;
if (polls[pollid].fd < 0) continue;
if (polls[pollid].fd) {
// handle listen socket
serverid = pollid - 1;
assert(0 <= serverid && serverid < servers.n);
serveraddr = &servers.p[serverid].addr;
ishandlingconnection = true;
_spinlock(&lualock);
rc = HandleConnection(serverid);
_spunlock(&lualock);
ishandlingconnection = false;
if (rc == -1) return -1;
} else {
// handle standard input
rc = HandleReadline();
if (rc == -1) return rc;
}
}
} else if (__replmode) {
// handle refresh repl line
if (!IsWindows()) {
rc = HandleReadline();
if (rc < 0) return rc;
} else {
linenoiseRefreshLine(lua_repl_linenoise);
}
}
} else {
if (errno == EINTR || errno == EAGAIN) {
LockInc(&shared->c.pollinterrupts);
} else if (errno == ENOMEM) {
LockInc(&shared->c.enomems);
WARNF("(srvr) %s ran out of memory");
meltdown = true;
} else {
DIEF("(srvr) poll error: %m");
}
errno = 0;
}
return 0;
}
static void Listen(void) {
char ipbuf[16];
size_t i, j, n;
@ -6960,10 +7027,9 @@ static void HandleShutdown(void) {
}
// this function coroutines with linenoise
static int EventLoop(int fd, int ms) {
int rc;
static int EventLoop(int ms) {
long double t;
rc = -1;
VERBOSEF("EventLoop()");
while (!terminated) {
errno = 0;
if (zombied) {
@ -6977,54 +7043,47 @@ static int EventLoop(int fd, int ms) {
} else if ((t = nowl()) - lastheartbeat > HEARTBEAT / 1000.) {
lastheartbeat = t;
HandleHeartbeat();
} else if ((rc = HandlePoll(ms)) != 2) {
break; // return control to linenoise
} else if (HandlePoll(ms) == -1) {
break;
}
}
return rc;
return -1;
}
static void ReplEventLoop(void) {
int status;
long double t;
lua_State *L = GL;
DEBUGF("ReplEventLoop()");
polls[0].fd = 0;
__nomultics = 2;
__replmode = true;
lua_initrepl("redbean");
linenoiseSetPollCallback(EventLoop);
for (;;) {
if ((status = lua_loadline(L)) == -1) {
if (errno == EINTR) {
LockInc(&shared->c.pollinterrupts);
if (terminated) {
break;
} else {
continue;
lua_initrepl(GL, "redbean");
if (lua_repl_isterminal) {
linenoiseEnableRawMode(0);
}
} else {
break;
}
}
if (status == LUA_OK) {
status = lua_runchunk(L, 0, LUA_MULTRET);
}
if (status == LUA_OK) {
lua_l_print(L);
} else {
lua_report(L, status);
}
}
if (!terminated && !isexitingworker) {
OnTerm(SIGHUP); // eof event
}
lua_settop(L, 0); // clear stack
lua_writeline();
__replmode = false;
__nomultics = 0;
EventLoop(100);
linenoiseDisableRawMode();
lua_freerepl();
lua_settop(GL, 0); // clear stack
polls[0].fd = -1;
}
static uint32_t WindowsReplThread(void *arg) {
DEBUGF("WindowsReplThread()");
lua_repl_blocking = true;
lua_initrepl(GL, "redbean");
if (lua_repl_isterminal) {
linenoiseEnableRawMode(0);
}
for (;;) {
if (HandleReadline() == -1) {
break;
}
}
linenoiseDisableRawMode();
lua_freerepl();
_spinlock(&lualock);
lua_settop(GL, 0); // clear stack
_spunlock(&lualock);
return 0;
}
static void SigInit(void) {
xsigaction(SIGINT, OnInt, 0, 0, 0);
xsigaction(SIGHUP, OnHup, 0, 0, 0);
@ -7217,13 +7276,6 @@ void RedBean(int argc, char *argv[]) {
if (daemonize) {
Daemonize();
} else {
// xxx: create process group to make it easier to propagate SIGTERM
// to children. the downside to doing this seems to be that
// ctrl-c isn't propagating as expected when running redbean
// underneath strace.com :|
if (!IsWindows()) {
setpgrp();
}
if (logpath) {
close(2);
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
@ -7240,14 +7292,18 @@ void RedBean(int argc, char *argv[]) {
isinitialized = true;
CallSimpleHookIfDefined("OnServerStart");
#ifdef STATIC
EventLoop(-1, HEARTBEAT);
EventLoop(HEARTBEAT);
#else
GetResolvConf(); // for effect
GetHostsTxt(); // for effect
if (!IsWindows() && isatty(0)) {
ReplEventLoop();
GetResolvConf(); // for effect
if (daemonize || !linenoiseIsTerminal()) {
EventLoop(HEARTBEAT);
} else if (IsWindows()) {
uint32_t tid;
CreateThread(0, 0, NT2SYSV(WindowsReplThread), 0, 0, &tid);
EventLoop(100);
} else {
EventLoop(-1, HEARTBEAT);
ReplEventLoop();
}
#endif
if (!isexitingworker) {

View file

@ -83,7 +83,7 @@ void bf(int fd) {
obuf[n++] = ';';
obuf[n++] = '5';
obuf[n++] = ';';
n += int64toarray_radix10(fg, obuf + n);
n = FormatInt64(obuf + n, fg) - (obuf + n);
obuf[n++] = 'm';
}
obuf[n++] = "0123456789abcdef"[c >> 4];

View file

@ -79,7 +79,7 @@ static const char *GetStorageSpecifier(const char *type, int *out_width,
static void EmitSection(long yn, long xn, int w, int arrayalign, int emit(),
void *a) {
char alignstr[21];
uint64toarray_radix10(arrayalign, alignstr);
FormatUint32(alignstr, arrayalign);
if (arrayalign <= 8 && yn * xn * w == 8) {
emit("\t.rodata.cst", a);
emit("8\n", a);
@ -108,8 +108,8 @@ void *FormatStringTableAsAssembly(long yn, long xn, const char *const T[yn][xn],
char ynstr[21], xnstr[21];
name = firstnonnull(name, "M");
storage = GetStorageSpecifier(firstnonnull(type, "long"), &w, &align);
uint64toarray_radix10(yn, ynstr);
uint64toarray_radix10(xn, xnstr);
FormatUint64(ynstr, yn);
FormatUint64(xnstr, xn);
EmitSection(yn, xn, w, GetArrayAlignment(yn, xn, w, align), emit, a);
emit(name, a);
emit(":", a);

View file

@ -24,8 +24,8 @@ void *FormatStringTableAsCode(long yn, long xn, const char *const T[yn][xn],
int emit(), void *arg, const char *type,
const char *name, const char *ignored) {
char ynstr[21], xnstr[21];
uint64toarray_radix10(yn, ynstr);
uint64toarray_radix10(xn, xnstr);
FormatUint64(ynstr, yn);
FormatUint64(xnstr, xn);
emit(type, arg);
emit(" ", arg);
emit(firstnonnull(name, "M"), arg);

View file

@ -341,7 +341,7 @@ static void AppendChar(char c) {
static void AppendInt(long x) {
char ibuf[21];
AppendData(ibuf, int64toarray_radix10(x, ibuf));
AppendData(ibuf, FormatInt64(ibuf, x) - ibuf);
}
/*───────────────────────────────────────────────────────────────────────────│─╗

View file

@ -743,7 +743,7 @@ static void Render(void) {
fg = InvertXtermGreyscale(fg);
}
p = stpcpy(p, "\e[38;5;");
p += int64toarray_radix10(fg, p);
p = FormatInt64(p, fg);
*p++ = 'm';
}
w = tpenc(kCp437[c]);
@ -769,14 +769,14 @@ static void Render(void) {
}
p = stpcpy(p, " memzoom\e[0m ");
if (!pid) {
p += uint64toarray_radix10(MIN(offset / (long double)size * 100, 100), p);
p = FormatUint32(p, MIN(offset / (long double)size * 100, 100));
p = stpcpy(p, "%-");
p += uint64toarray_radix10(
MIN((offset + ((tyn * txn) << zoom)) / (long double)size * 100, 100),
p);
p = FormatUint32(
p,
MIN((offset + ((tyn * txn) << zoom)) / (long double)size * 100, 100));
p = stpcpy(p, "% ");
}
p += uint64toarray_radix10(1L << zoom, p);
p = FormatUint32(p, 1L << zoom);
p = stpcpy(p, "x\e[J");
PreventBufferbloat();
for (i = 0, n = p - buffer; i < n; i += got) {
@ -910,10 +910,10 @@ static void GetOpts(int argc, char *argv[]) {
}
if (pid) {
p = stpcpy(path, "/proc/");
p += int64toarray_radix10(pid, p);
p = FormatInt64(p, pid);
stpcpy(p, "/mem");
p = stpcpy(mapspath, "/proc/");
p += int64toarray_radix10(pid, p);
p = FormatInt64(p, pid);
stpcpy(p, "/maps");
} else {
if (optind == argc) {

View file

@ -857,8 +857,8 @@ static void OpenVideo(void) {
plm_set_video_decode_callback(plm_, OnVideo, NULL);
plm_set_audio_decode_callback(plm_, OnAudio, NULL);
plm_set_loop(plm_, false);
int64toarray_radix10((chans_ = 2), chansstr_);
int64toarray_radix10((srate_ = plm_get_samplerate(plm_)), sratestr_);
FormatInt64(chansstr_, (chans_ = 2));
FormatInt64(sratestr_, (srate_ = plm_get_samplerate(plm_)));
if (plm_get_num_audio_streams(plm_) && OpenSpeaker()) {
plm_set_audio_enabled(plm_, true, 0);
} else {