mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
Remove printf() linking hack
This commit is contained in:
parent
ba03cd95c5
commit
b881c0ec9e
107 changed files with 1520 additions and 2577 deletions
|
@ -103,9 +103,12 @@ int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *name,
|
|||
if (service != NULL && servicelen != 0) {
|
||||
if ((flags & NI_NUMERICSERV) ||
|
||||
LookupServicesByPort(port, ((flags & NI_DGRAM) ? "udp" : "tcp"), 4,
|
||||
info, sizeof(info), NULL) == -1)
|
||||
itoa(port, info, 10);
|
||||
if (strlen(info) + 1 > servicelen) return EAI_OVERFLOW;
|
||||
info, sizeof(info), NULL) == -1) {
|
||||
FormatInt32(info, port);
|
||||
}
|
||||
if (strlen(info) + 1 > servicelen) {
|
||||
return EAI_OVERFLOW;
|
||||
}
|
||||
strcpy(service, info);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,14 @@ unsigned long long wcstoull(const wchar_t *, wchar_t **, int);
|
|||
int wcscoll(const wchar_t *, const wchar_t *);
|
||||
size_t wcsxfrm(wchar_t *, const wchar_t *, size_t);
|
||||
|
||||
double atof(const char *);
|
||||
float strtof(const char *, char **);
|
||||
double strtod(const char *, char **);
|
||||
long double strtold(const char *, char **);
|
||||
float wcstof(const wchar_t *, wchar_t **);
|
||||
double wcstod(const wchar_t *, wchar_t **);
|
||||
long double wcstold(const wchar_t *, wchar_t **);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § conversion » time ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
|
431
libc/fmt/fmt.c
431
libc/fmt/fmt.c
|
@ -1,431 +0,0 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/nomultics.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.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 (64-bit)
|
||||
* - `%jjd` int128_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 if floating point isn't used
|
||||
* @vforksafe if floating point isn't used
|
||||
*/
|
||||
_Hide int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||
long ld;
|
||||
void *p;
|
||||
unsigned u;
|
||||
char ibuf[21];
|
||||
bool longdouble;
|
||||
unsigned long lu;
|
||||
wchar_t charbuf[1];
|
||||
char *s, *q, qchar;
|
||||
const char *alphabet;
|
||||
unsigned char signbit, log2base;
|
||||
int (*out)(const char *, void *, size_t);
|
||||
int d, w, n, sign, prec, flags, width, lasterr;
|
||||
|
||||
lasterr = errno;
|
||||
out = fn ? fn : (void *)_missingno;
|
||||
|
||||
while (*format) {
|
||||
if (*format != '%') {
|
||||
for (n = 1; format[n]; ++n) {
|
||||
if (format[n] == '%') break;
|
||||
}
|
||||
if (out(format, arg, n) == -1) return -1;
|
||||
format += n;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsTiny()) {
|
||||
if (format[1] == 's') { // FAST PATH: PLAIN STRING
|
||||
s = va_arg(va, char *);
|
||||
if (!s) s = "(null)";
|
||||
if (out(s, arg, strlen(s)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'd') { // FAST PATH: PLAIN INTEGER
|
||||
d = va_arg(va, int);
|
||||
if (out(ibuf, arg, FormatInt32(ibuf, d) - ibuf) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'u') { // FAST PATH: PLAIN UNSIGNED
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, FormatUint32(ibuf, u) - ibuf) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'x') { // FAST PATH: PLAIN HEX
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix16(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'x') {
|
||||
lu = va_arg(va, unsigned long); // FAST PATH: PLAIN LONG HEX
|
||||
if (out(ibuf, arg, uint64toarray_radix16(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||
ld = va_arg(va, long); // FAST PATH: PLAIN LONG
|
||||
if (out(ibuf, arg, FormatInt64(ibuf, ld) - ibuf) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||
lu = va_arg(va, unsigned long); // FAST PATH: PLAIN UNSIGNED LONG
|
||||
if (out(ibuf, arg, FormatUint64(ibuf, lu) - ibuf) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||
n = va_arg(va, unsigned); // FAST PATH: PRECISION STRING
|
||||
s = va_arg(va, const char *);
|
||||
if (s) {
|
||||
n = strnlen(s, n);
|
||||
} else {
|
||||
s = "(null)";
|
||||
n = MIN(6, n);
|
||||
}
|
||||
if (out(s, arg, n) == -1) return -1;
|
||||
format += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// GENERAL PATH
|
||||
format++;
|
||||
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;
|
||||
flags &= ~FLAGS_PRECISION;
|
||||
}
|
||||
|
||||
// evaluate length field
|
||||
signbit = 31;
|
||||
longdouble = false;
|
||||
switch (*format) {
|
||||
case 'j': // intmax_t
|
||||
format++;
|
||||
signbit = sizeof(intmax_t) * 8 - 1;
|
||||
if (*format == 'j') {
|
||||
format++;
|
||||
signbit = sizeof(int128_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 = "0123456789abcdefpx";
|
||||
switch ((d = *format++)) {
|
||||
case 'p':
|
||||
flags |= FLAGS_HASH;
|
||||
log2base = 4;
|
||||
signbit = 63;
|
||||
goto FormatNumber;
|
||||
case 'X':
|
||||
alphabet = "0123456789ABCDEFPX";
|
||||
// fallthrough
|
||||
case 'x':
|
||||
log2base = 4;
|
||||
goto FormatNumber;
|
||||
case 'b':
|
||||
log2base = 1;
|
||||
alphabet = "0123456789abcdefpb";
|
||||
goto FormatNumber;
|
||||
case 'o':
|
||||
log2base = 3;
|
||||
goto FormatNumber;
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= FLAGS_ISSIGNED;
|
||||
// fallthrough
|
||||
case 'u': {
|
||||
uint128_t value;
|
||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||
FormatNumber:
|
||||
if (signbit > 63) {
|
||||
value = va_arg(va, uint128_t);
|
||||
} else {
|
||||
value = va_arg(va, uint64_t);
|
||||
}
|
||||
if (__fmt_ntoa(out, arg, value, signbit, log2base, prec, width, flags,
|
||||
alphabet) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
if ((charbuf[0] = va_arg(va, int))) {
|
||||
p = charbuf;
|
||||
qchar = '\'';
|
||||
flags |= FLAGS_PRECISION;
|
||||
prec = 1;
|
||||
goto FormatString;
|
||||
} else {
|
||||
__FMT_PUT('\0');
|
||||
break;
|
||||
}
|
||||
case 'm':
|
||||
p = _weaken(strerror) ? _weaken(strerror)(lasterr) : "?";
|
||||
signbit = 0;
|
||||
goto FormatString;
|
||||
case 'r':
|
||||
// undocumented %r specifier
|
||||
// used for good carriage return
|
||||
// helps integrate loggers with repls
|
||||
if (!__replstderr) {
|
||||
break;
|
||||
} else {
|
||||
p = "\r\e[K";
|
||||
goto FormatString;
|
||||
}
|
||||
case 'S':
|
||||
// Specified by POSIX to be equivalent to %ls
|
||||
signbit = 63;
|
||||
goto FormatStringPNotFetchedYet;
|
||||
case 'q':
|
||||
flags |= FLAGS_QUOTE;
|
||||
// fallthrough
|
||||
case 's':
|
||||
FormatStringPNotFetchedYet:
|
||||
p = va_arg(va, void *);
|
||||
FormatString:
|
||||
if (__fmt_stoa(out, arg, p, flags, prec, width, signbit, qchar) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
__FMT_PUT('\n');
|
||||
break;
|
||||
case 'F':
|
||||
case 'f':
|
||||
case 'G':
|
||||
case 'g':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'a':
|
||||
case 'A': {
|
||||
int rc;
|
||||
if (!_weaken(__fmt_dtoa)) {
|
||||
p = "?";
|
||||
prec = 0;
|
||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
||||
goto FormatString;
|
||||
}
|
||||
rc = _weaken(__fmt_dtoa)(out, arg, d, flags, prec, sign, width,
|
||||
longdouble, qchar, signbit, alphabet, va);
|
||||
if (rc == -1) return -1;
|
||||
#ifdef __aarch64__
|
||||
// huge kludge
|
||||
switch (rc) {
|
||||
case __FMT_CONSUMED_DOUBLE:
|
||||
va_arg(va, double);
|
||||
break;
|
||||
case __FMT_CONSUMED_LONG_DOUBLE:
|
||||
va_arg(va, long double);
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
#endif /* __aarch64__ */
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
__FMT_PUT('%');
|
||||
break;
|
||||
default:
|
||||
__FMT_PUT(format[-1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_FMT_H_
|
||||
#include "libc/fmt/pflink.h"
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § string formatting ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
@ -31,19 +30,6 @@ char *fcvt(double, int, int *, int *);
|
|||
char *ecvt(double, int, int *, int *);
|
||||
char *gcvt(double, int, char *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § string formatting » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#if defined(COSMO) && !defined(__cplusplus)
|
||||
#define sprintf(BUF, FMT, ...) (sprintf)(BUF, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vsprintf(BUF, FMT, VA) (vsprintf)(BUF, PFLINK(FMT), VA)
|
||||
#define snprintf(B, Z, F, ...) (snprintf)(B, Z, PFLINK(F), ##__VA_ARGS__)
|
||||
#define vsnprintf(BUF, SIZE, FMT, VA) (vsnprintf)(BUF, SIZE, PFLINK(FMT), VA)
|
||||
#define sscanf(STR, FMT, ...) (sscanf)(STR, SFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vsscanf(STR, FMT, VA) (vsscanf)(STR, SFLINK(FMT), VA)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_FMT_H_ */
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_
|
||||
|
||||
#define PRINTF_NTOA_BUFFER_SIZE 144
|
||||
|
||||
#define __FMT_CONSUMED_DOUBLE 1
|
||||
#define __FMT_CONSUMED_LONG_DOUBLE 2
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define __FMT_PUT(C) \
|
||||
do { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||
unsigned long) _Hide;
|
||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||
unsigned char) _Hide;
|
||||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, uint128_t,
|
||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||
unsigned char, const char *) _Hide;
|
||||
int __fmt_dtoa(int (*)(const char *, void *, size_t), void *, int, int, int,
|
||||
int, int, bool, char, unsigned char, const char *, va_list);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_ */
|
|
@ -1,16 +0,0 @@
|
|||
#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_ */
|
|
@ -1,30 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
||||
compatfn char *itoa(int value, char *str, int radix) {
|
||||
(sprintf)(str,
|
||||
VEIL("r", radix == 16 ? "%x"
|
||||
: radix == 8 ? "%d"
|
||||
: radix == 2 ? "%b"
|
||||
: "%d"),
|
||||
value);
|
||||
return str;
|
||||
}
|
196
libc/fmt/ntoa.c
196
libc/fmt/ntoa.c
|
@ -1,196 +0,0 @@
|
|||
/*-*- 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/divmod10.internal.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/reverse.internal.h"
|
||||
|
||||
#define BUFFER_SIZE 144
|
||||
|
||||
uint128_t __udivmodti4(uint128_t, uint128_t, uint128_t *);
|
||||
|
||||
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||
char *buf, unsigned len, bool negative,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned char flags, const char *alphabet) {
|
||||
unsigned i, prec_width_zeros;
|
||||
char alternate_form_middle_char, sign_character;
|
||||
unsigned actual_buf_len;
|
||||
actual_buf_len = len;
|
||||
prec_width_zeros = 0;
|
||||
/* pad leading zeros */
|
||||
if (width && (flags & FLAGS_ZEROPAD) &&
|
||||
(negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
||||
width--;
|
||||
}
|
||||
if (len < prec) {
|
||||
prec_width_zeros += (prec - len);
|
||||
len = prec;
|
||||
}
|
||||
if ((flags & FLAGS_ZEROPAD) && (len < width)) {
|
||||
prec_width_zeros += (width - len);
|
||||
len = width;
|
||||
}
|
||||
/* handle hash */
|
||||
if (flags & FLAGS_HASH) {
|
||||
if ((!(flags & FLAGS_PRECISION) || log2base == 3) && len &&
|
||||
((len >= prec) || (len >= width)) &&
|
||||
(prec_width_zeros || buf[len - 1] == '0')) {
|
||||
if (prec_width_zeros) {
|
||||
--prec_width_zeros;
|
||||
}
|
||||
--len;
|
||||
if (len < actual_buf_len) {
|
||||
actual_buf_len = len;
|
||||
}
|
||||
if (len && (log2base == 4 || log2base == 1) &&
|
||||
(prec_width_zeros || buf[len - 1] == '0')) {
|
||||
if (prec_width_zeros) {
|
||||
--prec_width_zeros;
|
||||
}
|
||||
--len;
|
||||
if (len < actual_buf_len) {
|
||||
actual_buf_len = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
alternate_form_middle_char = '\0';
|
||||
if ((log2base == 4 || log2base == 1)) {
|
||||
++len;
|
||||
alternate_form_middle_char =
|
||||
alphabet[17]; // x, X or b (for the corresponding conversion
|
||||
// specifiers)
|
||||
}
|
||||
++len;
|
||||
}
|
||||
sign_character = '\0';
|
||||
if (negative) {
|
||||
++len;
|
||||
sign_character = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
++len;
|
||||
sign_character = '+'; /* ignore the space if the '+' exists */
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
++len;
|
||||
sign_character = ' ';
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
if (sign_character != '\0' && out(&sign_character, arg, 1) == -1) return -1;
|
||||
if (flags & FLAGS_HASH) {
|
||||
if (out("0", arg, 1) == -1) return -1;
|
||||
if (alternate_form_middle_char != '\0' &&
|
||||
out(&alternate_form_middle_char, arg, 1) == -1)
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < prec_width_zeros; ++i)
|
||||
if (out("0", arg, 1) == -1) return -1;
|
||||
reverse(buf, actual_buf_len);
|
||||
if (out(buf, arg, actual_buf_len) == -1) return -1;
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (len < width) {
|
||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||
uint128_t value, bool neg, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned flags, const char *alphabet) {
|
||||
uint128_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
len = 0;
|
||||
/* we check for log2base != 3 because otherwise we'll print nothing for a
|
||||
* value of 0 with precision 0 when # mandates that one be printed */
|
||||
if (!value && log2base != 3) flags &= ~FLAGS_HASH;
|
||||
if (value || !(flags & FLAGS_PRECISION)) {
|
||||
count = 0;
|
||||
do {
|
||||
if (!log2base) {
|
||||
if (value <= UINT64_MAX) {
|
||||
value = DivMod10(value, &digit);
|
||||
} else {
|
||||
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);
|
||||
_npassert(count <= BUFFER_SIZE);
|
||||
}
|
||||
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
|
||||
flags, alphabet);
|
||||
}
|
||||
|
||||
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg,
|
||||
uint128_t value, unsigned char signbit, unsigned long log2base,
|
||||
unsigned long prec, unsigned long width, unsigned char flags,
|
||||
const char *lang) {
|
||||
bool neg;
|
||||
uint128_t sign;
|
||||
|
||||
/* ignore '0' flag when prec or minus flag is given */
|
||||
if (flags & (FLAGS_PRECISION | FLAGS_LEFT)) {
|
||||
flags &= ~FLAGS_ZEROPAD;
|
||||
}
|
||||
|
||||
/* no plus / space flag for u, x, X, o, b */
|
||||
if (!(flags & FLAGS_ISSIGNED)) {
|
||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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.internal.h"
|
||||
|
||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||
unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(" ", arg, 1);
|
||||
return rc;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#ifdef COSMO
|
||||
|
||||
/**
|
||||
* @fileoverview builtin+preprocessor+linker tricks for printf/scanf.
|
||||
*
|
||||
* Your printf() function only requires that you pay for what you use.
|
||||
* These macros ensure that its code size starts at under 4kb, growing
|
||||
* to about 40kb for a fully-loaded implementation. This works best when
|
||||
* format strings are constexprs that only contain directives.
|
||||
*/
|
||||
|
||||
#define PFLINK(...) _PFLINK(__VA_ARGS__)
|
||||
#define _PFLINK(FMT, ...) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strpbrk, "fFaAeEgG")) STATIC_YOINK("__fmt_dtoa"); \
|
||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||
if (___PFLINK(FMT, strstr, "%*") || \
|
||||
___PFLINK(FMT, strpbrk, "0123456789")) { \
|
||||
STATIC_YOINK("strnwidth"); \
|
||||
STATIC_YOINK("strnwidth16"); \
|
||||
STATIC_YOINK("wcsnwidth"); \
|
||||
} \
|
||||
} \
|
||||
FMT; \
|
||||
})
|
||||
|
||||
#define SFLINK(...) _SFLINK(__VA_ARGS__)
|
||||
#define _SFLINK(FMT) \
|
||||
({ \
|
||||
if (___PFLINK(FMT, strchr, 'm')) { \
|
||||
STATIC_YOINK("malloc"); \
|
||||
STATIC_YOINK("calloc"); \
|
||||
STATIC_YOINK("free"); \
|
||||
STATIC_YOINK("__grow"); \
|
||||
} \
|
||||
FMT; \
|
||||
})
|
||||
|
||||
#if __GNUC__ + 0 < 4 || defined(__llvm__)
|
||||
#define ___PFLINK(FMT, FN, C) 1
|
||||
#else
|
||||
#define ___PFLINK(FMT, FN, C) \
|
||||
!__builtin_constant_p(FMT) || ((FMT) && __builtin_##FN(FMT, C) != NULL)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 6
|
||||
/*
|
||||
* Compilers don't understand the features we've added to the format
|
||||
* string DSL, such as c string escaping, therefore we can't use it.
|
||||
* Ideally compilers should grant us more flexibility to define DSLs
|
||||
*
|
||||
* The recommended approach to turning this back on is `CFLAGS=-std=c11`
|
||||
* which puts the compiler in __STRICT_ANSI__ mode, which Cosmopolitan
|
||||
* respects by disabling all the esoteric tuning in headers like this.
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wformat-security"
|
||||
#endif /* __GNUC__ + 0 < 6 */
|
||||
|
||||
#else
|
||||
STATIC_YOINK("strerror");
|
||||
STATIC_YOINK("strnwidth");
|
||||
STATIC_YOINK("__fmt_dtoa");
|
||||
STATIC_YOINK("strnwidth16");
|
||||
STATIC_YOINK("wcsnwidth");
|
||||
#endif /* COSMO */
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_PFLINK_H_ */
|
219
libc/fmt/stoa.c
219
libc/fmt/stoa.c
|
@ -1,219 +0,0 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/intrin/tpenc.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/strwidth.h"
|
||||
#include "libc/str/tab.internal.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/unicode.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
||||
typedef int (*out_f)(const char *, void *, size_t);
|
||||
typedef int (*emit_f)(out_f, void *, uint64_t);
|
||||
|
||||
static int __fmt_stoa_byte(out_f out, void *a, uint64_t c) {
|
||||
char buf[1] = {c};
|
||||
return out(buf, a, 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (!isascii(w)) w = _tpenc(w);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (_bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
w = _tpenc(kCp437[w & 0xFF]);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (_bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (isascii(w)) {
|
||||
w = _cescapec(w);
|
||||
} else {
|
||||
w = _tpenc(w);
|
||||
}
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (_bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to array.
|
||||
*
|
||||
* 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 __fmt()
|
||||
*/
|
||||
int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||
unsigned long flags, unsigned long precision,
|
||||
unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
wint_t wc;
|
||||
unsigned n;
|
||||
emit_f emit;
|
||||
char *p, buf[1];
|
||||
unsigned w, c, pad;
|
||||
bool justdobytes, ignorenul;
|
||||
|
||||
p = data;
|
||||
if (!p) {
|
||||
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
||||
signbit = 0;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
precision = min(strlen(p), precision);
|
||||
}
|
||||
}
|
||||
|
||||
ignorenul = false;
|
||||
justdobytes = false;
|
||||
if (signbit == 15 || signbit == 63) {
|
||||
if (flags & FLAGS_QUOTE) {
|
||||
emit = __fmt_stoa_quoted;
|
||||
ignorenul = flags & FLAGS_PRECISION;
|
||||
} else {
|
||||
emit = __fmt_stoa_wide;
|
||||
}
|
||||
} else if ((flags & FLAGS_HASH) && _weaken(kCp437)) {
|
||||
justdobytes = true;
|
||||
emit = __fmt_stoa_bing;
|
||||
ignorenul = flags & FLAGS_PRECISION;
|
||||
} else if (flags & FLAGS_QUOTE) {
|
||||
emit = __fmt_stoa_quoted;
|
||||
ignorenul = flags & FLAGS_PRECISION;
|
||||
} else {
|
||||
justdobytes = true;
|
||||
emit = __fmt_stoa_byte;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_PRECISION)) precision = -1;
|
||||
if (!(flags & FLAGS_PRECISION) || !ignorenul) {
|
||||
if (signbit == 63) {
|
||||
precision = wcsnlen((const wchar_t *)p, precision);
|
||||
} else if (signbit == 15) {
|
||||
precision = strnlen16((const char16_t *)p, precision);
|
||||
} else {
|
||||
precision = strnlen(p, precision);
|
||||
}
|
||||
}
|
||||
|
||||
pad = 0;
|
||||
if (width) {
|
||||
w = precision;
|
||||
if (signbit == 63) {
|
||||
if (_weaken(wcsnwidth)) {
|
||||
w = _weaken(wcsnwidth)((const wchar_t *)p, precision, 0);
|
||||
}
|
||||
} else if (signbit == 15) {
|
||||
if (_weaken(strnwidth16)) {
|
||||
w = _weaken(strnwidth16)((const char16_t *)p, precision, 0);
|
||||
}
|
||||
} else if (_weaken(strnwidth)) {
|
||||
w = _weaken(strnwidth)(p, precision, 0);
|
||||
}
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
w += 2 + (signbit == 63) + (signbit == 15);
|
||||
}
|
||||
if (w < width) {
|
||||
pad = width - w;
|
||||
}
|
||||
}
|
||||
|
||||
if (pad && !(flags & FLAGS_LEFT)) {
|
||||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
if (signbit == 63) {
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
if (justdobytes) {
|
||||
while (precision--) {
|
||||
wc = *p++ & 0xff;
|
||||
if (!wc && !ignorenul) break;
|
||||
if (emit(out, arg, wc) == -1) return -1;
|
||||
}
|
||||
} else {
|
||||
while (precision--) {
|
||||
if (signbit == 15) {
|
||||
wc = *(const char16_t *)p;
|
||||
if (!wc && !ignorenul) break;
|
||||
if (IsUcs2(wc)) {
|
||||
p += sizeof(char16_t);
|
||||
} else if (IsUtf16Cont(wc)) {
|
||||
p += sizeof(char16_t);
|
||||
continue;
|
||||
} else if (!precision) {
|
||||
break;
|
||||
} else {
|
||||
--precision;
|
||||
wc = MergeUtf16(wc, *(const char16_t *)p);
|
||||
}
|
||||
} else if (signbit == 63) {
|
||||
wc = *(const wint_t *)p;
|
||||
if (!wc && !ignorenul) break;
|
||||
p += sizeof(wint_t);
|
||||
if (!wc) break;
|
||||
} else {
|
||||
wc = *p++ & 0xff;
|
||||
if (!wc && !ignorenul) break;
|
||||
if (!isascii(wc)) {
|
||||
if (ThomPikeCont(wc)) continue;
|
||||
n = ThomPikeLen(wc) - 1;
|
||||
wc = ThomPikeByte(wc);
|
||||
if (n > precision) break;
|
||||
precision -= n;
|
||||
while (n--) {
|
||||
wc = ThomPikeMerge(wc, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (emit(out, arg, wc) == -1) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
if (pad && (flags & FLAGS_LEFT)) {
|
||||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef LIBC_ISYSTEM_STDIO_H_
|
||||
#define LIBC_ISYSTEM_STDIO_H_
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/fmt.h"
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
#ifndef LIBC_ISYSTEM_STDLIB_H_
|
||||
#define LIBC_ISYSTEM_STDLIB_H_
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/temp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/musl/crypt.h"
|
||||
#include "third_party/musl/rand48.h"
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
#include "libc/str/str.h"
|
||||
|
||||
dontinstrument void _log_errno(const char *file, int line, const char *form) {
|
||||
flogf(kLogWarn, file, line, NULL, PFLINK("%s → %s"), form, strerror(errno));
|
||||
flogf(kLogWarn, file, line, NULL, "%s → %s", form, strerror(errno));
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_MEM_FMT_H_
|
||||
#define COSMOPOLITAN_LIBC_MEM_FMT_H_
|
||||
#include "libc/fmt/pflink.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -8,11 +7,6 @@ int asprintf(char **, const char *, ...) printfesque(2)
|
|||
paramsnonnull((1, 2)) libcesque;
|
||||
int vasprintf(char **, const char *, va_list) paramsnonnull() libcesque;
|
||||
|
||||
#if defined(COSMO) && !defined(__cplusplus)
|
||||
#define asprintf(SP, FMT, ...) (asprintf)(SP, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vasprintf(SP, FMT, VA) (vasprintf)(SP, PFLINK(FMT), VA)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_MEM_FMT_H_ */
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- 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 2023 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/str/str.h"
|
||||
|
||||
/**
|
||||
* Converts byte to word-encoded C string literal representation.
|
||||
*/
|
||||
int _cescapec(int c) {
|
||||
switch ((c &= 255)) {
|
||||
case '\a':
|
||||
return '\\' | 'a' << 8;
|
||||
case '\b':
|
||||
return '\\' | 'b' << 8;
|
||||
case '\t':
|
||||
return '\\' | 't' << 8;
|
||||
case '\n':
|
||||
return '\\' | 'n' << 8;
|
||||
case '\v':
|
||||
return '\\' | 'v' << 8;
|
||||
case '\f':
|
||||
return '\\' | 'f' << 8;
|
||||
case '\r':
|
||||
return '\\' | 'r' << 8;
|
||||
case '"':
|
||||
return '\\' | '"' << 8;
|
||||
case '\'':
|
||||
return '\\' | '\'' << 8;
|
||||
case '\\':
|
||||
return '\\' | '\\' << 8;
|
||||
default:
|
||||
if (' ' <= c && c <= '~') {
|
||||
return c;
|
||||
} else {
|
||||
return '\\' | //
|
||||
('0' + (c >> 6)) << 8 | //
|
||||
('0' + ((c >> 3) & 7)) << 16 | //
|
||||
('0' + (c & 7)) << 24;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/sock/syslog.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/dprintf.h"
|
||||
#include "libc/stdio/dprintf.h"
|
||||
|
||||
/**
|
||||
* Formats string directly to file descriptor.
|
|
@ -1,17 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_DPRINTF_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_DPRINTF_H_
|
||||
#include "libc/fmt/pflink.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int dprintf(int, const char *, ...) printfesque(2) paramsnonnull((2));
|
||||
int vdprintf(int, const char *, va_list) paramsnonnull();
|
||||
|
||||
#if defined(COSMO) && !defined(__cplusplus)
|
||||
#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA)
|
||||
#endif /* GNU && !ANSI */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_DPRINTF_H_ */
|
|
@ -1,567 +0,0 @@
|
|||
/*-*- 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 (C) 1997, 1999, 2001 Lucent Technologies │
|
||||
│ All Rights Reserved │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and distribute this software and │
|
||||
│ its documentation for any purpose and without fee is hereby │
|
||||
│ granted, provided that the above copyright notice appear in all │
|
||||
│ copies and that both that the copyright notice and this │
|
||||
│ permission notice and warranty disclaimer appear in supporting │
|
||||
│ documentation, and that the name of Lucent or any of its entities │
|
||||
│ not be used in advertising or publicity pertaining to │
|
||||
│ distribution of the software without specific, written prior │
|
||||
│ permission. │
|
||||
│ │
|
||||
│ LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, │
|
||||
│ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. │
|
||||
│ IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY │
|
||||
│ SPECIAL, 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/fmt.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Floating-Point Formatting
|
||||
*
|
||||
* This implements most of ANSI C's printf floating-point directives.
|
||||
* omitting L, with %.0g and %.0G giving the shortest decimal string
|
||||
* that rounds to the number being converted, and with negative
|
||||
* precisions allowed for %f.
|
||||
*/
|
||||
|
||||
struct FPBits {
|
||||
uint32_t bits[4];
|
||||
const FPI *fpi;
|
||||
int sign;
|
||||
int ex; // exponent
|
||||
int kind;
|
||||
};
|
||||
|
||||
union U {
|
||||
double d;
|
||||
uint64_t q;
|
||||
long double ld;
|
||||
uint32_t ui[4];
|
||||
uint16_t us[5];
|
||||
};
|
||||
|
||||
static const FPI kFpiDbl = {
|
||||
.nbits = DBL_MANT_DIG,
|
||||
.emin = 3 - DBL_MAX_EXP - DBL_MANT_DIG,
|
||||
.emax = DBL_MAX_EXP - DBL_MANT_DIG,
|
||||
.rounding = FPI_Round_near,
|
||||
.sudden_underflow = 0,
|
||||
};
|
||||
|
||||
static const FPI kFpiLdbl = {
|
||||
.nbits = LDBL_MANT_DIG,
|
||||
.emin = 3 - LDBL_MAX_EXP - LDBL_MANT_DIG,
|
||||
.emax = LDBL_MAX_EXP - LDBL_MANT_DIG,
|
||||
.rounding = FPI_Round_near,
|
||||
.sudden_underflow = 0,
|
||||
};
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {
|
||||
{"INF", "inf"},
|
||||
{"NAN", "nan"},
|
||||
};
|
||||
|
||||
static void dfpbits(union U *u, struct FPBits *b) {
|
||||
int ex, i;
|
||||
b->fpi = &kFpiDbl;
|
||||
b->sign = u->ui[1] & 0x80000000L;
|
||||
b->bits[1] = u->ui[1] & 0xfffff;
|
||||
b->bits[0] = u->ui[0];
|
||||
if ((ex = (u->ui[1] & 0x7ff00000L) >> 20) != 0) {
|
||||
if (ex != 0x7ff) {
|
||||
i = STRTOG_Normal;
|
||||
b->bits[1] |= 1 << (52 - 32); // set lowest exponent bit
|
||||
} else if (b->bits[0] | b->bits[1]) {
|
||||
i = STRTOG_NaN;
|
||||
} else {
|
||||
i = STRTOG_Infinite;
|
||||
}
|
||||
} else if (b->bits[0] | b->bits[1]) {
|
||||
i = STRTOG_Denormal;
|
||||
ex = 1;
|
||||
} else {
|
||||
i = STRTOG_Zero;
|
||||
}
|
||||
b->kind = i;
|
||||
b->ex = ex - (0x3ff + 52);
|
||||
}
|
||||
|
||||
static void ldfpbits(union U *u, struct FPBits *b) {
|
||||
#if LDBL_MANT_DIG == 53
|
||||
dfpbits(u, b);
|
||||
#else
|
||||
int ex, i;
|
||||
uint16_t sex;
|
||||
#if LDBL_MANT_DIG == 64
|
||||
b->bits[3] = 0;
|
||||
b->bits[2] = 0;
|
||||
b->bits[1] = ((unsigned)u->us[3] << 16) | u->us[2];
|
||||
b->bits[0] = ((unsigned)u->us[1] << 16) | u->us[0];
|
||||
sex = u->us[4];
|
||||
#elif LDBL_MANT_DIG == 113
|
||||
b->bits[3] = u->ui[3] & 0xffff;
|
||||
b->bits[2] = u->ui[2];
|
||||
b->bits[1] = u->ui[1];
|
||||
b->bits[0] = u->ui[0];
|
||||
sex = u->ui[3] >> 16;
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
b->fpi = &kFpiLdbl;
|
||||
b->sign = sex & 0x8000;
|
||||
if ((ex = sex & 0x7fff) != 0) {
|
||||
if (ex != 0x7fff) {
|
||||
i = STRTOG_Normal;
|
||||
#if LDBL_MANT_DIG == 113
|
||||
b->bits[3] |= 1 << (112 - 32 * 3); // set lowest exponent bit
|
||||
#endif
|
||||
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
|
||||
i = STRTOG_NaN;
|
||||
} else {
|
||||
i = STRTOG_Infinite;
|
||||
}
|
||||
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
|
||||
i = STRTOG_Denormal;
|
||||
ex = 1;
|
||||
} else {
|
||||
i = STRTOG_Zero;
|
||||
}
|
||||
b->kind = i;
|
||||
b->ex = ex - (0x3fff + (LDBL_MANT_DIG - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns number of hex digits minus 1, or 0 for zero
|
||||
static int fpiprec(struct FPBits *b) {
|
||||
FPI *fpi;
|
||||
int i, j, k, m;
|
||||
uint32_t *bits;
|
||||
if (b->kind == STRTOG_Zero) return (b->ex = 0);
|
||||
fpi = b->fpi;
|
||||
bits = b->bits;
|
||||
for (k = (fpi->nbits - 1) >> 2; k > 0; --k) {
|
||||
if ((bits[k >> 3] >> 4 * (k & 7)) & 0xf) {
|
||||
m = k >> 3;
|
||||
for (i = 0; i <= m; ++i)
|
||||
if (bits[i]) {
|
||||
if (i > 0) {
|
||||
k -= 8 * i;
|
||||
b->ex += 32 * i;
|
||||
for (j = i; j <= m; ++j) {
|
||||
bits[j - i] = bits[j];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < 28 && !((bits[0] >> i) & 0xf); i += 4) donothing;
|
||||
if (i) {
|
||||
b->ex += i;
|
||||
m = k >> 3;
|
||||
k -= (i >> 2);
|
||||
for (j = 0;; ++j) {
|
||||
bits[j] >>= i;
|
||||
if (j == m) break;
|
||||
bits[j] |= bits[j + 1] << (32 - i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
// round to prec hex digits after the "."
|
||||
// prec1 = incoming precision (after ".")
|
||||
static int bround(struct FPBits *b, int prec, int prec1) {
|
||||
uint32_t *bits, t;
|
||||
int i, inc, j, k, m, n;
|
||||
m = prec1 - prec;
|
||||
bits = b->bits;
|
||||
inc = 0;
|
||||
k = m - 1;
|
||||
if ((t = bits[k >> 3] >> (j = (k & 7) * 4)) & 8) {
|
||||
if (t & 7) goto inc1;
|
||||
if (j && bits[k >> 3] << (32 - j)) goto inc1;
|
||||
while (k >= 8) {
|
||||
k -= 8;
|
||||
if (bits[k >> 3]) {
|
||||
inc1:
|
||||
inc = 1;
|
||||
goto haveinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
haveinc:
|
||||
b->ex += m * 4;
|
||||
i = m >> 3;
|
||||
k = prec1 >> 3;
|
||||
j = i;
|
||||
if ((n = 4 * (m & 7)))
|
||||
for (;; ++j) {
|
||||
bits[j - i] = bits[j] >> n;
|
||||
if (j == k) break;
|
||||
bits[j - i] |= bits[j + 1] << (32 - n);
|
||||
}
|
||||
else
|
||||
for (;; ++j) {
|
||||
bits[j - i] = bits[j];
|
||||
if (j == k) break;
|
||||
}
|
||||
k = prec >> 3;
|
||||
if (inc) {
|
||||
for (j = 0; !(++bits[j] & 0xffffffff); ++j) donothing;
|
||||
if (j > k) {
|
||||
onebit:
|
||||
bits[0] = 1;
|
||||
b->ex += 4 * prec;
|
||||
return 1;
|
||||
}
|
||||
if ((j = prec & 7) < 7 && bits[k] >> (j + 1) * 4) goto onebit;
|
||||
}
|
||||
for (i = 0; !(bits[i >> 3] & (0xf << 4 * (i & 7))); ++i) donothing;
|
||||
if (i) {
|
||||
b->ex += 4 * i;
|
||||
prec -= i;
|
||||
j = i >> 3;
|
||||
i &= 7;
|
||||
i *= 4;
|
||||
for (m = j;; ++m) {
|
||||
bits[m - j] = bits[m] >> i;
|
||||
if (m == k) break;
|
||||
bits[m - j] |= bits[m + 1] << (32 - i);
|
||||
}
|
||||
}
|
||||
return prec;
|
||||
}
|
||||
|
||||
int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||
int flags, int prec, int sign, int width, bool longdouble,
|
||||
char qchar, unsigned char signbit, const char *alphabet,
|
||||
va_list va) {
|
||||
double x;
|
||||
union U u;
|
||||
struct FPBits fpb;
|
||||
char *s, *q, *se, *s0, special[8];
|
||||
int c, k, i1, ui, bw, rc, bex, sgn, prec1, decpt, consumed;
|
||||
x = 0;
|
||||
switch (d) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (!longdouble) {
|
||||
x = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
s = s0 = dtoa(x, 3, prec, &decpt, &fpb.sign, &se);
|
||||
if (decpt == 9999) {
|
||||
if (s && s[0] == 'N') {
|
||||
fpb.kind = STRTOG_NaN;
|
||||
} else {
|
||||
fpb.kind = STRTOG_Infinite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
s = s0 =
|
||||
gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, 3, prec, &decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
if (s0) freedtoa(s0);
|
||||
bzero(special, sizeof(special));
|
||||
s = q = special;
|
||||
if (fpb.sign) {
|
||||
*q++ = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
*q++ = '+';
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
*q++ = ' ';
|
||||
}
|
||||
memcpy(q, kSpecialFloats[fpb.kind == STRTOG_NaN][d >= 'a'], 4);
|
||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_HASH | FLAGS_SPACE);
|
||||
prec = 0;
|
||||
rc = __fmt_stoa(out, arg, s, flags, prec, width, signbit, qchar);
|
||||
if (rc == -1) return -1;
|
||||
return consumed;
|
||||
}
|
||||
FormatReal:
|
||||
if (fpb.sign /* && (x || sign) */) 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 || (flags & FLAGS_HASH)) --width;
|
||||
}
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if ((flags & FLAGS_ZEROPAD)) {
|
||||
if (sign) __FMT_PUT(sign);
|
||||
sign = 0;
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else
|
||||
do __FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
if (decpt <= 0) {
|
||||
__FMT_PUT('0');
|
||||
if (prec > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
while (decpt < 0) {
|
||||
__FMT_PUT('0');
|
||||
prec--;
|
||||
decpt++;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
} while (--decpt > 0);
|
||||
if (prec > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
}
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
if (s0) freedtoa(s0);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
case 'g':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (prec < 1) prec = 1;
|
||||
if (!longdouble) {
|
||||
x = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
s = s0 = dtoa(x, 2, prec, &decpt, &fpb.sign, &se);
|
||||
if (decpt == 9999) {
|
||||
if (s && s[0] == 'N') {
|
||||
fpb.kind = STRTOG_NaN;
|
||||
} else {
|
||||
fpb.kind = STRTOG_Infinite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec,
|
||||
&decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) goto Format9999;
|
||||
c = se - s;
|
||||
prec1 = prec;
|
||||
if (!prec) {
|
||||
prec = c;
|
||||
prec1 = c + (s[1] || (flags & FLAGS_HASH) ? 5 : 4);
|
||||
// %.0g gives 10 rather than 1e1
|
||||
}
|
||||
if (decpt > -4 && decpt <= prec1) {
|
||||
if ((flags & FLAGS_HASH))
|
||||
prec -= decpt;
|
||||
else
|
||||
prec = c - decpt;
|
||||
if (prec < 0) prec = 0;
|
||||
goto FormatReal;
|
||||
}
|
||||
d -= 2;
|
||||
if (!(flags & FLAGS_HASH) && prec > c) prec = c;
|
||||
--prec;
|
||||
goto FormatExpo;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (prec < 0) prec = 0;
|
||||
if (!longdouble) {
|
||||
x = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
s = s0 = dtoa(x, 2, prec + 1, &decpt, &fpb.sign, &se);
|
||||
if (decpt == 9999) {
|
||||
if (s && s[0] == 'N') {
|
||||
fpb.kind = STRTOG_NaN;
|
||||
} else {
|
||||
fpb.kind = STRTOG_Infinite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec,
|
||||
&decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) goto Format9999;
|
||||
FormatExpo:
|
||||
if (fpb.sign /* && (x || sign) */) sign = '-';
|
||||
if ((width -= prec + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec || (flags & FLAGS_HASH)) --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) __FMT_PUT(sign);
|
||||
sign = 0;
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else
|
||||
do __FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT(*s++);
|
||||
if (prec || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s))
|
||||
s++;
|
||||
else
|
||||
c = '0';
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
__FMT_PUT(d);
|
||||
if (decpt < 0) {
|
||||
__FMT_PUT('-');
|
||||
decpt = -decpt;
|
||||
} else
|
||||
__FMT_PUT('+');
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) donothing;
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
__FMT_PUT(i1 + '0');
|
||||
if (--c <= 0) break;
|
||||
decpt -= i1 * k;
|
||||
decpt *= 10;
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
freedtoa(s0);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
alphabet = "0123456789ABCDEFPX";
|
||||
goto FormatBinary;
|
||||
case 'a':
|
||||
alphabet = "0123456789abcdefpx";
|
||||
FormatBinary:
|
||||
if (longdouble) {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
} else {
|
||||
u.d = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
dfpbits(&u, &fpb);
|
||||
}
|
||||
if (fpb.kind == STRTOG_Infinite || fpb.kind == STRTOG_NaN) {
|
||||
s0 = 0;
|
||||
goto Format9999;
|
||||
}
|
||||
prec1 = fpiprec(&fpb);
|
||||
if ((flags & FLAGS_PRECISION) && prec < prec1) {
|
||||
prec1 = bround(&fpb, prec, prec1);
|
||||
}
|
||||
bw = 1;
|
||||
bex = fpb.ex + 4 * prec1;
|
||||
if (bex) {
|
||||
if ((i1 = bex) < 0) i1 = -i1;
|
||||
while (i1 >= 10) {
|
||||
++bw;
|
||||
i1 /= 10;
|
||||
}
|
||||
}
|
||||
if (fpb.sign /* && (sign || fpb.kind != STRTOG_Zero) */) {
|
||||
sign = '-';
|
||||
}
|
||||
if ((width -= bw + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec1 || (flags & FLAGS_HASH)) --width;
|
||||
}
|
||||
if ((width -= prec1) > 0 && !(flags & FLAGS_LEFT) &&
|
||||
!(flags & FLAGS_ZEROPAD)) {
|
||||
do __FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT('0');
|
||||
__FMT_PUT(alphabet[17]);
|
||||
if ((flags & FLAGS_ZEROPAD) && width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
}
|
||||
i1 = prec1 & 7;
|
||||
k = prec1 >> 3;
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
if (prec1 > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
if (prec1 > 0) {
|
||||
prec -= prec1;
|
||||
while (prec1 > 0) {
|
||||
if (--i1 < 0) {
|
||||
if (--k < 0) break;
|
||||
i1 = 7;
|
||||
}
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
--prec1;
|
||||
}
|
||||
if ((flags & FLAGS_HASH) && prec > 0) {
|
||||
do __FMT_PUT(0);
|
||||
while (--prec > 0);
|
||||
}
|
||||
}
|
||||
__FMT_PUT(alphabet[16]);
|
||||
if (bex < 0) {
|
||||
__FMT_PUT('-');
|
||||
bex = -bex;
|
||||
} else
|
||||
__FMT_PUT('+');
|
||||
for (c = 1; 10 * c <= bex; c *= 10) donothing;
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
__FMT_PUT('0' + i1);
|
||||
if (!--bw) break;
|
||||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
return consumed;
|
||||
}
|
1375
libc/stdio/fmt.c
Normal file
1375
libc/stdio/fmt.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,5 @@
|
|||
#ifndef _STDIO_H
|
||||
#define _STDIO_H
|
||||
#include "libc/fmt/pflink.h"
|
||||
|
||||
#define L_ctermid 20
|
||||
#define FILENAME_MAX PATH_MAX
|
||||
|
@ -162,25 +161,6 @@ int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
|
|||
int vfprintf_unlocked(FILE *, const char *, va_list)
|
||||
paramsnonnull() dontthrow nocallback;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § standard i/o » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#if defined(COSMO) && !defined(__cplusplus)
|
||||
/* clang-format off */
|
||||
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vprintf(FMT, VA) (vprintf)(PFLINK(FMT), VA)
|
||||
#define fprintf(F, FMT, ...) (fprintf)(F, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vfprintf(F, FMT, VA) (vfprintf)(F, PFLINK(FMT), VA)
|
||||
#define fprintf_unlocked(F, FMT, ...) (fprintf_unlocked)(F, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vfprintf_unlocked(F, FMT, VA) (vfprintf_unlocked)(F, PFLINK(FMT), VA)
|
||||
#define vscanf(FMT, VA) (vscanf)(SFLINK(FMT), VA)
|
||||
#define scanf(FMT, ...) (scanf)(SFLINK(FMT), ##__VA_ARGS__)
|
||||
#define fscanf(F, FMT, ...) (fscanf)(F, SFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vfscanf(F, FMT, VA) (vfscanf)(F, SFLINK(FMT), VA)
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* _STDIO_H */
|
||||
|
|
|
@ -26,7 +26,6 @@ int ispunct(int);
|
|||
int toupper(int);
|
||||
int toascii(int);
|
||||
int hextoint(int);
|
||||
int _cescapec(int);
|
||||
|
||||
int iswalnum(wint_t);
|
||||
int iswalpha(wint_t);
|
||||
|
|
|
@ -29,13 +29,14 @@ LIBC_TIME_A_CHECKS = \
|
|||
|
||||
LIBC_TIME_A_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_INTRIN \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_X_XASPRINTF_H_
|
||||
#define COSMOPOLITAN_LIBC_X_XASPRINTF_H_
|
||||
#include "libc/fmt/pflink.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -9,11 +8,6 @@ char *xasprintf(const char *, ...) printfesque(1) paramsnonnull((1))
|
|||
char *xvasprintf(const char *, va_list) paramsnonnull()
|
||||
returnspointerwithnoaliases dontthrow nocallback dontdiscard returnsnonnull;
|
||||
|
||||
#if defined(COSMO) && !defined(__cplusplus)
|
||||
#define xasprintf(FMT, ...) (xasprintf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define xvasprintf(FMT, VA) (xvasprintf)(PFLINK(FMT), VA)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_X_XASPRINTF_H_ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue