mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 11:18: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
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
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,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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue