cosmopolitan/tool/plinko/lib/printf.c
Justine Tunney 9208c83f7a Make some systemic improvements
- add vdso dump utility
- tests now log stack usage
- rename g_ftrace to __ftrace
- make internal spinlocks go faster
- add conformant c11 atomics library
- function tracing now logs stack usage
- make function call tracing thread safe
- add -X unsecure (no ssl) mode to redbean
- munmap() has more consistent behavior now
- pacify fsync() calls on python unit tests
- make --strace flag work better in redbean
- start minimizing and documenting compiler flags
2022-05-18 16:52:36 -07:00

304 lines
8.5 KiB
C

/*-*- 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/calls/strace.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/time/clockstonanos.internal.h"
#include "tool/plinko/lib/char.h"
#include "tool/plinko/lib/plinko.h"
#include "tool/plinko/lib/print.h"
#include "tool/plinko/lib/printf.h"
static inline long GetVarInt(va_list va, signed char t) {
if (t <= 0) return va_arg(va, int);
return va_arg(va, long);
}
static int PrintStr(int fd, const char *s, int cols) {
int n, j, k = 0, i = 0;
n = strlen(s);
k += PrintIndent(fd, +cols - n);
while (i < n) k += PrintChar(fd, s[i++]);
k += PrintIndent(fd, -cols - n);
return k;
}
int Printf(const char *f, ...) {
int n;
va_list va;
va_start(va, f);
n = Vfnprintf(f, va, 1, 0);
va_end(va);
return n;
}
int Fprintf(int fd, const char *f, ...) {
int n;
va_list va;
va_start(va, f);
n = Vfnprintf(f, va, fd, 0);
va_end(va);
return n;
}
int Fnprintf(int fd, int n, const char *f, ...) {
va_list va;
va_start(va, f);
n = Vfnprintf(f, va, fd, n);
va_end(va);
return n;
}
int Vfprintf(const char *f, va_list va, int fd) {
return Vfnprintf(f, va, fd, 0);
}
int Vfnprintf(const char *f, va_list va, int fd, int n) {
enum { kPlain, kEsc, kCsi };
static int recursive;
dword t, u;
const char *s;
signed char type;
char quot, ansi, gotr, pdot, zero;
int b, c, i, x, y, si, prec, cols, sign;
gotr = false;
t = rdtsc();
--__ftrace;
--__strace;
++recursive;
for (ansi = 0;;) {
for (;;) {
if (!(c = *f++ & 0377) || c == L'%') break;
if (c >= 0300) {
for (b = 0200; c & b; b >>= 1) {
c ^= b;
}
while ((*f & 0300) == 0200) {
c <<= 6;
c |= *f++ & 0177;
}
}
switch (ansi) {
case kPlain:
if (c == 033) {
ansi = kEsc;
} else if (c != L'\n' && c != L'\r') {
n += GetMonospaceCharacterWidth(c);
} else {
n = 0;
}
break;
case kEsc:
if (c == '[') {
ansi = kCsi;
} else {
ansi = kPlain;
}
break;
case kCsi:
if (0x40 <= c && c <= 0x7e) {
ansi = kPlain;
}
break;
default:
unreachable;
}
EmitFormatByte:
PrintChar(fd, c);
}
if (!c) break;
prec = 0;
pdot = 0;
cols = 0;
quot = 0;
type = 0;
zero = 0;
sign = 1;
for (;;) {
switch ((c = *f++)) {
default:
goto EmitFormatByte;
case L'n':
PrintNewline(fd);
n = 0;
break;
case L'l':
++type;
continue;
case L'0':
case L'1':
case L'2':
case L'3':
case L'4':
case L'5':
case L'6':
case L'7':
case L'8':
case L'9':
si = pdot ? prec : cols;
si *= 10;
si += c - '0';
goto UpdateCols;
case L'*':
si = va_arg(va, int);
UpdateCols:
if (pdot) {
prec = si;
} else {
if (si < 0) {
si = -si;
sign = -1;
} else if (!si) {
zero = 1;
}
cols = si;
}
continue;
case L'-':
sign = -1;
continue;
case L'.':
pdot = 1;
continue;
case L'_':
case L',':
case L'\'':
quot = c;
continue;
case L'I':
if (depth >= 0) {
n += PrintDepth(fd, depth);
} else {
n += PrintIndent(fd, sp * 2);
}
break;
case L'J':
if (depth >= 0) {
n += PrintDepth(fd, depth - 1);
} else {
n += PrintIndent(fd, (sp - 1) * 2);
}
break;
case L'V':
y = depth >= 0 ? depth : sp;
if (y) {
n += PrintIndent(fd, (y - 1) * 2);
n += PrintChar(fd, L'');
n += PrintChar(fd, L'');
}
break;
case L'W':
y = depth >= 0 ? depth : sp;
if (y) {
n += PrintIndent(fd, (y - 1) * 2);
n += PrintChar(fd, L'');
n += PrintChar(fd, L' ');
}
break;
case L'X':
y = depth >= 0 ? depth : sp;
if (y) {
n += PrintIndent(fd, (y - 1) * 2);
n += PrintChar(fd, L'');
n += PrintChar(fd, L'');
}
break;
case L'p':
if (simpler) goto SimplePrint;
// fallthrough
case L'P':
n += PrettyPrint(fd, va_arg(va, int),
MAX(0, depth > 0 ? n - depth * 3 : n));
break;
case L'T':
PrintTree(fd, va_arg(va, int), n);
break;
case L'R':
gotr = true;
n += PrintInt(fd, ClocksToNanos(tick, t), cols * sign, quot, zero, 10,
true);
break;
case L'S':
SimplePrint:
n += Print(fd, va_arg(va, int));
break;
case L'A':
y = va_arg(va, int);
x = va_arg(va, int);
n += PrintChar(fd, L'[');
n += PrintArgs(fd, y, x, 0);
n += PrintChar(fd, L']');
break;
case L'K':
if ((b = va_arg(va, int)) < 0) {
PrintChar(fd, L'(');
for (;;) {
n += Print(fd, Car(Car(b)));
if ((b = Cdr(b)) >= 0) break;
PrintChar(fd, L' ');
}
PrintChar(fd, L')');
} else {
n += Print(fd, b);
}
break;
case L'd':
n += PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 10,
true);
break;
case L'u':
n +=
PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 10, 0);
break;
case L'b':
n += PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 2, 0);
break;
case L'o':
n += PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 8, 0);
break;
case L'x':
n +=
PrintInt(fd, GetVarInt(va, type), cols * sign, quot, zero, 16, 0);
break;
case L's':
s = va_arg(va, const char *);
if (!s) s = "NULL";
n += PrintStr(fd, s, cols * sign);
break;
case L'c':
n += PrintChar(fd, va_arg(va, int));
break;
}
break;
}
}
--recursive;
++__ftrace;
++__strace;
if (!recursive) {
u = rdtsc();
if (gotr) {
tick = u;
} else {
tick -= u >= t ? u - t : ~t + u + 1;
}
}
return n;
}