Remove printf() linking hack

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

38
libc/stdio/asprintf.c Normal file
View 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
View 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
View 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_ */

View file

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

File diff suppressed because it is too large Load diff

38
libc/stdio/snprintf.c Normal file
View 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
View 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
View 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;
}

View file

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