Make more fixes and improvements

This commit is contained in:
Justine Tunney 2022-04-21 13:44:59 -07:00
parent 01b25e267b
commit 1599b818d9
24 changed files with 858 additions and 538 deletions

View file

@ -21,7 +21,7 @@
#include "libc/bits/weaken.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/fmts.h"
#include "libc/fmt/fmt.internal.h"
#include "libc/fmt/internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/nomultics.internal.h"
@ -33,25 +33,6 @@
#include "libc/sysv/errfuns.h"
#include "third_party/gdtoa/gdtoa.h"
#define PUT(C) \
do { \
char Buf[1] = {C}; \
if (out(Buf, arg, 1) == -1) { \
return -1; \
} \
} while (0)
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
static void __fmt_free_dtoa(char **mem) {
if (*mem) {
if (weaken(freedtoa)) {
weaken(freedtoa)(*mem);
}
*mem = 0;
}
}
static int __fmt_atoi(const char **str) {
int i;
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
@ -129,11 +110,6 @@ static int __fmt_atoi(const char **str) {
* @vforksafe if floating point isn't used
*/
hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
union {
double d;
uint32_t u[2];
uint64_t q;
} pun;
long ld;
void *p;
unsigned u;
@ -145,13 +121,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
const char *alphabet;
int (*out)(const char *, void *, size_t);
unsigned char signbit, log2base;
int c, d, k, w, n, i1, ui, bw, bex;
char *s, *q, *se, *mem, qchar, special[8];
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
char *s, *q, qchar;
int d, w, n;
int sign, prec, flags, width, lasterr;
lasterr = errno;
out = fn ? fn : (void *)missingno;
mem = 0;
while (*format) {
if (*format != '%') {
@ -361,7 +336,6 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
}
break;
}
case 'c':
prec = 1;
flags |= FLAGS_PRECISION;
@ -369,12 +343,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = charbuf;
charbuf[0] = va_arg(va, int);
goto FormatString;
case 'm':
p = weaken(strerror) ? weaken(strerror)(lasterr) : "?";
signbit = 0;
goto FormatString;
case 'r':
// undocumented %r specifier
// used for good carriage return
@ -385,11 +357,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
p = "\r\e[K";
goto FormatString;
}
case 'q':
flags |= FLAGS_QUOTE;
/* fallthrough */
case 's':
p = va_arg(va, void *);
FormatString:
@ -397,369 +367,40 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
return -1;
}
break;
case 'n':
// nonstandard %n specifier
// used to print newlines that work in raw terminal modes
if (__nomultics) PUT('\r');
PUT('\n');
if (__nomultics) __FMT_PUT('\r');
__FMT_PUT('\n');
break;
case 'F':
case 'f':
if (!(flags & FLAGS_PRECISION)) prec = 6;
if (longdouble) {
pun.d = va_arg(va, long double);
} else {
pun.d = va_arg(va, double);
}
FormatDtoa:
case 'G':
case 'g':
case 'e':
case 'E':
case 'a':
case 'A':
if (!weaken(__fmt_dtoa)) {
p = "?";
goto FormatThatThing;
}
assert(!mem);
s = mem = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
if (decpt == 9999) {
Format9999:
bzero(special, sizeof(special));
p = q = special;
if (sgn) {
*q++ = '-';
} else if (flags & FLAGS_PLUS) {
*q++ = '+';
} else if (flags & FLAGS_SPACE) {
*q++ = ' ';
}
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
FormatThatThing:
__fmt_free_dtoa(&mem);
mem = 0;
prec = alt = 0;
prec = 0;
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
goto FormatString;
}
FormatReal:
if (sgn) sign = '-';
if (prec > 0) width -= prec;
if (width > 0) {
if (sign) --width;
if (decpt <= 0) {
--width;
if (prec > 0) --width;
} else {
if (s == se) decpt = 1;
width -= decpt;
if (prec > 0 || alt) --width;
}
}
if (width > 0 && !(flags & FLAGS_LEFT)) {
if (flags & FLAGS_ZEROPAD) {
if (sign) PUT(sign);
sign = 0;
do PUT('0');
while (--width > 0);
} else {
do PUT(' ');
while (--width > 0);
}
}
if (sign) PUT(sign);
if (decpt <= 0) {
PUT('0');
if (prec > 0 || alt) PUT('.');
while (decpt < 0) {
PUT('0');
prec--;
decpt++;
}
} else {
do {
if ((c = *s)) {
s++;
} else {
c = '0';
}
PUT(c);
} while (--decpt > 0);
if (prec > 0 || alt) PUT('.');
}
while (--prec >= 0) {
if ((c = *s)) {
s++;
} else {
c = '0';
}
PUT(c);
}
while (--width >= 0) {
PUT(' ');
}
__fmt_free_dtoa(&mem);
continue;
case 'G':
case 'g':
if (!(flags & FLAGS_PRECISION)) prec = 6;
if (longdouble) {
pun.d = va_arg(va, long double);
} else {
pun.d = va_arg(va, double);
}
if (prec < 0) prec = 0;
if (!weaken(__fmt_dtoa)) {
p = "?";
goto FormatThatThing;
}
assert(!mem);
s = mem =
weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
if (decpt == 9999) goto Format9999;
c = se - s;
prec1 = prec;
if (!prec) {
prec = c;
prec1 = c + (s[1] || alt ? 5 : 4);
}
if (decpt > -4 && decpt <= prec1) {
if (alt) {
prec -= decpt;
} else {
prec = c - decpt;
}
if (prec < 0) prec = 0;
goto FormatReal;
}
d -= 2;
if (!alt && prec > c) prec = c;
--prec;
goto FormatExpo;
case 'e':
case 'E':
if (!(flags & FLAGS_PRECISION)) prec = 6;
if (longdouble) {
pun.d = va_arg(va, long double);
} else {
pun.d = va_arg(va, double);
}
if (prec < 0) prec = 0;
if (!weaken(__fmt_dtoa)) {
p = "?";
goto FormatThatThing;
}
assert(!mem);
s = mem = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se);
if (decpt == 9999) goto Format9999;
FormatExpo:
if (sgn) sign = '-';
if ((width -= prec + 5) > 0) {
if (sign) --width;
if (prec || alt) --width;
}
if ((c = --decpt) < 0) c = -c;
while (c >= 100) {
--width;
c /= 10;
}
if (width > 0 && !(flags & FLAGS_LEFT)) {
if (flags & FLAGS_ZEROPAD) {
if (sign) PUT(sign);
sign = 0;
do PUT('0');
while (--width > 0);
} else {
do PUT(' ');
while (--width > 0);
}
}
if (sign) PUT(sign);
PUT(*s++);
if (prec || alt) PUT('.');
while (--prec >= 0) {
if ((c = *s)) {
s++;
} else {
c = '0';
}
PUT(c);
}
__fmt_free_dtoa(&mem);
PUT(d);
if (decpt < 0) {
PUT('-');
decpt = -decpt;
} else {
PUT('+');
}
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
for (;;) {
i1 = decpt / k;
PUT(i1 + '0');
if (--c <= 0) break;
decpt -= i1 * k;
decpt *= 10;
}
while (--width >= 0) {
PUT(' ');
}
continue;
case 'a':
alphabet = "0123456789abcdefpx";
goto FormatBinary;
case 'A':
alphabet = "0123456789ABCDEFPX";
FormatBinary:
if (longdouble) {
pun.d = va_arg(va, long double);
} else {
pun.d = va_arg(va, double);
}
if ((pun.u[1] & 0x7ff00000) == 0x7ff00000) {
goto FormatDtoa;
}
if (pun.u[1] & 0x80000000) {
sign = '-';
pun.u[1] &= 0x7fffffff;
}
if (pun.d) {
c = '1';
bex = (pun.u[1] >> 20) - 1023;
pun.u[1] &= 0xfffff;
if (bex == -1023) {
++bex;
if (pun.u[1]) {
do {
--bex;
pun.u[1] <<= 1;
if (pun.u[0] & 0x80000000) pun.u[1] |= 1;
pun.u[0] <<= 1;
} while (pun.u[1] < 0x100000);
} else {
while (!(pun.u[0] & 0x80000000)) {
--bex;
pun.u[0] <<= 1;
}
bex -= 21;
pun.u[1] = pun.u[0] >> 11;
pun.u[0] <<= 21;
}
}
} else {
c = '0';
bex = 0;
}
if (flags & FLAGS_PRECISION) {
if (prec > 13) prec = 13;
if (pun.d && prec < 13) {
pun.u[1] |= 0x100000;
if (prec < 5) {
ui = 1u << ((5 - prec) * 4 - 1);
if (pun.u[1] & ui) {
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
pun.u[1] += ui;
BexCheck:
if (pun.u[1] & 0x200000) {
++bex;
pun.u[1] >>= 1;
}
}
}
} else if (prec == 5) {
if (pun.u[0] & 0x80000000) {
BumpIt:
++pun.u[1];
goto BexCheck;
}
} else {
i1 = (13 - prec) * 4;
ui = 1u << (i1 - 1);
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
pun.u[0] += ui;
if (!(pun.u[0] >> i1)) goto BumpIt;
}
}
}
} else {
if ((ui = pun.u[0])) {
ui = __builtin_ctz(ui);
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
} else if ((ui = pun.u[1] & 0xfffff)) {
ui = __builtin_ctz(ui);
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
} else {
prec = 0;
}
}
bw = 1;
if (bex) {
if ((i1 = bex) < 0) i1 = -i1;
while (i1 >= 10) {
++bw;
i1 /= 10;
}
}
if (pun.u[1] & 0x80000000) {
pun.u[1] &= 0x7fffffff;
if (pun.d || sign) sign = '-';
}
if ((width -= bw + 5) > 0) {
if (sign) --width;
if (prec || alt) --width;
}
if (pun.q && prec > 0) {
width -= ROUNDUP(bsrl(pun.q) + 1, 4) >> 2;
}
if (width > 0 && !(flags & FLAGS_LEFT)) {
if (flags & FLAGS_ZEROPAD) {
if (sign) {
PUT(sign);
sign = 0;
}
do PUT('0');
while (--width > 0);
} else {
do PUT(' ');
while (--width > 0);
}
}
if (sign) PUT(sign);
PUT('0');
PUT(alphabet[17]);
PUT(c);
if (prec > 0 || alt) PUT('.');
while (prec-- > 0) {
PUT(alphabet[(pun.q >> 48) & 0xf]);
pun.q <<= 4;
}
PUT(alphabet[16]);
if (bex < 0) {
PUT('-');
bex = -bex;
} else {
PUT('+');
}
for (c = 1; 10 * c <= bex;) c *= 10;
for (;;) {
i1 = bex / c;
PUT('0' + i1);
if (!--bw) break;
bex -= i1 * c;
bex *= 10;
if (weaken(__fmt_dtoa)(out, arg, d, flags, prec, sign, width,
longdouble, qchar, signbit, alphabet,
va) == -1) {
return -1;
}
break;
case '%':
PUT('%');
__FMT_PUT('%');
break;
default:
PUT(format[-1]);
__FMT_PUT(format[-1]);
break;
}
}
assert(!mem);
return 0;
}