mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
parent
e26bdbec52
commit
f064183646
48 changed files with 1034 additions and 921 deletions
|
@ -1,21 +0,0 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/errno.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("abcdefghijklmnopqrstuvwxyz "
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ "
|
||||
"!@#$$%%^&*(){}%%* "
|
||||
"0123456789 "
|
||||
"%3d\n",
|
||||
argc);
|
||||
return errno;
|
||||
}
|
|
@ -58,7 +58,7 @@ int(vdprintf)(int fd, const char *fmt, va_list va) {
|
|||
struct VdprintfState df;
|
||||
df.n = 0;
|
||||
df.fd = fd;
|
||||
if (palandprintf(vdprintfputchar, &df, fmt, va) == -1) return -1;
|
||||
if (__fmt(vdprintfputchar, &df, fmt, va) == -1) return -1;
|
||||
if (vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) == -1) return -1;
|
||||
return df.n;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,6 @@ div_t div(int, int) pureconst;
|
|||
ldiv_t ldiv(long, long) pureconst;
|
||||
lldiv_t lldiv(long long, long long) pureconst;
|
||||
imaxdiv_t imaxdiv(intmax_t, intmax_t) pureconst;
|
||||
double RoundDecimalPlaces(double, double, double (*)(double));
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § conversion » optimizations ─╬─│┼
|
||||
|
|
657
libc/fmt/fmt.c
Normal file
657
libc/fmt/fmt.c
Normal file
|
@ -0,0 +1,657 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
static int __fmt_atoi(const char **str) {
|
||||
int i;
|
||||
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
||||
i *= 10;
|
||||
i += **str - '0';
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {,v}{,s{,n},{,{,x}as},f,d}printf domain-specific language.
|
||||
*
|
||||
* Type Specifiers
|
||||
*
|
||||
* - `%s` char * (thompson-pike unicode)
|
||||
* - `%ls` wchar_t * (32-bit unicode → thompson-pike unicode)
|
||||
* - `%hs` char16_t * (16-bit unicode → thompson-pike unicode)
|
||||
* - `%b` int (radix 2 binary)
|
||||
* - `%o` int (radix 8 octal)
|
||||
* - `%d` int (radix 10 decimal)
|
||||
* - `%x` int (radix 16 hexadecimal)
|
||||
* - `%X` int (radix 16 hexadecimal uppercase)
|
||||
* - `%p` pointer (48-bit hexadecimal)
|
||||
* - `%u` unsigned
|
||||
* - `%g` double (smart formatting)
|
||||
* - `%e` double (expo formatting)
|
||||
* - `%f` double (ugly formatting)
|
||||
* - `%a` double (hex formatting)
|
||||
* - `%Lg` long double
|
||||
*
|
||||
* Size Modifiers
|
||||
*
|
||||
* - `%hhd` char (8-bit)
|
||||
* - `%hd` short (16-bit)
|
||||
* - `%ld` long (64-bit)
|
||||
* - `%lu` unsigned long (64-bit)
|
||||
* - `%lx` unsigned long (64-bit hexadecimal)
|
||||
* - `%jd` intmax_t (128-bit)
|
||||
*
|
||||
* Width Modifiers
|
||||
*
|
||||
* - `%08d` fixed columns w/ zero leftpadding
|
||||
* - `%8d` fixed columns w/ space leftpadding
|
||||
* - `%*s` variable column string (thompson-pike)
|
||||
*
|
||||
* Precision Modifiers
|
||||
*
|
||||
* - `%.8s` supplied byte length (obeys nul terminator)
|
||||
* - `%.*s` supplied byte length argument (obeys nul terminator)
|
||||
* - ``%`.*s`` supplied byte length argument c escaped (ignores nul term)
|
||||
* - `%#.*s` supplied byte length argument visualized (ignores nul term)
|
||||
* - `%.*hs` supplied char16_t length argument (obeys nul terminator)
|
||||
* - `%.*ls` supplied wchar_t length argument (obeys nul terminator)
|
||||
*
|
||||
* Formatting Modifiers
|
||||
*
|
||||
* - `%,d` thousands separators
|
||||
* - `%'s` escaped c string literal
|
||||
* - ``%`c`` c escaped character
|
||||
* - ``%`'c`` c escaped character quoted
|
||||
* - ``%`s`` c escaped string
|
||||
* - ``%`'s`` c escaped string quoted
|
||||
* - ``%`s`` escaped double quoted c string literal
|
||||
* - ``%`c`` escaped double quoted c character literal
|
||||
* - `%+d` plus leftpad if positive (aligns w/ negatives)
|
||||
* - `% d` space leftpad if positive (aligns w/ negatives)
|
||||
* - `%#s` datum (radix 256 null-terminated ibm cp437)
|
||||
* - `%#x` int (radix 16 hexadecimal w/ 0x prefix if not zero)
|
||||
*
|
||||
* @note implementation detail of printf(), snprintf(), etc.
|
||||
* @see printf() for wordier documentation
|
||||
* @note netlib.org is so helpful
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
union {
|
||||
double d;
|
||||
unsigned int u[2];
|
||||
} pun;
|
||||
void *p;
|
||||
char qchar;
|
||||
char *s, *se;
|
||||
bool longdouble;
|
||||
long double ldbl;
|
||||
wchar_t charbuf[1];
|
||||
const char *alphabet;
|
||||
int (*out)(long, void *);
|
||||
unsigned char signbit, log2base;
|
||||
int c, d, k, w, i1, ui, bw, bex;
|
||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||
|
||||
lasterr = errno;
|
||||
out = fn ? fn : (void *)missingno;
|
||||
|
||||
while (*format) {
|
||||
/* %[flags][width][.prec][length] */
|
||||
if (*format != '%') {
|
||||
/* no */
|
||||
if (out(*format, arg) == -1) return -1;
|
||||
format++;
|
||||
continue;
|
||||
} else {
|
||||
/* yes, evaluate it */
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate flags */
|
||||
sign = 0;
|
||||
flags = 0;
|
||||
getflag:
|
||||
switch (*format++) {
|
||||
case '0':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
goto getflag;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
goto getflag;
|
||||
case '+':
|
||||
sign = '+';
|
||||
flags |= FLAGS_PLUS;
|
||||
goto getflag;
|
||||
case ' ':
|
||||
sign = ' ';
|
||||
flags |= FLAGS_SPACE;
|
||||
goto getflag;
|
||||
case '#':
|
||||
flags |= FLAGS_HASH;
|
||||
goto getflag;
|
||||
case ',':
|
||||
flags |= FLAGS_GROUPING;
|
||||
goto getflag;
|
||||
case '`':
|
||||
flags |= FLAGS_REPR;
|
||||
/* fallthrough */
|
||||
case '\'':
|
||||
flags |= FLAGS_QUOTE;
|
||||
goto getflag;
|
||||
default:
|
||||
format--;
|
||||
break;
|
||||
}
|
||||
|
||||
/* evaluate width field */
|
||||
width = 0;
|
||||
if (isdigit(*format)) {
|
||||
width = __fmt_atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; /* reverse padding */
|
||||
width = -w;
|
||||
sign = '-';
|
||||
} else {
|
||||
width = w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate prec field */
|
||||
prec = 0;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (isdigit(*format)) {
|
||||
prec = __fmt_atoi(&format);
|
||||
} else if (*format == '*') {
|
||||
prec = va_arg(va, int);
|
||||
format++;
|
||||
}
|
||||
}
|
||||
if (prec < 0) {
|
||||
prec = 0;
|
||||
}
|
||||
|
||||
/* evaluate length field */
|
||||
signbit = 31;
|
||||
longdouble = false;
|
||||
switch (*format) {
|
||||
case 'j': /* intmax_t */
|
||||
format++;
|
||||
signbit = sizeof(intmax_t) * 8 - 1;
|
||||
break;
|
||||
case 'l':
|
||||
if (format[1] == 'f' || format[1] == 'F') {
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
if (format[1] == 'l') format++;
|
||||
/* fallthrough */
|
||||
case 't': /* ptrdiff_t */
|
||||
case 'z': /* size_t */
|
||||
case 'Z': /* size_t */
|
||||
format++;
|
||||
signbit = 63;
|
||||
break;
|
||||
case 'L': /* long double */
|
||||
format++;
|
||||
longdouble = true;
|
||||
break;
|
||||
case 'h':
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
format++;
|
||||
signbit = 7;
|
||||
} else {
|
||||
signbit = 15;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* evaluate specifier */
|
||||
qchar = '"';
|
||||
log2base = 0;
|
||||
alphabet = "0123456789abcdef";
|
||||
switch ((d = *format++)) {
|
||||
case 'p':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
width = POINTER_XDIGITS;
|
||||
log2base = 4;
|
||||
signbit = 47;
|
||||
goto FormatNumber;
|
||||
case 'X':
|
||||
alphabet = "0123456789ABCDEF";
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
log2base = 4;
|
||||
goto FormatNumber;
|
||||
case 'b':
|
||||
log2base = 1;
|
||||
goto FormatNumber;
|
||||
case 'o':
|
||||
log2base = 3;
|
||||
goto FormatNumber;
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= FLAGS_ISSIGNED;
|
||||
/* fallthrough */
|
||||
case 'u': {
|
||||
flags &= ~FLAGS_HASH; /* no hash for dec format */
|
||||
FormatNumber:
|
||||
if (__fmt_ntoa(out, arg, va, signbit, log2base, prec, width, flags,
|
||||
alphabet) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c':
|
||||
prec = 1;
|
||||
flags |= FLAGS_PRECISION;
|
||||
qchar = '\'';
|
||||
p = charbuf;
|
||||
charbuf[0] = va_arg(va, int);
|
||||
goto FormatString;
|
||||
|
||||
case 'm':
|
||||
p = weaken(strerror) ? weaken(strerror)(lasterr) : "?";
|
||||
signbit = 0;
|
||||
goto FormatString;
|
||||
|
||||
case 'r':
|
||||
flags |= FLAGS_REPR;
|
||||
/* fallthrough */
|
||||
|
||||
case 'q':
|
||||
flags |= FLAGS_QUOTE;
|
||||
/* fallthrough */
|
||||
|
||||
case 's':
|
||||
p = va_arg(va, void *);
|
||||
FormatString:
|
||||
if (__fmt_stoa(out, arg, p, flags, prec, width, signbit, qchar) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
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:
|
||||
if (!weaken(__fmt_dtoa)) {
|
||||
p = "nan";
|
||||
goto FormatString;
|
||||
}
|
||||
s = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
prec = alt = 0;
|
||||
flags &= ~FLAGS_PRECISION;
|
||||
if (*s == 'N') {
|
||||
p = s;
|
||||
goto FormatString;
|
||||
}
|
||||
decpt = strlen(s);
|
||||
}
|
||||
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) out(sign, arg);
|
||||
sign = 0;
|
||||
do out('0', arg);
|
||||
while (--width > 0);
|
||||
} else
|
||||
do out(' ', arg);
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) out(sign, arg);
|
||||
if (decpt <= 0) {
|
||||
out('0', arg);
|
||||
if (prec > 0 || alt) out('.', arg);
|
||||
while (decpt < 0) {
|
||||
out('0', arg);
|
||||
prec--;
|
||||
decpt++;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
out(c, arg);
|
||||
} while (--decpt > 0);
|
||||
if (prec > 0 || alt) out('.', arg);
|
||||
}
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
out(c, arg);
|
||||
}
|
||||
while (--width >= 0) {
|
||||
out(' ', arg);
|
||||
}
|
||||
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 = "nan";
|
||||
goto FormatString;
|
||||
}
|
||||
s = 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);
|
||||
/* %.0g gives 10 rather than 1e1 */
|
||||
}
|
||||
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 = "nan";
|
||||
goto FormatString;
|
||||
}
|
||||
s = 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) out(sign, arg);
|
||||
sign = 0;
|
||||
do out('0', arg);
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do out(' ', arg);
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) out(sign, arg);
|
||||
out(*s++, arg);
|
||||
if (prec || alt) out('.', arg);
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
out(c, arg);
|
||||
}
|
||||
out(d, arg);
|
||||
if (decpt < 0) {
|
||||
out('-', arg);
|
||||
decpt = -decpt;
|
||||
} else {
|
||||
out('+', arg);
|
||||
}
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) {
|
||||
}
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
out(i1 + '0', arg);
|
||||
if (--c <= 0) break;
|
||||
decpt -= i1 * k;
|
||||
decpt *= 10;
|
||||
}
|
||||
while (--width >= 0) {
|
||||
out(' ', arg);
|
||||
}
|
||||
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.d) {
|
||||
c = '1';
|
||||
if (pun.u[1] & 0x80000000) {
|
||||
sign = '-';
|
||||
pun.u[1] &= 0x7fffffff;
|
||||
}
|
||||
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 = 1 << ((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 = 1 << (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])) {
|
||||
for (prec = 6; (ui = (ui << 4) & 0xffffffff); ++prec) {
|
||||
}
|
||||
} else {
|
||||
for (prec = 0, ui = pun.u[1] & 0xfffff; ui;
|
||||
++prec, ui = (ui << 4) & 0xfffff) {
|
||||
}
|
||||
}
|
||||
}
|
||||
bw = 1;
|
||||
if (bex) {
|
||||
if ((i1 = bex) < 0) i1 = -i1;
|
||||
while (i1 >= 10) {
|
||||
++bw;
|
||||
i1 /= 10;
|
||||
}
|
||||
}
|
||||
if ((sgn = 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 (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if (flags & FLAGS_ZEROPAD) {
|
||||
if (sign) {
|
||||
out(sign, arg);
|
||||
sign = 0;
|
||||
}
|
||||
do out('0', arg);
|
||||
while (--width > 0);
|
||||
} else {
|
||||
do out(' ', arg);
|
||||
while (--width > 0);
|
||||
}
|
||||
}
|
||||
if (sign) out(sign, arg);
|
||||
out('0', arg);
|
||||
out(alphabet[17], arg);
|
||||
out(c, arg);
|
||||
if (prec > 0 || alt) out('.', arg);
|
||||
if (prec > 0) {
|
||||
if ((i1 = prec) > 5) i1 = 5;
|
||||
prec -= i1;
|
||||
do {
|
||||
out(alphabet[(pun.u[1] >> 16) & 0xf], arg);
|
||||
pun.u[1] <<= 4;
|
||||
} while (--i1 > 0);
|
||||
while (prec > 0) {
|
||||
--prec;
|
||||
out(alphabet[(pun.u[0] >> 28) & 0xf], arg);
|
||||
pun.u[0] <<= 4;
|
||||
}
|
||||
}
|
||||
out(alphabet[16], arg);
|
||||
if (bex < 0) {
|
||||
out('-', arg);
|
||||
bex = -bex;
|
||||
} else {
|
||||
out('+', arg);
|
||||
}
|
||||
for (c = 1; 10 * c <= bex; c *= 10) {
|
||||
}
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
out('0' + i1, arg);
|
||||
if (!--bw) break;
|
||||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
}
|
||||
continue;
|
||||
|
||||
case '%':
|
||||
if (out('%', arg) == -1) return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (out(format[-1], arg) == -1) return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -27,7 +27,7 @@ int vsscanf(const char *, const char *, va_list);
|
|||
int vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
|
||||
va_list);
|
||||
int strerror_r(int, char *, size_t) nothrow nocallback;
|
||||
int palandprintf(void *, void *, const char *, va_list) hidden;
|
||||
int __fmt(void *, void *, const char *, va_list) hidden;
|
||||
char *itoa(int, char *, int) compatfn;
|
||||
char *fcvt(double, int, int *, int *);
|
||||
char *ecvt(double, int, int *, int *);
|
||||
|
|
20
libc/fmt/fmts.h
Normal file
20
libc/fmt/fmts.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_FMTS_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_FMTS_H_
|
||||
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 144
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int __fmt_pad(int (*)(long, void *), void *, unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(long, void *), void *, void *, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char,
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(long, void *), void *, va_list, unsigned char,
|
||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||
const char *) hidden;
|
||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_FMTS_H_ */
|
16
libc/fmt/internal.h
Normal file
16
libc/fmt/internal.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_INTERNAL_H_
|
||||
|
||||
#define FLAGS_ZEROPAD 0x01
|
||||
#define FLAGS_LEFT 0x02
|
||||
#define FLAGS_PLUS 0x04
|
||||
#define FLAGS_SPACE 0x08
|
||||
#define FLAGS_HASH 0x10
|
||||
#define FLAGS_PRECISION 0x20
|
||||
#define FLAGS_ISSIGNED 0x40
|
||||
#define FLAGS_NOQUOTE 0x80
|
||||
#define FLAGS_QUOTE FLAGS_SPACE
|
||||
#define FLAGS_GROUPING FLAGS_NOQUOTE
|
||||
#define FLAGS_REPR FLAGS_PLUS
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_INTERNAL_H_ */
|
|
@ -19,13 +19,12 @@
|
|||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
|
||||
compatfn char *itoa(int value, char *str, int radix) {
|
||||
(sprintf)(
|
||||
str,
|
||||
VEIL("r",
|
||||
radix == 16 ? "%x" : radix == 8 ? "%d" : radix == 2 ? "%b" : "%d"),
|
||||
value);
|
||||
(sprintf)(str,
|
||||
VEIL("r", radix == 16 ? "%x"
|
||||
: radix == 8 ? "%d"
|
||||
: radix == 2 ? "%b"
|
||||
: "%d"),
|
||||
value);
|
||||
return str;
|
||||
}
|
||||
|
|
174
libc/fmt/ntoa.c
Normal file
174
libc/fmt/ntoa.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
|
||||
#define BUFFER_SIZE 144
|
||||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||
unsigned len, bool negative, unsigned log2base,
|
||||
unsigned prec, unsigned width,
|
||||
unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
idx = 0;
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) &&
|
||||
(negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
/* handle hash */
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len &&
|
||||
((len == prec) || (len == width)) && buf[len - 1] == '0') {
|
||||
len--;
|
||||
if (len && (log2base == 4 || log2base == 1) && buf[len - 1] == '0') {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if (log2base == 4 && len < BUFFER_SIZE) {
|
||||
buf[len++] = 'x';
|
||||
} else if (log2base == 1 && len < BUFFER_SIZE) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; /* ignore the space if the '+' exists */
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* pad spaces up to given width */
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
if (len < width) {
|
||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (i = 0U; i < len; i++) {
|
||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (idx < width) {
|
||||
if (__fmt_pad(out, arg, width - idx) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned flags, const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
len = 0;
|
||||
if (!value) flags &= ~FLAGS_HASH;
|
||||
if (value || !(flags & FLAGS_PRECISION)) {
|
||||
count = 0;
|
||||
do {
|
||||
assert(len < BUFFER_SIZE);
|
||||
if (!log2base) {
|
||||
value = __udivmodti4(value, 10, &remainder);
|
||||
digit = remainder;
|
||||
} else {
|
||||
digit = value;
|
||||
digit &= (1u << log2base) - 1;
|
||||
value >>= log2base;
|
||||
}
|
||||
if ((flags & FLAGS_GROUPING) && count == 3) {
|
||||
buf[len++] = ',';
|
||||
count = 1;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
buf[len++] = alphabet[digit];
|
||||
} while (value);
|
||||
}
|
||||
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
|
||||
flags);
|
||||
}
|
||||
|
||||
int __fmt_ntoa(int out(long, void *), void *arg, va_list va,
|
||||
unsigned char signbit, unsigned long log2base,
|
||||
unsigned long prec, unsigned long width, unsigned char flags,
|
||||
const char *lang) {
|
||||
bool neg;
|
||||
uintmax_t value, sign;
|
||||
|
||||
/* ignore '0' flag when prec is given */
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
/* no plus / space flag for u, x, X, o, b */
|
||||
if (!(flags & FLAGS_ISSIGNED)) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
if (signbit > 63) {
|
||||
value = va_arg(va, uint128_t);
|
||||
} else {
|
||||
value = va_arg(va, uint64_t);
|
||||
}
|
||||
|
||||
neg = 0;
|
||||
sign = 1;
|
||||
sign <<= signbit;
|
||||
value &= sign | (sign - 1);
|
||||
if (flags & FLAGS_ISSIGNED) {
|
||||
if (value != sign) {
|
||||
if (value & sign) {
|
||||
value = ~value + 1;
|
||||
value &= sign | (sign - 1);
|
||||
neg = 1;
|
||||
}
|
||||
value &= sign - 1;
|
||||
} else {
|
||||
neg = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return __fmt_ntoa2(out, arg, value, neg, log2base, prec, width, flags, lang);
|
||||
}
|
|
@ -16,9 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
||||
int spacepad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int __fmt_pad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
||||
return rc;
|
|
@ -1,48 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
│ @author (c) Marco Paland (info@paland.com) │
|
||||
│ 2014-2019, PALANDesign Hannover, Germany │
|
||||
│ │
|
||||
│ @license The MIT License (MIT) │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
|
||||
│ of this software and associated documentation files (the "Software"), to deal│
|
||||
│ in the Software without restriction, including without limitation the rights │
|
||||
│ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell │
|
||||
│ copies of the Software, and to permit persons to whom the Software is │
|
||||
│ furnished to do so, subject to the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be included in │
|
||||
│ all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │
|
||||
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │
|
||||
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │
|
||||
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │
|
||||
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,│
|
||||
│ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN │
|
||||
│ THE SOFTWARE. │
|
||||
└─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Paland Printf (MIT License)\\n\
|
||||
Copyright 2014-2019 Marco Paland\\n\
|
||||
PALANDesign Hannover, Germany\\n\
|
||||
info@paland.com\"");
|
||||
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define FLAGS_ZEROPAD (1U << 0U)
|
||||
#define FLAGS_LEFT (1U << 1U)
|
||||
#define FLAGS_PLUS (1U << 2U)
|
||||
#define FLAGS_SPACE (1U << 3U)
|
||||
#define FLAGS_HASH (1U << 4U)
|
||||
#define FLAGS_PRECISION (1U << 5U)
|
||||
#define FLAGS_ISSIGNED (1U << 6U)
|
||||
#define FLAGS_NOQUOTE (1U << 7U)
|
||||
#define FLAGS_QUOTE FLAGS_SPACE
|
||||
#define FLAGS_GROUPING FLAGS_NOQUOTE
|
||||
#define FLAGS_REPR FLAGS_PLUS
|
|
@ -1,170 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
│ @author (c) Marco Paland (info@paland.com) │
|
||||
│ 2014-2019, PALANDesign Hannover, Germany │
|
||||
│ │
|
||||
│ @license The MIT License (MIT) │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
|
||||
│ of this software and associated documentation files (the "Software"), to deal│
|
||||
│ in the Software without restriction, including without limitation the rights │
|
||||
│ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell │
|
||||
│ copies of the Software, and to permit persons to whom the Software is │
|
||||
│ furnished to do so, subject to the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be included in │
|
||||
│ all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │
|
||||
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │
|
||||
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │
|
||||
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │
|
||||
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,│
|
||||
│ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN │
|
||||
│ THE SOFTWARE. │
|
||||
│ │
|
||||
│ @brief Tiny printf, sprintf and (v)snprintf implementation, optimized for │
|
||||
│ embedded systems with a very limited resources. These routines are │
|
||||
│ thread safe and reentrant! Use this instead of the bloated │
|
||||
│ standard/newlib printf cause these use malloc for printf (and may not │
|
||||
│ be thread safe). │
|
||||
└─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/paland.inc"
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
#include "libc/math.h"
|
||||
|
||||
/**
|
||||
* Formats floating point number.
|
||||
*
|
||||
* @see xdtoa() for higher precision at the cost of bloat
|
||||
* @see palandprintf() which is intended caller
|
||||
*/
|
||||
int ftoa(int out(long, void *), void *arg, long double value, int prec,
|
||||
unsigned long width, unsigned long flags) {
|
||||
long whole, frac;
|
||||
long double tmp, diff;
|
||||
unsigned i, len, count, idx;
|
||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||
|
||||
len = 0;
|
||||
diff = 0;
|
||||
|
||||
if (isnan(value)) {
|
||||
buf[0] = 'n';
|
||||
buf[1] = 'a';
|
||||
buf[2] = 'n';
|
||||
buf[3] = '\0';
|
||||
len += 3;
|
||||
} else if (isinf(value) || (value && ilogbl(fabsl(value)) > 63)) {
|
||||
buf[0] = 'f';
|
||||
buf[1] = 'n';
|
||||
buf[2] = 'i';
|
||||
buf[3] = '\0';
|
||||
len += 3;
|
||||
} else {
|
||||
|
||||
/* set default precision to 6, if not set explicitly */
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
prec = 6;
|
||||
}
|
||||
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 14) {
|
||||
buf[len++] = '0';
|
||||
prec--;
|
||||
}
|
||||
|
||||
whole = truncl(fabsl(value));
|
||||
tmp = (fabsl(value) - whole) * exp10l(prec);
|
||||
frac = tmp;
|
||||
diff = tmp - frac;
|
||||
|
||||
if (diff > .5) {
|
||||
++frac; /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
|
||||
if (frac >= exp10l(prec)) {
|
||||
frac = 0;
|
||||
++whole;
|
||||
}
|
||||
} else if (diff < .5) {
|
||||
} else if (!frac || (frac & 1)) {
|
||||
++frac; /* if halfway, round up if odd OR if last digit is 0 */
|
||||
}
|
||||
|
||||
if (!prec) {
|
||||
diff = fabsl(value) - whole;
|
||||
if ((!(diff < .5) || (diff > .5)) && (whole & 1)) {
|
||||
/* exactly .5 and ODD, then round up */
|
||||
/* 1.5 -> 2, but 2.5 -> 2 */
|
||||
++whole;
|
||||
}
|
||||
} else {
|
||||
count = prec;
|
||||
/* now do fractional part, as an unsigned number */
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
--count;
|
||||
buf[len++] = 48 + (frac % 10);
|
||||
if (!(frac /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* add extra 0s */
|
||||
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
/* add decimal */
|
||||
buf[len++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
/* do whole part, number is reversed */
|
||||
while (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
buf[len++] = (char)(48 + (whole % 10));
|
||||
if (!(whole /= 10)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
|
||||
if (width && (signbit(value) || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_FTOA_BUFFER_SIZE) {
|
||||
if (signbit(value)) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; /* ignore the space if the '+' exists */
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* pad spaces up to given width */
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
if (len < width) {
|
||||
if (spacepad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (idx = i = 0; i < len; i++) {
|
||||
if (out(buf[len - i - 1U], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (len < width) {
|
||||
if (spacepad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
│ @author (c) Marco Paland (info@paland.com) │
|
||||
│ 2014-2019, PALANDesign Hannover, Germany │
|
||||
│ │
|
||||
│ @license The MIT License (MIT) │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
|
||||
│ of this software and associated documentation files (the "Software"), to deal│
|
||||
│ in the Software without restriction, including without limitation the rights │
|
||||
│ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell │
|
||||
│ copies of the Software, and to permit persons to whom the Software is │
|
||||
│ furnished to do so, subject to the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be included in │
|
||||
│ all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │
|
||||
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │
|
||||
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │
|
||||
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │
|
||||
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,│
|
||||
│ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN │
|
||||
│ THE SOFTWARE. │
|
||||
└─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/paland.inc"
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int ntoaformat(int out(long, void *), void *arg, char *buf, unsigned len,
|
||||
bool negative, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
idx = 0;
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
if (width && (flags & FLAGS_ZEROPAD) &&
|
||||
(negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while ((flags & FLAGS_ZEROPAD) && (len < width) &&
|
||||
(len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
/* handle hash */
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (!(flags & FLAGS_PRECISION) && len &&
|
||||
((len == prec) || (len == width)) && buf[len - 1] == '0') {
|
||||
len--;
|
||||
if (len && (log2base == 4 || log2base == 1) && buf[len - 1] == '0') {
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if (log2base == 4 && len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = 'x';
|
||||
} else if (log2base == 1 && len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = 'b';
|
||||
}
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
|
||||
if (len < PRINTF_NTOA_BUFFER_SIZE) {
|
||||
if (negative) {
|
||||
buf[len++] = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
buf[len++] = '+'; /* ignore the space if the '+' exists */
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* pad spaces up to given width */
|
||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||
if (len < width) {
|
||||
if (spacepad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (i = 0U; i < len; i++) {
|
||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (idx < width) {
|
||||
if (spacepad(out, arg, width - idx) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width, unsigned flags,
|
||||
const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||
len = 0;
|
||||
if (!value) flags &= ~FLAGS_HASH;
|
||||
if (value || !(flags & FLAGS_PRECISION)) {
|
||||
count = 0;
|
||||
do {
|
||||
assert(len < PRINTF_NTOA_BUFFER_SIZE);
|
||||
if (!log2base) {
|
||||
value = __udivmodti4(value, 10, &remainder);
|
||||
digit = remainder;
|
||||
} else {
|
||||
digit = value;
|
||||
digit &= (1u << log2base) - 1;
|
||||
value >>= log2base;
|
||||
}
|
||||
if ((flags & FLAGS_GROUPING) && count == 3) {
|
||||
buf[len++] = ',';
|
||||
count = 1;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
buf[len++] = alphabet[digit];
|
||||
} while (value);
|
||||
}
|
||||
return ntoaformat(out, arg, buf, len, neg, log2base, prec, width, flags);
|
||||
}
|
||||
|
||||
int ntoa(int out(long, void *), void *arg, va_list va, unsigned char signbit,
|
||||
unsigned long log2base, unsigned long prec, unsigned long width,
|
||||
unsigned char flags, const char *lang) {
|
||||
bool neg;
|
||||
uintmax_t value, sign;
|
||||
|
||||
/* ignore '0' flag when prec is given */
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
/* no plus / space flag for u, x, X, o, b */
|
||||
if (!(flags & FLAGS_ISSIGNED)) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
if (signbit > 63) {
|
||||
value = va_arg(va, uint128_t);
|
||||
} else {
|
||||
value = va_arg(va, uint64_t);
|
||||
}
|
||||
|
||||
neg = 0;
|
||||
sign = 1;
|
||||
sign <<= signbit;
|
||||
value &= sign | (sign - 1);
|
||||
if (flags & FLAGS_ISSIGNED) {
|
||||
if (value != sign) {
|
||||
if (value & sign) {
|
||||
value = ~value + 1;
|
||||
value &= sign | (sign - 1);
|
||||
neg = 1;
|
||||
}
|
||||
value &= sign - 1;
|
||||
} else {
|
||||
neg = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ntoa2(out, arg, value, neg, log2base, prec, width, flags, lang);
|
||||
}
|
|
@ -1,337 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╚══════════════════════════════════════════════════════════════════════════════╝
|
||||
│ @author (c) Marco Paland (info@paland.com) │
|
||||
│ 2014-2019, PALANDesign Hannover, Germany │
|
||||
│ │
|
||||
│ @license The MIT License (MIT) │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
|
||||
│ of this software and associated documentation files (the "Software"), to deal│
|
||||
│ in the Software without restriction, including without limitation the rights │
|
||||
│ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell │
|
||||
│ copies of the Software, and to permit persons to whom the Software is │
|
||||
│ furnished to do so, subject to the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be included in │
|
||||
│ all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │
|
||||
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │
|
||||
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │
|
||||
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │
|
||||
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,│
|
||||
│ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN │
|
||||
│ THE SOFTWARE. │
|
||||
│ │
|
||||
│ @brief Tiny printf, sprintf and (v)snprintf implementation, optimized for │
|
||||
│ embedded systems with a very limited resources. These routines are │
|
||||
│ thread safe and reentrant! Use this instead of the bloated │
|
||||
│ standard/newlib printf cause these use malloc for printf (and may not │
|
||||
│ be thread safe). │
|
||||
│ │
|
||||
│ @brief Modified by Justine Tunney to support three different types of │
|
||||
│ UNICODE, 128-bit arithmetic, binary conversion, string escaping, │
|
||||
│ AVX2 character scanning, and possibly a tinier footprint too, so │
|
||||
│ long as extremely wild linker hacks aren't considered cheating. │
|
||||
└─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/paland.inc"
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static int ppatoi(const char **str) {
|
||||
int i;
|
||||
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
||||
i *= 10;
|
||||
i += **str - '0';
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {,v}{,s{,n},{,{,x}as},f,d}printf domain-specific language.
|
||||
*
|
||||
* Type Specifiers
|
||||
*
|
||||
* - `%s` char * (thompson-pike unicode)
|
||||
* - `%ls` wchar_t * (32-bit unicode → thompson-pike unicode)
|
||||
* - `%hs` char16_t * (16-bit unicode → thompson-pike unicode)
|
||||
* - `%b` int (radix 2 binary)
|
||||
* - `%o` int (radix 8 octal)
|
||||
* - `%d` int (radix 10 decimal)
|
||||
* - `%x` int (radix 16 hexadecimal)
|
||||
* - `%X` int (radix 16 hexadecimal uppercase)
|
||||
* - `%u` unsigned
|
||||
* - `%f` double
|
||||
* - `%Lf` long double
|
||||
* - `%p` pointer (48-bit hexadecimal)
|
||||
*
|
||||
* Size Modifiers
|
||||
*
|
||||
* - `%hhd` char (8-bit)
|
||||
* - `%hd` short (16-bit)
|
||||
* - `%ld` long (64-bit)
|
||||
* - `%lu` unsigned long (64-bit)
|
||||
* - `%lx` unsigned long (64-bit hexadecimal)
|
||||
* - `%jd` intmax_t (128-bit)
|
||||
*
|
||||
* Width Modifiers
|
||||
*
|
||||
* - `%08d` fixed columns w/ zero leftpadding
|
||||
* - `%8d` fixed columns w/ space leftpadding
|
||||
* - `%*s` variable column string (thompson-pike)
|
||||
*
|
||||
* Precision Modifiers
|
||||
*
|
||||
* - `%.8s` supplied byte length (obeys nul terminator)
|
||||
* - `%.*s` supplied byte length argument (obeys nul terminator)
|
||||
* - ``%`.*s`` supplied byte length argument c escaped (ignores nul term)
|
||||
* - `%#.*s` supplied byte length argument visualized (ignores nul term)
|
||||
* - `%.*hs` supplied char16_t length argument (obeys nul terminator)
|
||||
* - `%.*ls` supplied wchar_t length argument (obeys nul terminator)
|
||||
*
|
||||
* Formatting Modifiers
|
||||
*
|
||||
* - `%,d` thousands separators
|
||||
* - `%'s` escaped c string literal
|
||||
* - ``%`c`` c escaped character
|
||||
* - ``%`'c`` c escaped character quoted
|
||||
* - ``%`s`` c escaped string
|
||||
* - ``%`'s`` c escaped string quoted
|
||||
* - ``%`s`` escaped double quoted c string literal
|
||||
* - ``%`c`` escaped double quoted c character literal
|
||||
* - `%+d` plus leftpad if positive (aligns w/ negatives)
|
||||
* - `% d` space leftpad if positive (aligns w/ negatives)
|
||||
* - `%#s` datum (radix 256 null-terminated ibm cp437)
|
||||
* - `%#x` int (radix 16 hexadecimal w/ 0x prefix if not zero)
|
||||
*
|
||||
* @note implementation detail of printf(), snprintf(), etc.
|
||||
* @see printf() for wordier documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
|
||||
void *p;
|
||||
char qchar;
|
||||
bool longdouble;
|
||||
long double ldbl;
|
||||
wchar_t charbuf[1];
|
||||
const char *alphabet;
|
||||
int (*out)(long, void *);
|
||||
unsigned char signbit, log2base;
|
||||
int w, flags, width, lasterr, precision;
|
||||
|
||||
lasterr = errno;
|
||||
out = fn ? fn : (void *)missingno;
|
||||
|
||||
while (*format) {
|
||||
/* %[flags][width][.precision][length] */
|
||||
if (*format != '%') {
|
||||
/* no */
|
||||
if (out(*format, arg) == -1) return -1;
|
||||
format++;
|
||||
continue;
|
||||
} else {
|
||||
/* yes, evaluate it */
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate flags */
|
||||
flags = 0;
|
||||
getflag:
|
||||
switch (*format++) {
|
||||
case '0':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
goto getflag;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
goto getflag;
|
||||
case '+':
|
||||
flags |= FLAGS_PLUS;
|
||||
goto getflag;
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
goto getflag;
|
||||
case '#':
|
||||
flags |= FLAGS_HASH;
|
||||
goto getflag;
|
||||
case ',':
|
||||
flags |= FLAGS_GROUPING;
|
||||
goto getflag;
|
||||
case '`':
|
||||
flags |= FLAGS_REPR;
|
||||
/* fallthrough */
|
||||
case '\'':
|
||||
flags |= FLAGS_QUOTE;
|
||||
goto getflag;
|
||||
default:
|
||||
format--;
|
||||
break;
|
||||
}
|
||||
|
||||
/* evaluate width field */
|
||||
width = 0;
|
||||
if (isdigit(*format)) {
|
||||
width = ppatoi(&format);
|
||||
} else if (*format == '*') {
|
||||
w = va_arg(va, int);
|
||||
if (w < 0) {
|
||||
flags |= FLAGS_LEFT; /* reverse padding */
|
||||
width = -w;
|
||||
} else {
|
||||
width = w;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate precision field */
|
||||
precision = 0;
|
||||
if (*format == '.') {
|
||||
flags |= FLAGS_PRECISION;
|
||||
format++;
|
||||
if (isdigit(*format)) {
|
||||
precision = ppatoi(&format);
|
||||
} else if (*format == '*') {
|
||||
precision = va_arg(va, int);
|
||||
format++;
|
||||
}
|
||||
}
|
||||
if (precision < 0) {
|
||||
precision = 0;
|
||||
}
|
||||
|
||||
/* evaluate length field */
|
||||
signbit = 31;
|
||||
longdouble = false;
|
||||
switch (*format) {
|
||||
case 'j': /* intmax_t */
|
||||
format++;
|
||||
signbit = sizeof(intmax_t) * 8 - 1;
|
||||
break;
|
||||
case 'l':
|
||||
if (format[1] == 'f' || format[1] == 'F') {
|
||||
format++;
|
||||
break;
|
||||
}
|
||||
if (format[1] == 'l') format++;
|
||||
/* fallthrough */
|
||||
case 't': /* ptrdiff_t */
|
||||
case 'z': /* size_t */
|
||||
case 'Z': /* size_t */
|
||||
format++;
|
||||
signbit = 63;
|
||||
break;
|
||||
case 'L': /* long double */
|
||||
format++;
|
||||
longdouble = true;
|
||||
break;
|
||||
case 'h':
|
||||
format++;
|
||||
if (*format == 'h') {
|
||||
format++;
|
||||
signbit = 7;
|
||||
} else {
|
||||
signbit = 15;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* evaluate specifier */
|
||||
alphabet = "0123456789abcdef";
|
||||
log2base = 0;
|
||||
qchar = '"';
|
||||
switch (*format++) {
|
||||
case 'p':
|
||||
flags |= FLAGS_ZEROPAD;
|
||||
width = POINTER_XDIGITS;
|
||||
log2base = 4;
|
||||
signbit = 47;
|
||||
goto DoNumber;
|
||||
case 'X':
|
||||
alphabet = "0123456789ABCDEF";
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
log2base = 4;
|
||||
goto DoNumber;
|
||||
case 'b':
|
||||
log2base = 1;
|
||||
goto DoNumber;
|
||||
case 'o':
|
||||
log2base = 3;
|
||||
goto DoNumber;
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= FLAGS_ISSIGNED;
|
||||
/* fallthrough */
|
||||
case 'u': {
|
||||
flags &= ~FLAGS_HASH; /* no hash for dec format */
|
||||
DoNumber:
|
||||
if (ntoa(out, arg, va, signbit, log2base, precision, width, flags,
|
||||
alphabet) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
if (longdouble) {
|
||||
ldbl = va_arg(va, long double);
|
||||
} else {
|
||||
ldbl = va_arg(va, double);
|
||||
}
|
||||
if (ftoa(out, arg, ldbl, precision, width, flags) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
precision = 1;
|
||||
flags |= FLAGS_PRECISION;
|
||||
qchar = '\'';
|
||||
p = charbuf;
|
||||
charbuf[0] = va_arg(va, int); /* assume little endian */
|
||||
goto showstr;
|
||||
|
||||
case 'm':
|
||||
p = weaken(strerror) ? weaken(strerror)(lasterr) : "?";
|
||||
signbit = 0;
|
||||
goto showstr;
|
||||
|
||||
case 'r':
|
||||
flags |= FLAGS_REPR;
|
||||
/* fallthrough */
|
||||
|
||||
case 'q':
|
||||
flags |= FLAGS_QUOTE;
|
||||
/* fallthrough */
|
||||
|
||||
case 's':
|
||||
p = va_arg(va, void *);
|
||||
showstr:
|
||||
if (stoa(out, arg, p, flags, precision, width, signbit, qchar) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
if (out('%', arg) == -1) return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (out(format[-1], arg) == -1) return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_PALANDPRINTF_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_PALANDPRINTF_H_
|
||||
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 144
|
||||
#define PRINTF_FTOA_BUFFER_SIZE 64
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int spacepad(int (*)(long, void *), void *, unsigned long) hidden;
|
||||
int ftoa(int (*)(long, void *), void *, long double, int, unsigned long,
|
||||
unsigned long) hidden;
|
||||
int stoa(int (*)(long, void *), void *, void *, unsigned long, unsigned long,
|
||||
unsigned long, unsigned char, unsigned char) hidden;
|
||||
int ntoa(int (*)(long, void *), void *, va_list, unsigned char, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char, const char *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_PALANDPRINTF_H_ */
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -17,19 +18,20 @@
|
|||
* format strings are constexprs that only contain directives.
|
||||
*/
|
||||
|
||||
#define PFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
#define PFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "faAeEgG")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
})
|
||||
|
||||
#define SFLINK(FMT) \
|
||||
|
@ -67,6 +69,7 @@
|
|||
#define SFLINK(FMT) FMT
|
||||
#ifdef __GNUC__
|
||||
__asm__(".section .yoink\n\t"
|
||||
"nopl\t__fmt_dtoa(%rip)\n\t"
|
||||
"nopl\tkCp437(%rip)\n\t"
|
||||
"nopl\tstrerror(%rip)\n\t"
|
||||
"nopl\tstrnwidth(%rip)\n\t"
|
||||
|
@ -79,6 +82,7 @@ __asm__(".section .yoink\n\t"
|
|||
#else
|
||||
static long __pflink(long x) {
|
||||
x |= kCp437[0];
|
||||
x |= __fmt_dtoa(0, 0, 0, 0, 0, 0);
|
||||
x |= strnwidth(0, 0, 0);
|
||||
x |= strnwidth16(0, 0, 0);
|
||||
x |= wcsnwidth(0, 0, 0);
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* @return number of bytes written, excluding the NUL terminator; or,
|
||||
* if the output buffer wasn't passed, or was too short, then the
|
||||
* number of characters that *would* have been written is returned
|
||||
* @see palandprintf() and printf() for detailed documentation
|
||||
* @see __fmt() and printf() for detailed documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
/**
|
||||
* Formats string to buffer that's hopefully large enough.
|
||||
*
|
||||
* @see palandprintf() and printf() for detailed documentation
|
||||
* @see __fmt() and printf() for detailed documentation
|
||||
* @see snprintf() for same w/ buf size param
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/paland.inc"
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/nexgen32e/tinystrlen.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
|
@ -28,12 +28,13 @@
|
|||
|
||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
||||
|
||||
static noinstrument int StoaEmitByte(int f(long, void *), void *a, wint_t c) {
|
||||
static noinstrument int __fmt_stoa_byte(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return f(c, a);
|
||||
}
|
||||
|
||||
static noinstrument int StoaEmitWordEncodedString(int f(long, void *), void *a,
|
||||
uint64_t w) {
|
||||
static noinstrument int __fmt_stoa_word(int f(long, void *), void *a,
|
||||
uint64_t w) {
|
||||
do {
|
||||
if (f(w & 0xff, a) == -1) {
|
||||
return -1;
|
||||
|
@ -42,31 +43,32 @@ static noinstrument int StoaEmitWordEncodedString(int f(long, void *), void *a,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static noinstrument int StoaEmitUnicode(int f(long, void *), void *a,
|
||||
static noinstrument int __fmt_stoa_wide(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return f(c, a);
|
||||
} else {
|
||||
return StoaEmitWordEncodedString(f, a, tpenc(c));
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static noinstrument int StoaEmitQuoted(int f(long, void *), void *a, wint_t c) {
|
||||
static noinstrument int __fmt_stoa_bing(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return __fmt_stoa_wide(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quoted(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return StoaEmitWordEncodedString(f, a, cescapec(c));
|
||||
return __fmt_stoa_word(f, a, cescapec(c));
|
||||
} else {
|
||||
return StoaEmitWordEncodedString(f, a, tpenc(c));
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static noinstrument int StoaEmitVisualized(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return StoaEmitUnicode(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static noinstrument int StoaEmitQuote(int out(long, void *), void *arg,
|
||||
unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||
unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out('L', arg) == -1) return -1;
|
||||
|
@ -81,15 +83,16 @@ static noinstrument int StoaEmitQuote(int out(long, void *), void *arg,
|
|||
/**
|
||||
* Converts string to array.
|
||||
*
|
||||
* This function is used by palandprintf() to implement the %s and %c
|
||||
* directives. The content outputted to the array is always UTF-8, but
|
||||
* the input may be UTF-16 or UTF-32.
|
||||
* This is used by __fmt() to implement the %s and %c directives. The
|
||||
* content outputted to the array is always UTF-8, but the input may be
|
||||
* UTF-16 or UTF-32.
|
||||
*
|
||||
* @see palandprintf()
|
||||
* @see __fmt()
|
||||
*/
|
||||
int stoa(int out(long, void *), void *arg, void *data, unsigned long flags,
|
||||
unsigned long precision, unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||
unsigned long flags, unsigned long precision,
|
||||
unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
char *p;
|
||||
wint_t wc;
|
||||
unsigned n;
|
||||
|
@ -104,28 +107,28 @@ int stoa(int out(long, void *), void *arg, void *data, unsigned long flags,
|
|||
flags |= FLAGS_NOQUOTE;
|
||||
signbit = 0;
|
||||
} else {
|
||||
if (StoaEmitQuote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
|
||||
ignorenul = false;
|
||||
justdobytes = false;
|
||||
if (signbit == 15 || signbit == 63) {
|
||||
if (flags & FLAGS_QUOTE) {
|
||||
emit = StoaEmitQuoted;
|
||||
emit = __fmt_stoa_quoted;
|
||||
ignorenul = flags & FLAGS_PRECISION;
|
||||
} else {
|
||||
emit = StoaEmitUnicode;
|
||||
emit = __fmt_stoa_wide;
|
||||
}
|
||||
} else if ((flags & FLAGS_HASH) && weaken(kCp437)) {
|
||||
justdobytes = true;
|
||||
emit = StoaEmitVisualized;
|
||||
emit = __fmt_stoa_bing;
|
||||
ignorenul = flags & FLAGS_PRECISION;
|
||||
} else if (flags & FLAGS_QUOTE) {
|
||||
emit = StoaEmitQuoted;
|
||||
emit = __fmt_stoa_quoted;
|
||||
ignorenul = flags & FLAGS_PRECISION;
|
||||
} else {
|
||||
justdobytes = true;
|
||||
emit = StoaEmitByte;
|
||||
emit = __fmt_stoa_byte;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_PRECISION)) precision = -1;
|
||||
|
@ -159,7 +162,7 @@ int stoa(int out(long, void *), void *arg, void *data, unsigned long flags,
|
|||
}
|
||||
|
||||
if (pad && !(flags & FLAGS_LEFT)) {
|
||||
if (spacepad(out, arg, pad) == -1) return -1;
|
||||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (justdobytes) {
|
||||
|
@ -208,7 +211,7 @@ int stoa(int out(long, void *), void *arg, void *data, unsigned long flags,
|
|||
}
|
||||
|
||||
if (pad && (flags & FLAGS_LEFT)) {
|
||||
if (spacepad(out, arg, pad) == -1) return -1;
|
||||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
|
||||
STATIC_YOINK("E2BIG");
|
||||
STATIC_YOINK("EACCES");
|
||||
STATIC_YOINK("EADDRINUSE");
|
||||
|
|
|
@ -25,9 +25,5 @@
|
|||
* @param optional_base is recommended as 0 for flexidecimal
|
||||
*/
|
||||
long strtol(const char *s, char **opt_out_end, int optional_base) {
|
||||
long res;
|
||||
res = strtoimax(s, opt_out_end, optional_base);
|
||||
if (res < LONG_MIN) return LONG_MIN;
|
||||
if (res > LONG_MAX) return LONG_MAX;
|
||||
return res;
|
||||
return strtoimax(s, opt_out_end, optional_base);
|
||||
}
|
||||
|
|
|
@ -44,13 +44,13 @@ static noinstrument int vsnprintfputchar(unsigned char c,
|
|||
* @return number of bytes written, excluding the NUL terminator; or,
|
||||
* if the output buffer wasn't passed, or was too short, then the
|
||||
* number of characters that *would* have been written is returned
|
||||
* @see palandprintf() and printf() for detailed documentation
|
||||
* @see __fmt() and printf() for detailed documentation
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||
struct SprintfStr str = {buf, 0, size};
|
||||
palandprintf(vsnprintfputchar, &str, fmt, va);
|
||||
__fmt(vsnprintfputchar, &str, fmt, va);
|
||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
||||
return str.i;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
/**
|
||||
* Formats string to buffer hopefully large enough w/ vararg state.
|
||||
*
|
||||
* @see palandprintf() and printf() for detailed documentation
|
||||
* @see __fmt() and printf() for detailed documentation
|
||||
* @see vsnprintf() for modern alternative w/ buf size param
|
||||
*/
|
||||
int(vsprintf)(char *buf, const char *fmt, va_list va) {
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_WCSLOL_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_WCSLOL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define WCSLOL(STR, ENDPTR, OPTIONAL_BASE, MIN, MAX) \
|
||||
({ \
|
||||
intmax_t res = wcstoimax(STR, ENDPTR, OPTIONAL_BASE); \
|
||||
if (res < MIN) return MIN; \
|
||||
if (res > MAX) return MAX; \
|
||||
res; \
|
||||
})
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_WCSLOL_H_ */
|
|
@ -17,10 +17,8 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/wcslol.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
long wcstol(const wchar_t *s, wchar_t **end, int opt_base) {
|
||||
return WCSLOL(s, end, opt_base, LONG_MIN, LONG_MAX);
|
||||
return wcstoimax(s, end, opt_base);
|
||||
}
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
|
||||
void __check_fail_aligned(unsigned bytes, uint64_t ptr) {
|
||||
fflush(stderr);
|
||||
if (!IsTiny()) memsummary(fileno(stderr));
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
STATIC_YOINK("ftoa");
|
||||
|
||||
/**
|
||||
* Handles failure of CHECK_xx() macros.
|
||||
*/
|
||||
|
|
|
@ -44,7 +44,8 @@ LIBC_LOG_A_DIRECTDEPS = \
|
|||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
THIRD_PARTY_DLMALLOC
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA
|
||||
|
||||
LIBC_LOG_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_LOG_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/dlmalloc/dlmalloc.internal.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
|
||||
void malloc_stats(void) {
|
||||
struct MallocStats res = dlmalloc_stats(g_dlmalloc);
|
||||
(fprintf)(stderr, "max system bytes = %'10zu\r\n", res.maxfp);
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
|
||||
static void onmemchunk(void *start, void *end, size_t used_bytes, void *arg) {
|
||||
(dprintf)(*(int *)arg, "%p - %p : %08zx / %08lx\r\n", start, end, used_bytes,
|
||||
(intptr_t)end - (intptr_t)start);
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
|
||||
void memsummary(int fd) {
|
||||
struct mallinfo mi;
|
||||
mi = mallinfo();
|
||||
|
|
|
@ -37,10 +37,6 @@
|
|||
|
||||
#define kNontrivialSize (8 * 1000 * 1000)
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
STATIC_YOINK("ftoa");
|
||||
|
||||
static struct timespec vflogf_ts;
|
||||
|
||||
static int vflogf_loglevel2char(unsigned level) {
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/memtrack.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
|
||||
void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
|
||||
int i, frames, maptally, gaptally;
|
||||
maptally = 0;
|
||||
|
|
|
@ -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,13 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
double RoundDecimalPlaces(double f, double digs, double rounder(double)) {
|
||||
if (!(0 <= digs && digs < 15)) {
|
||||
return f;
|
||||
} else {
|
||||
return rounder(f * exp10(digs)) / exp10(digs);
|
||||
}
|
||||
char *__fmt_dtoa(double d0, int mode, int ndigits, int *decpt, int *sign,
|
||||
char **rve) {
|
||||
return dtoa(d0, mode, ndigits, decpt, sign, rve);
|
||||
}
|
|
@ -58,7 +58,7 @@
|
|||
* This means it implies the quoting modifier, wraps the value with
|
||||
* {,u,L}['"] quotes, displays NULL as "NULL" rather than "(null)".
|
||||
*
|
||||
* @see palandprintf() for intuitive reference documentation
|
||||
* @see __fmt() for intuitive reference documentation
|
||||
* @see {,v}{,s{,n},{,{,x}as},f,d}printf
|
||||
*/
|
||||
int(printf)(const char* fmt, ...) {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int Printf(const char *, ...);
|
||||
int Sprintf(char *, const char *, ...);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § standard i/o ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
|
|
@ -37,7 +37,8 @@ LIBC_STDIO_A_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS
|
||||
LIBC_SYSV_CALLS \
|
||||
THIRD_PARTY_GDTOA
|
||||
|
||||
LIBC_STDIO_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_STDIO_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -33,7 +33,7 @@ static noinstrument int vfprintfputchar(int c, struct state *st) {
|
|||
|
||||
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
|
||||
struct state st[1] = {{f, 0}};
|
||||
if (palandprintf(vfprintfputchar, st, fmt, va) != -1) {
|
||||
if (__fmt(vfprintfputchar, st, fmt, va) != -1) {
|
||||
return st->n;
|
||||
} else {
|
||||
return -1;
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
STATIC_YOINK("strnwidth");
|
||||
|
||||
void __testlib_ezbenchreport(const char *form, uint64_t c1, uint64_t c2) {
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
STATIC_YOINK("stoa");
|
||||
|
||||
static unsigned clip(unsigned index, unsigned count) {
|
||||
return index < count ? index : 0;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include "libc/time/time.h"
|
||||
#include "libc/time/tzfile.internal.h"
|
||||
|
||||
STATIC_YOINK("ntoa");
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
strftime (BSD-3)\\n\
|
||||
Copyright 1989 The Regents of the University of California\"");
|
||||
|
@ -330,13 +328,13 @@ static char *strftime_timefmt(char *p, const char *pe, const char *format,
|
|||
if (t->tm_isdst == 0)
|
||||
#ifdef USG_COMPAT
|
||||
diff = -timezone;
|
||||
#else /* !defined USG_COMPAT */
|
||||
#else /* !defined USG_COMPAT */
|
||||
continue;
|
||||
#endif /* !defined USG_COMPAT */
|
||||
else
|
||||
#ifdef ALTZONE
|
||||
diff = -altzone;
|
||||
#else /* !defined ALTZONE */
|
||||
#else /* !defined ALTZONE */
|
||||
continue;
|
||||
#endif /* !defined ALTZONE */
|
||||
#endif /* !defined TM_GMTOFF */
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
STATIC_YOINK("stoa");
|
||||
STATIC_YOINK("ntoa");
|
||||
|
||||
/**
|
||||
* @fileoverview Timestamps in One True Format w/o toil.
|
||||
*/
|
||||
|
|
|
@ -433,8 +433,7 @@ TEST(sprintf, test_float) {
|
|||
EXPECT_STREQ("3.5", Format("%.1f", 3.49));
|
||||
EXPECT_STREQ("a0.5 ", Format("a%-5.1f", 0.5));
|
||||
EXPECT_STREQ("a0.5 end", Format("a%-5.1fend", 0.5));
|
||||
/* out of range in the moment, need to be fixed by someone */
|
||||
EXPECT_STREQ("inf", Format("%.1f", 1E20));
|
||||
EXPECT_STREQ("100000000000000000000.0", Format("%.1f", 1E20));
|
||||
}
|
||||
|
||||
TEST(sprintf, test_types) {
|
||||
|
|
68
test/libc/fmt/realfmt_test.c
Normal file
68
test/libc/fmt/realfmt_test.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*-*- 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/fmt.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
TEST(RealFormatting, g) {
|
||||
EXPECT_STREQ("nan", gc(xasprintf("%g", NAN)));
|
||||
EXPECT_STREQ("-nan", gc(xasprintf("%g", -NAN)));
|
||||
EXPECT_STREQ("inf", gc(xasprintf("%g", INFINITY)));
|
||||
EXPECT_STREQ("-inf", gc(xasprintf("%g", -INFINITY)));
|
||||
EXPECT_STREQ("0", gc(xasprintf("%g", 0.)));
|
||||
EXPECT_STREQ("-0", gc(xasprintf("%g", -0.)));
|
||||
EXPECT_STREQ("1", gc(xasprintf("%g", 1.)));
|
||||
EXPECT_STREQ("-1", gc(xasprintf("%g", -1.)));
|
||||
EXPECT_STREQ("10", gc(xasprintf("%g", 10.)));
|
||||
EXPECT_STREQ("10", gc(xasprintf("%.0g", 10.)));
|
||||
EXPECT_STREQ("-10", gc(xasprintf("%g", -10.)));
|
||||
EXPECT_STREQ("-10", gc(xasprintf("%.0g", -10.)));
|
||||
EXPECT_STREQ(" -10", gc(xasprintf("%10g", -10.)));
|
||||
EXPECT_STREQ(" -10", gc(xasprintf("%*g", 10, -10.)));
|
||||
EXPECT_STREQ("1e+100", gc(xasprintf("%g", 1e100)));
|
||||
EXPECT_STREQ("1e-100", gc(xasprintf("%g", 1e-100)));
|
||||
EXPECT_STREQ("-1e-100", gc(xasprintf("%g", -1e-100)));
|
||||
EXPECT_STREQ("3.14159", gc(xasprintf("%g", 0x1.921fb54442d1846ap+1)));
|
||||
}
|
||||
|
||||
TEST(RealFormatting, f) {
|
||||
EXPECT_STREQ("3.141593", gc(xasprintf("%f", 0x1.921fb54442d1846ap+1)));
|
||||
EXPECT_STREQ("3.1415926535897931",
|
||||
gc(xasprintf("%.16f", 0x1.921fb54442d1846ap+1)));
|
||||
EXPECT_STREQ("100000000000000001590289110975991804683608085639452813"
|
||||
"89781327557747838772170381060813469985856815104.000000",
|
||||
gc(xasprintf("%f", 1e100)));
|
||||
}
|
||||
|
||||
TEST(RealFormatting, e) {
|
||||
EXPECT_STREQ("3.14159", gc(xasprintf("%g", 0x1.921fb54442d1846ap+1)));
|
||||
EXPECT_STREQ("3.141592653589793",
|
||||
gc(xasprintf("%.16g", 0x1.921fb54442d1846ap+1)));
|
||||
EXPECT_STREQ("1.000000e+100", gc(xasprintf("%e", 1e100)));
|
||||
EXPECT_STREQ("1.000000E+100", gc(xasprintf("%E", 1e100)));
|
||||
}
|
||||
|
||||
TEST(RealFormatting, a) {
|
||||
EXPECT_STREQ("0x1.921fb54442d18p+1",
|
||||
gc(xasprintf("%a", 0x1.921fb54442d1846ap+1)));
|
||||
EXPECT_STREQ("0X1.921FB54442D18P+1",
|
||||
gc(xasprintf("%A", 0x1.921fb54442d1846ap+1)));
|
||||
}
|
|
@ -29,6 +29,7 @@ TEST_LIBC_FMT_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
|
|
7
third_party/duktape/duktape.mk
vendored
7
third_party/duktape/duktape.mk
vendored
|
@ -31,13 +31,14 @@ THIRD_PARTY_DUKTAPE_A_DIRECTDEPS = \
|
|||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_TIME \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_NEXGEN32E
|
||||
LIBC_UNICODE
|
||||
|
||||
THIRD_PARTY_DUKTAPE_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_DUKTAPE_A_DIRECTDEPS),$($(x))))
|
||||
|
|
4
third_party/gdtoa/dtoa.c
vendored
4
third_party/gdtoa/dtoa.c
vendored
|
@ -168,9 +168,9 @@ dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
|
|||
*decpt = 9999;
|
||||
#ifdef IEEE_Arith
|
||||
if (!word1(&d) && !(word0(&d) & 0xfffff))
|
||||
return nrv_alloc("Infinity", rve, 8 MTb);
|
||||
return nrv_alloc("inf", rve, 8 MTb);
|
||||
#endif
|
||||
return nrv_alloc("NaN", rve, 3 MTb);
|
||||
return nrv_alloc("nan", rve, 3 MTb);
|
||||
}
|
||||
#endif
|
||||
#ifdef IBM
|
||||
|
|
8
third_party/getopt/getopt.c
vendored
8
third_party/getopt/getopt.c
vendored
|
@ -135,8 +135,8 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
|
|||
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
|
||||
if (*getopt_place == 0) ++optind;
|
||||
if (opterr && *ostr != ':') {
|
||||
fprintf(stderr, "%s: illegal option -- %c\n", program_invocation_name,
|
||||
optopt);
|
||||
fprintf(stderr, "%s%s%c\n", program_invocation_name,
|
||||
": illegal option -- ", optopt);
|
||||
}
|
||||
return (BADCH);
|
||||
}
|
||||
|
@ -157,8 +157,8 @@ int getopt(int nargc, char *const nargv[], const char *ostr) {
|
|||
getopt_place = kGetoptEmsg;
|
||||
if (*ostr == ':') return (BADARG);
|
||||
if (opterr)
|
||||
fprintf(stderr, "%s: option requires an argument -- %c\n",
|
||||
program_invocation_name, optopt);
|
||||
fprintf(stderr, "%s%s%c\n", program_invocation_name,
|
||||
": option requires an argument -- ", optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
getopt_place = kGetoptEmsg;
|
||||
|
|
Loading…
Reference in a new issue