mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-30 08: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
38
libc/stdio/asprintf.c
Normal file
38
libc/stdio/asprintf.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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/mem/fmt.h"
|
||||
|
||||
/**
|
||||
* Formats string, allocating needed memory.
|
||||
*
|
||||
* @param *strp is output-only and must be free'd, even on error; this
|
||||
* behavior was adopted to help put your needs first in terms of
|
||||
* portability, since that's guaranteed to work with all libraries
|
||||
* @return bytes written (excluding NUL) or -1 w/ errno
|
||||
* @see xasprintf() for a better API
|
||||
* @threadsafe
|
||||
*/
|
||||
int(asprintf)(char **strp, const char *fmt, ...) {
|
||||
int res;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = (vasprintf)(strp, fmt, va);
|
||||
va_end(va);
|
||||
return res;
|
||||
}
|
31
libc/stdio/dprintf.c
Normal file
31
libc/stdio/dprintf.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ 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/stdio/dprintf.h"
|
||||
|
||||
/**
|
||||
* Formats string directly to file descriptor.
|
||||
*/
|
||||
int(dprintf)(int fd, const char *fmt, ...) {
|
||||
int rc;
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
rc = (vdprintf)(fd, fmt, va);
|
||||
va_end(va);
|
||||
return rc;
|
||||
}
|
11
libc/stdio/dprintf.h
Normal file
11
libc/stdio/dprintf.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_DPRINTF_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_DPRINTF_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int dprintf(int, const char *, ...) printfesque(2) paramsnonnull((2));
|
||||
int vdprintf(int, const char *, va_list) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_DPRINTF_H_ */
|
|
@ -1,567 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright (C) 1997, 1999, 2001 Lucent Technologies │
|
||||
│ All Rights Reserved │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and distribute this software and │
|
||||
│ its documentation for any purpose and without fee is hereby │
|
||||
│ granted, provided that the above copyright notice appear in all │
|
||||
│ copies and that both that the copyright notice and this │
|
||||
│ permission notice and warranty disclaimer appear in supporting │
|
||||
│ documentation, and that the name of Lucent or any of its entities │
|
||||
│ not be used in advertising or publicity pertaining to │
|
||||
│ distribution of the software without specific, written prior │
|
||||
│ permission. │
|
||||
│ │
|
||||
│ LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, │
|
||||
│ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. │
|
||||
│ IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY │
|
||||
│ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES │
|
||||
│ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER │
|
||||
│ IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, │
|
||||
│ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF │
|
||||
│ THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmt.internal.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Floating-Point Formatting
|
||||
*
|
||||
* This implements most of ANSI C's printf floating-point directives.
|
||||
* omitting L, with %.0g and %.0G giving the shortest decimal string
|
||||
* that rounds to the number being converted, and with negative
|
||||
* precisions allowed for %f.
|
||||
*/
|
||||
|
||||
struct FPBits {
|
||||
uint32_t bits[4];
|
||||
const FPI *fpi;
|
||||
int sign;
|
||||
int ex; // exponent
|
||||
int kind;
|
||||
};
|
||||
|
||||
union U {
|
||||
double d;
|
||||
uint64_t q;
|
||||
long double ld;
|
||||
uint32_t ui[4];
|
||||
uint16_t us[5];
|
||||
};
|
||||
|
||||
static const FPI kFpiDbl = {
|
||||
.nbits = DBL_MANT_DIG,
|
||||
.emin = 3 - DBL_MAX_EXP - DBL_MANT_DIG,
|
||||
.emax = DBL_MAX_EXP - DBL_MANT_DIG,
|
||||
.rounding = FPI_Round_near,
|
||||
.sudden_underflow = 0,
|
||||
};
|
||||
|
||||
static const FPI kFpiLdbl = {
|
||||
.nbits = LDBL_MANT_DIG,
|
||||
.emin = 3 - LDBL_MAX_EXP - LDBL_MANT_DIG,
|
||||
.emax = LDBL_MAX_EXP - LDBL_MANT_DIG,
|
||||
.rounding = FPI_Round_near,
|
||||
.sudden_underflow = 0,
|
||||
};
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {
|
||||
{"INF", "inf"},
|
||||
{"NAN", "nan"},
|
||||
};
|
||||
|
||||
static void dfpbits(union U *u, struct FPBits *b) {
|
||||
int ex, i;
|
||||
b->fpi = &kFpiDbl;
|
||||
b->sign = u->ui[1] & 0x80000000L;
|
||||
b->bits[1] = u->ui[1] & 0xfffff;
|
||||
b->bits[0] = u->ui[0];
|
||||
if ((ex = (u->ui[1] & 0x7ff00000L) >> 20) != 0) {
|
||||
if (ex != 0x7ff) {
|
||||
i = STRTOG_Normal;
|
||||
b->bits[1] |= 1 << (52 - 32); // set lowest exponent bit
|
||||
} else if (b->bits[0] | b->bits[1]) {
|
||||
i = STRTOG_NaN;
|
||||
} else {
|
||||
i = STRTOG_Infinite;
|
||||
}
|
||||
} else if (b->bits[0] | b->bits[1]) {
|
||||
i = STRTOG_Denormal;
|
||||
ex = 1;
|
||||
} else {
|
||||
i = STRTOG_Zero;
|
||||
}
|
||||
b->kind = i;
|
||||
b->ex = ex - (0x3ff + 52);
|
||||
}
|
||||
|
||||
static void ldfpbits(union U *u, struct FPBits *b) {
|
||||
#if LDBL_MANT_DIG == 53
|
||||
dfpbits(u, b);
|
||||
#else
|
||||
int ex, i;
|
||||
uint16_t sex;
|
||||
#if LDBL_MANT_DIG == 64
|
||||
b->bits[3] = 0;
|
||||
b->bits[2] = 0;
|
||||
b->bits[1] = ((unsigned)u->us[3] << 16) | u->us[2];
|
||||
b->bits[0] = ((unsigned)u->us[1] << 16) | u->us[0];
|
||||
sex = u->us[4];
|
||||
#elif LDBL_MANT_DIG == 113
|
||||
b->bits[3] = u->ui[3] & 0xffff;
|
||||
b->bits[2] = u->ui[2];
|
||||
b->bits[1] = u->ui[1];
|
||||
b->bits[0] = u->ui[0];
|
||||
sex = u->ui[3] >> 16;
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
b->fpi = &kFpiLdbl;
|
||||
b->sign = sex & 0x8000;
|
||||
if ((ex = sex & 0x7fff) != 0) {
|
||||
if (ex != 0x7fff) {
|
||||
i = STRTOG_Normal;
|
||||
#if LDBL_MANT_DIG == 113
|
||||
b->bits[3] |= 1 << (112 - 32 * 3); // set lowest exponent bit
|
||||
#endif
|
||||
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
|
||||
i = STRTOG_NaN;
|
||||
} else {
|
||||
i = STRTOG_Infinite;
|
||||
}
|
||||
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
|
||||
i = STRTOG_Denormal;
|
||||
ex = 1;
|
||||
} else {
|
||||
i = STRTOG_Zero;
|
||||
}
|
||||
b->kind = i;
|
||||
b->ex = ex - (0x3fff + (LDBL_MANT_DIG - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns number of hex digits minus 1, or 0 for zero
|
||||
static int fpiprec(struct FPBits *b) {
|
||||
FPI *fpi;
|
||||
int i, j, k, m;
|
||||
uint32_t *bits;
|
||||
if (b->kind == STRTOG_Zero) return (b->ex = 0);
|
||||
fpi = b->fpi;
|
||||
bits = b->bits;
|
||||
for (k = (fpi->nbits - 1) >> 2; k > 0; --k) {
|
||||
if ((bits[k >> 3] >> 4 * (k & 7)) & 0xf) {
|
||||
m = k >> 3;
|
||||
for (i = 0; i <= m; ++i)
|
||||
if (bits[i]) {
|
||||
if (i > 0) {
|
||||
k -= 8 * i;
|
||||
b->ex += 32 * i;
|
||||
for (j = i; j <= m; ++j) {
|
||||
bits[j - i] = bits[j];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < 28 && !((bits[0] >> i) & 0xf); i += 4) donothing;
|
||||
if (i) {
|
||||
b->ex += i;
|
||||
m = k >> 3;
|
||||
k -= (i >> 2);
|
||||
for (j = 0;; ++j) {
|
||||
bits[j] >>= i;
|
||||
if (j == m) break;
|
||||
bits[j] |= bits[j + 1] << (32 - i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
// round to prec hex digits after the "."
|
||||
// prec1 = incoming precision (after ".")
|
||||
static int bround(struct FPBits *b, int prec, int prec1) {
|
||||
uint32_t *bits, t;
|
||||
int i, inc, j, k, m, n;
|
||||
m = prec1 - prec;
|
||||
bits = b->bits;
|
||||
inc = 0;
|
||||
k = m - 1;
|
||||
if ((t = bits[k >> 3] >> (j = (k & 7) * 4)) & 8) {
|
||||
if (t & 7) goto inc1;
|
||||
if (j && bits[k >> 3] << (32 - j)) goto inc1;
|
||||
while (k >= 8) {
|
||||
k -= 8;
|
||||
if (bits[k >> 3]) {
|
||||
inc1:
|
||||
inc = 1;
|
||||
goto haveinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
haveinc:
|
||||
b->ex += m * 4;
|
||||
i = m >> 3;
|
||||
k = prec1 >> 3;
|
||||
j = i;
|
||||
if ((n = 4 * (m & 7)))
|
||||
for (;; ++j) {
|
||||
bits[j - i] = bits[j] >> n;
|
||||
if (j == k) break;
|
||||
bits[j - i] |= bits[j + 1] << (32 - n);
|
||||
}
|
||||
else
|
||||
for (;; ++j) {
|
||||
bits[j - i] = bits[j];
|
||||
if (j == k) break;
|
||||
}
|
||||
k = prec >> 3;
|
||||
if (inc) {
|
||||
for (j = 0; !(++bits[j] & 0xffffffff); ++j) donothing;
|
||||
if (j > k) {
|
||||
onebit:
|
||||
bits[0] = 1;
|
||||
b->ex += 4 * prec;
|
||||
return 1;
|
||||
}
|
||||
if ((j = prec & 7) < 7 && bits[k] >> (j + 1) * 4) goto onebit;
|
||||
}
|
||||
for (i = 0; !(bits[i >> 3] & (0xf << 4 * (i & 7))); ++i) donothing;
|
||||
if (i) {
|
||||
b->ex += 4 * i;
|
||||
prec -= i;
|
||||
j = i >> 3;
|
||||
i &= 7;
|
||||
i *= 4;
|
||||
for (m = j;; ++m) {
|
||||
bits[m - j] = bits[m] >> i;
|
||||
if (m == k) break;
|
||||
bits[m - j] |= bits[m + 1] << (32 - i);
|
||||
}
|
||||
}
|
||||
return prec;
|
||||
}
|
||||
|
||||
int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||
int flags, int prec, int sign, int width, bool longdouble,
|
||||
char qchar, unsigned char signbit, const char *alphabet,
|
||||
va_list va) {
|
||||
double x;
|
||||
union U u;
|
||||
struct FPBits fpb;
|
||||
char *s, *q, *se, *s0, special[8];
|
||||
int c, k, i1, ui, bw, rc, bex, sgn, prec1, decpt, consumed;
|
||||
x = 0;
|
||||
switch (d) {
|
||||
case 'F':
|
||||
case 'f':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (!longdouble) {
|
||||
x = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
s = s0 = dtoa(x, 3, prec, &decpt, &fpb.sign, &se);
|
||||
if (decpt == 9999) {
|
||||
if (s && s[0] == 'N') {
|
||||
fpb.kind = STRTOG_NaN;
|
||||
} else {
|
||||
fpb.kind = STRTOG_Infinite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
s = s0 =
|
||||
gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, 3, prec, &decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
if (s0) freedtoa(s0);
|
||||
bzero(special, sizeof(special));
|
||||
s = q = special;
|
||||
if (fpb.sign) {
|
||||
*q++ = '-';
|
||||
} else if (flags & FLAGS_PLUS) {
|
||||
*q++ = '+';
|
||||
} else if (flags & FLAGS_SPACE) {
|
||||
*q++ = ' ';
|
||||
}
|
||||
memcpy(q, kSpecialFloats[fpb.kind == STRTOG_NaN][d >= 'a'], 4);
|
||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_HASH | FLAGS_SPACE);
|
||||
prec = 0;
|
||||
rc = __fmt_stoa(out, arg, s, flags, prec, width, signbit, qchar);
|
||||
if (rc == -1) return -1;
|
||||
return consumed;
|
||||
}
|
||||
FormatReal:
|
||||
if (fpb.sign /* && (x || sign) */) sign = '-';
|
||||
if (prec > 0) width -= prec;
|
||||
if (width > 0) {
|
||||
if (sign) --width;
|
||||
if (decpt <= 0) {
|
||||
--width;
|
||||
if (prec > 0) --width;
|
||||
} else {
|
||||
if (s == se) decpt = 1;
|
||||
width -= decpt;
|
||||
if (prec > 0 || (flags & FLAGS_HASH)) --width;
|
||||
}
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if ((flags & FLAGS_ZEROPAD)) {
|
||||
if (sign) __FMT_PUT(sign);
|
||||
sign = 0;
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else
|
||||
do __FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
if (decpt <= 0) {
|
||||
__FMT_PUT('0');
|
||||
if (prec > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
while (decpt < 0) {
|
||||
__FMT_PUT('0');
|
||||
prec--;
|
||||
decpt++;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
} while (--decpt > 0);
|
||||
if (prec > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
}
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s)) {
|
||||
s++;
|
||||
} else {
|
||||
c = '0';
|
||||
}
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
if (s0) freedtoa(s0);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
case 'g':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (prec < 1) prec = 1;
|
||||
if (!longdouble) {
|
||||
x = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
s = s0 = dtoa(x, 2, prec, &decpt, &fpb.sign, &se);
|
||||
if (decpt == 9999) {
|
||||
if (s && s[0] == 'N') {
|
||||
fpb.kind = STRTOG_NaN;
|
||||
} else {
|
||||
fpb.kind = STRTOG_Infinite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec,
|
||||
&decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) goto Format9999;
|
||||
c = se - s;
|
||||
prec1 = prec;
|
||||
if (!prec) {
|
||||
prec = c;
|
||||
prec1 = c + (s[1] || (flags & FLAGS_HASH) ? 5 : 4);
|
||||
// %.0g gives 10 rather than 1e1
|
||||
}
|
||||
if (decpt > -4 && decpt <= prec1) {
|
||||
if ((flags & FLAGS_HASH))
|
||||
prec -= decpt;
|
||||
else
|
||||
prec = c - decpt;
|
||||
if (prec < 0) prec = 0;
|
||||
goto FormatReal;
|
||||
}
|
||||
d -= 2;
|
||||
if (!(flags & FLAGS_HASH) && prec > c) prec = c;
|
||||
--prec;
|
||||
goto FormatExpo;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||
if (prec < 0) prec = 0;
|
||||
if (!longdouble) {
|
||||
x = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
s = s0 = dtoa(x, 2, prec + 1, &decpt, &fpb.sign, &se);
|
||||
if (decpt == 9999) {
|
||||
if (s && s[0] == 'N') {
|
||||
fpb.kind = STRTOG_NaN;
|
||||
} else {
|
||||
fpb.kind = STRTOG_Infinite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec,
|
||||
&decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) goto Format9999;
|
||||
FormatExpo:
|
||||
if (fpb.sign /* && (x || sign) */) sign = '-';
|
||||
if ((width -= prec + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec || (flags & FLAGS_HASH)) --width;
|
||||
}
|
||||
if ((c = --decpt) < 0) c = -c;
|
||||
while (c >= 100) {
|
||||
--width;
|
||||
c /= 10;
|
||||
}
|
||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
if ((flags & FLAGS_ZEROPAD)) {
|
||||
if (sign) __FMT_PUT(sign);
|
||||
sign = 0;
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
} else
|
||||
do __FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT(*s++);
|
||||
if (prec || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
while (--prec >= 0) {
|
||||
if ((c = *s))
|
||||
s++;
|
||||
else
|
||||
c = '0';
|
||||
__FMT_PUT(c);
|
||||
}
|
||||
__FMT_PUT(d);
|
||||
if (decpt < 0) {
|
||||
__FMT_PUT('-');
|
||||
decpt = -decpt;
|
||||
} else
|
||||
__FMT_PUT('+');
|
||||
for (c = 2, k = 10; 10 * k <= decpt; c++, k *= 10) donothing;
|
||||
for (;;) {
|
||||
i1 = decpt / k;
|
||||
__FMT_PUT(i1 + '0');
|
||||
if (--c <= 0) break;
|
||||
decpt -= i1 * k;
|
||||
decpt *= 10;
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
freedtoa(s0);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
alphabet = "0123456789ABCDEFPX";
|
||||
goto FormatBinary;
|
||||
case 'a':
|
||||
alphabet = "0123456789abcdefpx";
|
||||
FormatBinary:
|
||||
if (longdouble) {
|
||||
u.ld = va_arg(va, long double);
|
||||
consumed = __FMT_CONSUMED_LONG_DOUBLE;
|
||||
ldfpbits(&u, &fpb);
|
||||
} else {
|
||||
u.d = va_arg(va, double);
|
||||
consumed = __FMT_CONSUMED_DOUBLE;
|
||||
dfpbits(&u, &fpb);
|
||||
}
|
||||
if (fpb.kind == STRTOG_Infinite || fpb.kind == STRTOG_NaN) {
|
||||
s0 = 0;
|
||||
goto Format9999;
|
||||
}
|
||||
prec1 = fpiprec(&fpb);
|
||||
if ((flags & FLAGS_PRECISION) && prec < prec1) {
|
||||
prec1 = bround(&fpb, prec, prec1);
|
||||
}
|
||||
bw = 1;
|
||||
bex = fpb.ex + 4 * prec1;
|
||||
if (bex) {
|
||||
if ((i1 = bex) < 0) i1 = -i1;
|
||||
while (i1 >= 10) {
|
||||
++bw;
|
||||
i1 /= 10;
|
||||
}
|
||||
}
|
||||
if (fpb.sign /* && (sign || fpb.kind != STRTOG_Zero) */) {
|
||||
sign = '-';
|
||||
}
|
||||
if ((width -= bw + 5) > 0) {
|
||||
if (sign) --width;
|
||||
if (prec1 || (flags & FLAGS_HASH)) --width;
|
||||
}
|
||||
if ((width -= prec1) > 0 && !(flags & FLAGS_LEFT) &&
|
||||
!(flags & FLAGS_ZEROPAD)) {
|
||||
do __FMT_PUT(' ');
|
||||
while (--width > 0);
|
||||
}
|
||||
if (sign) __FMT_PUT(sign);
|
||||
__FMT_PUT('0');
|
||||
__FMT_PUT(alphabet[17]);
|
||||
if ((flags & FLAGS_ZEROPAD) && width > 0 && !(flags & FLAGS_LEFT)) {
|
||||
do __FMT_PUT('0');
|
||||
while (--width > 0);
|
||||
}
|
||||
i1 = prec1 & 7;
|
||||
k = prec1 >> 3;
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
if (prec1 > 0 || (flags & FLAGS_HASH)) __FMT_PUT('.');
|
||||
if (prec1 > 0) {
|
||||
prec -= prec1;
|
||||
while (prec1 > 0) {
|
||||
if (--i1 < 0) {
|
||||
if (--k < 0) break;
|
||||
i1 = 7;
|
||||
}
|
||||
__FMT_PUT(alphabet[(fpb.bits[k] >> 4 * i1) & 0xf]);
|
||||
--prec1;
|
||||
}
|
||||
if ((flags & FLAGS_HASH) && prec > 0) {
|
||||
do __FMT_PUT(0);
|
||||
while (--prec > 0);
|
||||
}
|
||||
}
|
||||
__FMT_PUT(alphabet[16]);
|
||||
if (bex < 0) {
|
||||
__FMT_PUT('-');
|
||||
bex = -bex;
|
||||
} else
|
||||
__FMT_PUT('+');
|
||||
for (c = 1; 10 * c <= bex; c *= 10) donothing;
|
||||
for (;;) {
|
||||
i1 = bex / c;
|
||||
__FMT_PUT('0' + i1);
|
||||
if (!--bw) break;
|
||||
bex -= i1 * c;
|
||||
bex *= 10;
|
||||
}
|
||||
while (--width >= 0) __FMT_PUT(' ');
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
return consumed;
|
||||
}
|
1375
libc/stdio/fmt.c
Normal file
1375
libc/stdio/fmt.c
Normal file
File diff suppressed because it is too large
Load diff
38
libc/stdio/snprintf.c
Normal file
38
libc/stdio/snprintf.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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;
|
||||
}
|
38
libc/stdio/sprintf.c
Normal file
38
libc/stdio/sprintf.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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;
|
||||
}
|
33
libc/stdio/sscanf.c
Normal file
33
libc/stdio/sscanf.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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;
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef _STDIO_H
|
||||
#define _STDIO_H
|
||||
#include "libc/fmt/pflink.h"
|
||||
|
||||
#define L_ctermid 20
|
||||
#define FILENAME_MAX PATH_MAX
|
||||
|
@ -162,25 +161,6 @@ int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
|
|||
int vfprintf_unlocked(FILE *, const char *, va_list)
|
||||
paramsnonnull() dontthrow nocallback;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § standard i/o » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#if defined(COSMO) && !defined(__cplusplus)
|
||||
/* clang-format off */
|
||||
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vprintf(FMT, VA) (vprintf)(PFLINK(FMT), VA)
|
||||
#define fprintf(F, FMT, ...) (fprintf)(F, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vfprintf(F, FMT, VA) (vfprintf)(F, PFLINK(FMT), VA)
|
||||
#define fprintf_unlocked(F, FMT, ...) (fprintf_unlocked)(F, PFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vfprintf_unlocked(F, FMT, VA) (vfprintf_unlocked)(F, PFLINK(FMT), VA)
|
||||
#define vscanf(FMT, VA) (vscanf)(SFLINK(FMT), VA)
|
||||
#define scanf(FMT, ...) (scanf)(SFLINK(FMT), ##__VA_ARGS__)
|
||||
#define fscanf(F, FMT, ...) (fscanf)(F, SFLINK(FMT), ##__VA_ARGS__)
|
||||
#define vfscanf(F, FMT, VA) (vfscanf)(F, SFLINK(FMT), VA)
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* _STDIO_H */
|
||||
|
|
25
libc/stdio/swprintf.c
Normal file
25
libc/stdio/swprintf.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*-*- 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);
|
||||
}
|
58
libc/stdio/vasprintf.c
Normal file
58
libc/stdio/vasprintf.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*-*- 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/assert.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
/**
|
||||
* Formats string w/ dynamic memory allocation.
|
||||
* @see xasprintf() for a better API
|
||||
* @threadsafe
|
||||
*/
|
||||
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
||||
va_list vb;
|
||||
size_t size;
|
||||
char *p, *p2;
|
||||
int wrote, rc = -1;
|
||||
if ((p = malloc((size = 512)))) {
|
||||
va_copy(vb, va);
|
||||
wrote = (vsnprintf)(p, size, fmt, va);
|
||||
if (wrote < size) {
|
||||
if ((p2 = realloc(p, wrote + 1))) {
|
||||
p = p2;
|
||||
rc = wrote;
|
||||
}
|
||||
} else {
|
||||
size = wrote + 1;
|
||||
if ((p2 = realloc(p, size))) {
|
||||
p = p2;
|
||||
wrote = (vsnprintf)(p, size, fmt, vb);
|
||||
_unassert(wrote == size - 1);
|
||||
rc = wrote;
|
||||
}
|
||||
}
|
||||
va_end(vb);
|
||||
}
|
||||
if (rc != -1) {
|
||||
*strp = p;
|
||||
return rc;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
310
libc/stdio/vcscanf.c
Normal file
310
libc/stdio/vcscanf.c
Normal file
|
@ -0,0 +1,310 @@
|
|||
/*-*- 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;
|
||||
}
|
77
libc/stdio/vdprintf.c
Normal file
77
libc/stdio/vdprintf.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ 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/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/iovec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct VdprintfState {
|
||||
int n, t, fd;
|
||||
char b[1024];
|
||||
};
|
||||
|
||||
static int vdprintf_putc(const char *s, struct VdprintfState *t, size_t n) {
|
||||
struct iovec iov[2];
|
||||
if (n) {
|
||||
if (t->n + n < sizeof(t->b)) {
|
||||
memcpy(t->b + t->n, s, n);
|
||||
t->n += n;
|
||||
} else {
|
||||
iov[0].iov_base = t->b;
|
||||
iov[0].iov_len = t->n;
|
||||
iov[1].iov_base = s;
|
||||
iov[1].iov_len = n;
|
||||
if (WritevUninterruptible(t->fd, iov, 2) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t->t += t->n;
|
||||
t->n = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats string directly to system i/o device.
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
||||
struct iovec iov[1];
|
||||
struct VdprintfState t;
|
||||
t.n = 0;
|
||||
t.t = 0;
|
||||
t.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &t, fmt, va) == -1) return -1;
|
||||
if (t.n) {
|
||||
iov[0].iov_base = t.b;
|
||||
iov[0].iov_len = t.n;
|
||||
if (WritevUninterruptible(t.fd, iov, 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t.t += t.n;
|
||||
}
|
||||
return t.t;
|
||||
}
|
64
libc/stdio/vsnprintf.c
Normal file
64
libc/stdio/vsnprintf.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*-*- 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;
|
||||
}
|
30
libc/stdio/vsprintf.c
Normal file
30
libc/stdio/vsprintf.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- 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);
|
||||
}
|
50
libc/stdio/vsscanf.c
Normal file
50
libc/stdio/vsscanf.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-*- 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