Remove printf() linking hack

This commit is contained in:
Justine Tunney 2023-06-17 10:13:50 -07:00
parent ba03cd95c5
commit b881c0ec9e
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
107 changed files with 1520 additions and 2577 deletions

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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_ */

View file

@ -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_ */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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_ */

View file

@ -1,38 +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.h"
/**
* Formats string to buffer.
*
* @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 __fmt() and printf() for detailed documentation
* @asyncsignalsafe
* @vforksafe
*/
int(snprintf)(char* buf, size_t count, const char* fmt, ...) {
int rc;
va_list va;
va_start(va, fmt);
rc = (vsnprintf)(buf, count, fmt, va);
va_end(va);
return rc;
}

View file

@ -1,38 +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.h"
#include "libc/limits.h"
#include "libc/log/log.h"
/**
* Formats string to buffer that's hopefully large enough.
*
* @see __fmt() and printf() for detailed documentation
* @see snprintf() for same w/ buf size param
* @asyncsignalsafe
* @vforksafe
*/
int(sprintf)(char *buf, const char *fmt, ...) {
int rc;
va_list va;
va_start(va, fmt);
rc = (vsnprintf)(buf, INT_MAX, fmt, va);
va_end(va);
return rc;
}

View file

@ -1,33 +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/dce.h"
#include "libc/fmt/fmt.h"
/**
* String decoder.
* @see libc/fmt/vcscanf.h (for docs and implementation)
*/
int(sscanf)(const char *str, const char *fmt, ...) {
int rc;
va_list va;
va_start(va, fmt);
rc = (vsscanf)(str, fmt, va);
va_end(va);
return rc;
}

View file

@ -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;
}

View file

@ -1,25 +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 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
int swprintf(wchar_t* ws, size_t n, const wchar_t* format, ...) {
kprintf("error: swprintf() not supported yet by cosmo libc sorry!\n");
_Exit(1);
}

View file

@ -1,310 +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"
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/str/tpdecodecb.internal.h"
#include "libc/str/utf16.h"
#include "libc/sysv/errfuns.h"
/**
* String / file / stream decoder.
*
* This scanf implementation is able to tokenize strings containing
* 8-bit through 128-bit integers (with validation), floating point
* numbers, etc. It can also be used to convert UTF-8 to UTF-16/32.
*
* - `%d` parses integer
* - `%ms` parses string allocating buffer assigning pointer
*
* @param callback supplies UTF-8 characters using -1 sentinel
* @param fmt is a computer program embedded inside a c string, written
* in a domain-specific programming language that, by design, lacks
* Turing-completeness
* @param va points to the variadic argument state
* @see libc/fmt/pflink.h (dynamic memory is not a requirement)
*/
int vcscanf(int callback(void *), int unget(int, void *), void *arg,
const char *fmt, va_list va) {
struct FreeMe {
struct FreeMe *next;
void *ptr;
} *freeme = NULL;
const unsigned char *p = (const unsigned char *)fmt;
unsigned i = 0;
int items = 0;
int c = callback(arg);
while (c != -1) {
switch (p[i++]) {
case '\0':
if (c != -1 && unget) {
unget(c, arg);
}
goto Done;
case ' ':
case '\t':
case '\n':
case '\r':
case '\v':
while (isspace(c)) {
c = callback(arg);
}
break;
case '%': {
uint128_t number;
void *buf;
size_t bufsize;
unsigned width = 0;
unsigned char bits = 32;
unsigned char charbytes = sizeof(char);
unsigned char diglet;
unsigned char base;
unsigned char prefix;
bool rawmode = false;
bool issigned = false;
bool ismalloc = false;
bool isneg = false;
bool thousands = false;
bool discard = false;
for (;;) {
switch (p[i++]) {
case '%': /* %% → % */
goto NonDirectiveCharacter;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
width *= 10;
width += p[i - 1] - '0';
break;
case '*':
discard = true;
break;
case 'm':
ismalloc = true;
break;
case 'c':
rawmode = true;
if (!width) width = 1;
/* εpsilon transition */
case 's':
goto DecodeString;
case '\'':
thousands = true;
break;
case 'j': /* j=64-bit jj=128-bit */
if (bits < 64) {
bits = 64;
} else {
bits = 128;
}
break;
case 'l': /* long */
case 'L': /* loooong */
charbytes = sizeof(wchar_t);
/* fallthrough */
case 't': /* ptrdiff_t */
case 'Z': /* size_t */
case 'z': /* size_t */
bits = 64;
break;
case 'h': /* short and char */
charbytes = sizeof(char16_t);
bits >>= 1;
break;
case 'b': /* binary */
base = 2;
prefix = 'b';
goto ConsumeBasePrefix;
case 'p': /* pointer (NexGen32e) */
bits = 48;
/* fallthrough */
case 'x':
case 'X': /* hexadecimal */
base = 16;
prefix = 'x';
goto ConsumeBasePrefix;
case 'o': /* octal */
base = 8;
goto DecodeNumber;
case 'd': /* decimal */
case 'n': /* TODO(jart): flexidecimal */
issigned = true;
if (c == '+' || (isneg = c == '-')) {
c = callback(arg);
}
/* εpsilon transition */
case 'u':
base = 10;
goto DecodeNumber;
default:
items = einval();
goto Done;
}
}
ConsumeBasePrefix:
if (c == '0') {
c = callback(arg);
if (c == prefix || c == prefix + ('a' - 'A')) {
c = callback(arg);
} else if (c == -1) {
c = '0';
}
}
DecodeNumber:
if (c != -1) {
number = 0;
width = !width ? bits : width;
do {
diglet = kBase36[(unsigned char)c];
if (1 <= diglet && diglet <= base) {
width -= 1;
number *= base;
number += diglet - 1;
} else if (thousands && diglet == ',') {
/* ignore */
} else {
break;
}
} while ((c = callback(arg)) != -1 && width > 0);
if (!discard) {
uint128_t bane = (uint128_t)1 << (bits - 1);
if (!(number & ~((bane - 1) | (issigned ? 0 : bane))) ||
(issigned && number == bane /* two's complement bane */)) {
++items;
} else {
items = erange();
goto Done;
}
if (issigned && isneg) {
number = ~number + 1;
}
void *out = va_arg(va, void *);
switch (bits) {
case sizeof(uint128_t) * CHAR_BIT:
*(uint128_t *)out = number;
break;
case 48:
case 64:
*(uint64_t *)out = (uint64_t)number;
break;
case 32:
*(uint32_t *)out = (uint32_t)number;
break;
case 16:
*(uint16_t *)out = (uint16_t)number;
break;
case 8:
default:
*(uint8_t *)out = (uint8_t)number;
break;
}
}
}
continue;
DecodeString:
bufsize = !width ? 32 : rawmode ? width : width + 1;
if (discard) {
buf = NULL;
} else if (ismalloc) {
buf = _weaken(malloc)(bufsize * charbytes);
struct FreeMe *entry;
if (buf && (entry = _weaken(calloc)(1, sizeof(struct FreeMe)))) {
entry->ptr = buf;
entry->next = freeme;
freeme = entry;
}
} else {
buf = va_arg(va, void *);
}
if (buf) {
size_t j = 0;
for (;;) {
if (ismalloc && !width && j + 2 + 1 >= bufsize &&
!_weaken(__grow)(&buf, &bufsize, charbytes, 0)) {
width = bufsize - 1;
}
if (c != -1 && j + !rawmode < bufsize && (rawmode || !isspace(c))) {
if (charbytes == 1) {
((unsigned char *)buf)[j++] = (unsigned char)c;
c = callback(arg);
} else if (tpdecodecb((wint_t *)&c, c, (void *)callback, arg) !=
-1) {
if (charbytes == sizeof(char16_t)) {
size_t k = 0;
unsigned w = EncodeUtf16(c);
do {
if ((j + 1) * 2 < bufsize) {
((char16_t *)buf)[j++] = w;
}
} while ((w >>= 16));
} else {
((wchar_t *)buf)[j++] = (wchar_t)c;
}
c = callback(arg);
}
} else {
if (!rawmode && j < bufsize) {
if (charbytes == sizeof(char)) {
((unsigned char *)buf)[j] = '\0';
} else if (charbytes == sizeof(char16_t)) {
((char16_t *)buf)[j] = u'\0';
} else if (charbytes == sizeof(wchar_t)) {
((wchar_t *)buf)[j] = L'\0';
}
}
break;
}
}
++items;
if (ismalloc) {
*va_arg(va, char **) = buf;
}
} else {
do {
if (isspace(c)) break;
} while ((c = callback(arg)) != -1);
}
break;
}
default:
NonDirectiveCharacter:
c = (c == p[i - 1]) ? callback(arg) : -1;
break;
}
}
Done:
while (freeme && _weaken(free)) {
struct FreeMe *entry = freeme;
freeme = entry->next;
if (items == -1) _weaken(free)(entry->ptr);
_weaken(free)(entry);
}
return items;
}

View file

@ -1,64 +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/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
struct SprintfStr {
char *p;
size_t i;
size_t n;
};
static int vsnprintfputchar(const char *s, struct SprintfStr *t, size_t n) {
if (n) {
if (n == 1 && t->i < t->n) {
t->p[t->i] = s[0];
} else if (t->i + n <= t->n) {
memcpy(t->p + t->i, s, n);
} else if (t->i < t->n) {
memcpy(t->p + t->i, s, t->n - t->i);
}
t->i += n;
}
return 0;
}
/**
* Formats string to buffer w/ preexisting vararg state.
*
* @param buf stores output and a NUL-terminator is always written,
* provided buf!=NULL && size!=0
* @param size is byte capacity buf
* @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 __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};
__fmt(vsnprintfputchar, &str, fmt, va);
if (str.n) str.p[MIN(str.i, str.n - 1)] = '\0';
return str.i;
}

View file

@ -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/fmt.h"
#include "libc/limits.h"
/**
* Formats string to buffer hopefully large enough w/ vararg state.
*
* @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) {
return (vsnprintf)(buf, INT_MAX, fmt, va);
}

View file

@ -1,50 +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/dce.h"
#include "libc/fmt/fmt.h"
struct StringScannerState {
const unsigned char *s;
size_t i;
};
static int vsscanfcb(void *arg) {
int res;
struct StringScannerState *state;
state = arg;
if ((res = state->s[state->i])) {
state->i++;
} else {
res = -1;
}
return res;
}
/**
* Decodes string.
*
* @see libc/fmt/vcscanf.h (for docs and implementation)
* @note to offer the best performance, we assume small codebases
* needing vsscanf() won't need sscanf() too; and as such, there's
* a small code size penalty to using both
*/
int(vsscanf)(const char *str, const char *fmt, va_list va) {
struct StringScannerState state = {(const unsigned char *)str, 0};
return vcscanf(vsscanfcb, NULL, &state, fmt, va);
}