mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-30 08:18:30 +00:00
Add fixes performance and static web server
This commit is contained in:
parent
b6793d42d5
commit
c45e46f871
108 changed files with 2927 additions and 819 deletions
128
libc/fmt/fcvt.c
Normal file
128
libc/fmt/fcvt.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*-*- 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 2009 Ian Piumarta │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
|
||||
│ of this software and associated documentation files (the 'Software'), to │
|
||||
│ deal in the Software without restriction, including without limitation the │
|
||||
│ rights to use, copy, modify, merge, publish, distribute, and/or sell copies │
|
||||
│ of the Software, and to permit persons to whom the Software is furnished to │
|
||||
│ do so, provided that the above copyright notice(s) and this permission │
|
||||
│ notice appear in all copies of the Software. Inclusion of the above │
|
||||
│ copyright notice(s) and this permission notice in supporting documentation │
|
||||
│ would be appreciated but is not required. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
ecvt, fcvt (MIT License)\\n\
|
||||
Copyright 2009 Ian Piumarta\"");
|
||||
|
||||
/**
|
||||
* @fileoverview Replacements for the functions ecvt() and fcvt()
|
||||
*
|
||||
* These functions were recently deprecated in POSIX. The interface and
|
||||
* behaviour is identical to the functions that they replace and faster.
|
||||
*
|
||||
* For details on the use of these functions, see your ecvt(3) manual
|
||||
* page. If you don't have one handy, there might still be one available
|
||||
* here: http://opengroup.org/onlinepubs/007908799/xsh/ecvt.html
|
||||
*
|
||||
* @see https://www.piumarta.com/software/fcvt/
|
||||
*/
|
||||
|
||||
static char *Fcvt(double value, int ndigit, int *decpt, int *sign, int fflag) {
|
||||
static char buf[128];
|
||||
double i;
|
||||
uint64_t l, mant;
|
||||
int exp2, exp10, ptr;
|
||||
memcpy(&l, &value, 8);
|
||||
exp2 = (0x7ff & (l >> 52)) - 1023;
|
||||
mant = l & 0x000fffffffffffffULL;
|
||||
if ((*sign = l >> 63)) value = -value;
|
||||
if (exp2 == 0x400) {
|
||||
*decpt = 0;
|
||||
return mant ? "nan" : "inf";
|
||||
}
|
||||
exp10 = (value == 0) ? !fflag : (int)ceil(log10(value));
|
||||
if (exp10 < -307) exp10 = -307; /* otherwise overflow in pow() */
|
||||
value *= pow(10.0, -exp10);
|
||||
if (value) {
|
||||
while (value < 0.1) {
|
||||
value *= 10;
|
||||
--exp10;
|
||||
}
|
||||
while (value >= 1.0) {
|
||||
value /= 10;
|
||||
++exp10;
|
||||
}
|
||||
}
|
||||
assert(value == 0 || (0.1 <= value && value < 1.0));
|
||||
if (fflag) {
|
||||
if (ndigit + exp10 < 0) {
|
||||
*decpt = -ndigit;
|
||||
return "";
|
||||
}
|
||||
ndigit += exp10;
|
||||
}
|
||||
*decpt = exp10;
|
||||
if (ARRAYLEN(buf) < ndigit + 2) abort();
|
||||
ptr = 1;
|
||||
#if 0 /* slow and safe (and dreadfully boring) */
|
||||
while (ptr <= ndigit) {
|
||||
i;
|
||||
value = modf(value * 10, &i);
|
||||
buf[ptr++] = '0' + (int)i;
|
||||
}
|
||||
if (value >= 0.5) {
|
||||
while (--ptr && ++buf[ptr] > '9') {
|
||||
buf[ptr] = '0';
|
||||
}
|
||||
}
|
||||
#else /* faster */
|
||||
memcpy(&l, &value, 8);
|
||||
exp2 = (0x7ff & (l >> 52)) - 1023;
|
||||
assert(value == 0 || (-4 <= exp2 && exp2 <= -1));
|
||||
mant = l & 0x000fffffffffffffULL;
|
||||
if (exp2 == -1023) {
|
||||
++exp2;
|
||||
} else {
|
||||
mant |= 0x0010000000000000ULL;
|
||||
}
|
||||
mant <<= (exp2 + 4); /* 56-bit denormalised signifier */
|
||||
while (ptr <= ndigit) {
|
||||
mant &= 0x00ffffffffffffffULL; /* mod 1.0 */
|
||||
mant = (mant << 1) + (mant << 3);
|
||||
buf[ptr++] = '0' + (mant >> 56);
|
||||
}
|
||||
if (mant & 0x0080000000000000ULL) /* 1/2 << 56 */
|
||||
while (--ptr && ++buf[ptr] > '9') buf[ptr] = '0';
|
||||
#endif
|
||||
if (ptr) {
|
||||
buf[ndigit + 1] = 0;
|
||||
return buf + 1;
|
||||
}
|
||||
if (fflag) {
|
||||
++ndigit;
|
||||
++*decpt;
|
||||
}
|
||||
buf[0] = '1';
|
||||
buf[ndigit] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *ecvt(double value, int ndigit, int *decpt, int *sign) {
|
||||
return Fcvt(value, ndigit, decpt, sign, 0);
|
||||
}
|
||||
|
||||
char *fcvt(double value, int ndigit, int *decpt, int *sign) {
|
||||
return Fcvt(value, ndigit, decpt, sign, 1);
|
||||
}
|
|
@ -29,6 +29,8 @@ char *strerror(int) returnsnonnull nothrow nocallback;
|
|||
int strerror_r(int, char *, size_t) nothrow nocallback;
|
||||
int palandprintf(void *, void *, const char *, va_list) hidden;
|
||||
char *itoa(int, char *, int) compatfn;
|
||||
char *fcvt(double, int, int *, int *);
|
||||
char *ecvt(double, int, int *, int *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § string formatting » optimizations ─╬─│┼
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
* @see xdtoa() for higher precision at the cost of bloat
|
||||
* @see palandprintf() which is intended caller
|
||||
*/
|
||||
int ftoa(int out(int, void *), void *arg, long double value, int prec,
|
||||
int ftoa(int out(long, void *), void *arg, long double value, int prec,
|
||||
unsigned long width, unsigned long flags) {
|
||||
long whole, frac;
|
||||
long double tmp, diff;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int ntoaformat(int out(int, void *), void *arg, char *buf, unsigned len,
|
||||
static int ntoaformat(int out(long, void *), void *arg, char *buf, unsigned len,
|
||||
bool negative, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
|
@ -103,7 +103,7 @@ static int ntoaformat(int out(int, void *), void *arg, char *buf, unsigned len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ntoa2(int out(int, void *), void *arg, uintmax_t value, bool neg,
|
||||
int ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width, unsigned flags,
|
||||
const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
|
@ -135,7 +135,7 @@ int ntoa2(int out(int, void *), void *arg, uintmax_t value, bool neg,
|
|||
return ntoaformat(out, arg, buf, len, neg, log2base, prec, width, flags);
|
||||
}
|
||||
|
||||
int ntoa(int out(int, void *), void *arg, va_list va, unsigned char signbit,
|
||||
int ntoa(int out(long, void *), void *arg, va_list va, unsigned char signbit,
|
||||
unsigned long log2base, unsigned long prec, unsigned long width,
|
||||
unsigned char flags, const char *lang) {
|
||||
bool neg;
|
||||
|
|
|
@ -75,7 +75,7 @@ static int ppatoi(const char **str) {
|
|||
* - `%Lf` long double
|
||||
* - `%p` pointer (48-bit hexadecimal)
|
||||
*
|
||||
* Length Modifiers
|
||||
* Size Modifiers
|
||||
*
|
||||
* - `%hhd` char (8-bit)
|
||||
* - `%hd` short (16-bit)
|
||||
|
@ -89,7 +89,11 @@ static int ppatoi(const char **str) {
|
|||
* - `%08d` fixed columns w/ zero leftpadding
|
||||
* - `%8d` fixed columns w/ space leftpadding
|
||||
* - `%*s` variable column string (thompson-pike)
|
||||
* - `%.*s` variable column data (ignore nul terminator)
|
||||
*
|
||||
* Precision Modifiers
|
||||
*
|
||||
* - `%.8s` supplied character length (ignore nul terminator)
|
||||
* - `%.*s` supplied character length argument (ignore nul terminator)
|
||||
*
|
||||
* Formatting Modifiers
|
||||
*
|
||||
|
@ -112,9 +116,9 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
|
|||
long double ldbl;
|
||||
wchar_t charbuf[3];
|
||||
const char *alphabet;
|
||||
int (*out)(int, void *);
|
||||
int (*out)(long, void *);
|
||||
unsigned char signbit, log2base;
|
||||
int w, rc, flags, width, lasterr, precision;
|
||||
int w, flags, width, lasterr, precision;
|
||||
|
||||
lasterr = errno;
|
||||
out = fn ? fn : (int (*)(int, void *))missingno;
|
||||
|
@ -255,7 +259,8 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
|
|||
case 'u': {
|
||||
flags &= ~FLAGS_HASH; /* no hash for dec format */
|
||||
DoNumber:
|
||||
if (weaken(ntoa)(out, arg, va, signbit, log2base, precision, width,
|
||||
if (!weaken(ntoa) ||
|
||||
weaken(ntoa)(out, arg, va, signbit, log2base, precision, width,
|
||||
flags, alphabet) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -269,7 +274,8 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
|
|||
} else {
|
||||
ldbl = va_arg(va, double);
|
||||
}
|
||||
if (weaken(ftoa)(out, arg, ldbl, precision, width, flags) == -1) {
|
||||
if (!weaken(ftoa) ||
|
||||
weaken(ftoa)(out, arg, ldbl, precision, width, flags) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
@ -297,8 +303,10 @@ hidden int palandprintf(void *fn, void *arg, const char *format, va_list va) {
|
|||
case 's':
|
||||
p = va_arg(va, void *);
|
||||
showstr:
|
||||
rc = weaken(stoa)(out, arg, p, flags, precision, width, signbit, qchar);
|
||||
if (rc == -1) return -1;
|
||||
if (!weaken(stoa) || weaken(stoa)(out, arg, p, flags, precision, width,
|
||||
signbit, qchar) == -1) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int spacepad(int(int, void *), void *, unsigned long) hidden;
|
||||
int ftoa(int(int, void *), void *, long double, int, unsigned long,
|
||||
int spacepad(int(long, void *), void *, unsigned long) hidden;
|
||||
int ftoa(int(long, void *), void *, long double, int, unsigned long,
|
||||
unsigned long) hidden;
|
||||
int stoa(int(int, void *), void *, void *, unsigned long, unsigned long,
|
||||
int stoa(int(long, void *), void *, void *, unsigned long, unsigned long,
|
||||
unsigned long, unsigned char, unsigned char) hidden;
|
||||
int ntoa(int(int, void *), void *, va_list, unsigned char, unsigned long,
|
||||
int ntoa(int(long, void *), void *, va_list, unsigned char, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char, const char *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
|
||||
int spacepad(int out(int, void *), void *arg, unsigned long n) {
|
||||
int spacepad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
||||
return rc;
|
||||
|
|
194
libc/fmt/stoa.c
194
libc/fmt/stoa.c
|
@ -17,47 +17,54 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/escape/escape.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/paland.inc"
|
||||
#include "libc/fmt/palandprintf.h"
|
||||
#include "libc/nexgen32e/tinystrlen.h"
|
||||
#include "libc/str/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpdecode.h"
|
||||
#include "libc/str/tpencode.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
|
||||
forceinline unsigned long tpiencode(wint_t wc) {
|
||||
char buf[8];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
tpencode(buf, sizeof(buf), wc, false);
|
||||
return read64le(buf);
|
||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
||||
|
||||
static int StoaEmitByte(int f(long, void *), void *a, wint_t c) {
|
||||
return f(c, a);
|
||||
}
|
||||
|
||||
forceinline int emitwc(int out(int, void *), void *arg, unsigned flags,
|
||||
wint_t wc) {
|
||||
unsigned long pending;
|
||||
if (flags & FLAGS_QUOTE) {
|
||||
if (wc > 127) {
|
||||
pending = tpiencode(wc);
|
||||
} else {
|
||||
pending = cescapec(wc);
|
||||
}
|
||||
} else {
|
||||
pending = tpiencode(wc);
|
||||
}
|
||||
static int StoaEmitWordEncodedString(int f(long, void *), void *a, uint64_t w) {
|
||||
do {
|
||||
if (out(pending & 0xff, arg) == -1) return -1;
|
||||
} while ((pending >>= 8));
|
||||
if (f(w & 0xff, a) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return 0;
|
||||
}
|
||||
|
||||
forceinline int emitquote(int out(int, void *), void *arg, unsigned flags,
|
||||
char ch, unsigned char signbit) {
|
||||
static int StoaEmitUnicode(int f(long, void *), void *a, wint_t c) {
|
||||
if (0 <= c && c <= 127) {
|
||||
return f(c, a);
|
||||
} else {
|
||||
return StoaEmitWordEncodedString(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static int StoaEmitQuoted(int f(long, void *), void *a, wint_t c) {
|
||||
if (0 <= c && c <= 127) {
|
||||
return StoaEmitWordEncodedString(f, a, cescapec(c));
|
||||
} else {
|
||||
return StoaEmitWordEncodedString(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static int StoaEmitVisualized(int f(long, void *), void *a, wint_t c) {
|
||||
return StoaEmitUnicode(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static int StoaEmitQuote(int out(long, void *), void *arg, unsigned flags,
|
||||
char ch, unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out('L', arg) == -1) return -1;
|
||||
|
@ -78,13 +85,15 @@ forceinline int emitquote(int out(int, void *), void *arg, unsigned flags,
|
|||
*
|
||||
* @see palandprintf()
|
||||
*/
|
||||
int stoa(int out(int, void *), void *arg, void *data, unsigned long flags,
|
||||
int stoa(int out(long, void *), void *arg, void *data, unsigned long flags,
|
||||
unsigned long precision, unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
char *p;
|
||||
wint_t wc;
|
||||
unsigned w, c;
|
||||
bool ignorenul;
|
||||
unsigned n;
|
||||
emit_f emit;
|
||||
bool justdobytes;
|
||||
unsigned w, c, pad;
|
||||
|
||||
p = data;
|
||||
if (!p) {
|
||||
|
@ -93,89 +102,102 @@ int stoa(int out(int, void *), void *arg, void *data, unsigned long flags,
|
|||
flags |= FLAGS_NOQUOTE;
|
||||
signbit = 0;
|
||||
} else {
|
||||
if (emitquote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
if (StoaEmitQuote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
|
||||
w = precision ? precision : -1;
|
||||
if (!(flags & FLAGS_PRECISION)) {
|
||||
if (signbit == 63) {
|
||||
precision = tinywcsnlen((const wchar_t *)p, -1);
|
||||
} else if (signbit == 15) {
|
||||
precision = tinystrnlen16((const char16_t *)p, -1);
|
||||
} else {
|
||||
precision = strlen(p);
|
||||
}
|
||||
}
|
||||
|
||||
pad = 0;
|
||||
if (width) {
|
||||
w = precision;
|
||||
if (signbit == 63) {
|
||||
if (weaken(wcsnwidth)) {
|
||||
w = weaken(wcsnwidth)((const wchar_t *)p, w);
|
||||
} else {
|
||||
w = tinywcsnlen((const wchar_t *)p, w);
|
||||
w = weaken(wcsnwidth)((const wchar_t *)p, precision);
|
||||
}
|
||||
} else if (signbit == 15) {
|
||||
if (weaken(strnwidth16)) {
|
||||
w = weaken(strnwidth16)((const char16_t *)p, w);
|
||||
} else {
|
||||
w = tinystrnlen16((const char16_t *)p, w);
|
||||
w = weaken(strnwidth16)((const char16_t *)p, precision);
|
||||
}
|
||||
} else if (weaken(strnwidth)) {
|
||||
w = weaken(strnwidth)(p, w);
|
||||
} else {
|
||||
w = strnlen(p, w);
|
||||
w = weaken(strnwidth)(p, precision);
|
||||
}
|
||||
if (w < width) {
|
||||
pad = width - w;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
w = MIN(w, precision);
|
||||
if (pad && !(flags & FLAGS_LEFT)) {
|
||||
if (spacepad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (w < width && !(flags & FLAGS_LEFT)) {
|
||||
if (spacepad(out, arg, width - w) == -1) return -1;
|
||||
justdobytes = false;
|
||||
if (signbit == 15 || signbit == 63) {
|
||||
if (flags & FLAGS_QUOTE) {
|
||||
emit = StoaEmitQuoted;
|
||||
} else {
|
||||
emit = StoaEmitUnicode;
|
||||
}
|
||||
} else if ((flags & FLAGS_HASH) && weaken(kCp437)) {
|
||||
justdobytes = true;
|
||||
emit = StoaEmitVisualized;
|
||||
} else if (flags & FLAGS_QUOTE) {
|
||||
emit = StoaEmitQuoted;
|
||||
} else {
|
||||
justdobytes = true;
|
||||
emit = StoaEmitByte;
|
||||
}
|
||||
|
||||
ignorenul = (flags & FLAGS_PRECISION) && (flags & (FLAGS_HASH | FLAGS_QUOTE));
|
||||
for (; !(flags & FLAGS_PRECISION) || precision; --precision) {
|
||||
if (signbit == 15) {
|
||||
if ((wc = *(const char16_t *)p) || ignorenul) {
|
||||
if ((1 <= wc && wc <= 0xD7FF)) {
|
||||
if (justdobytes) {
|
||||
while (precision--) {
|
||||
wc = *p++ & 0xff;
|
||||
if (emit(out, arg, wc) == -1) return -1;
|
||||
}
|
||||
} else {
|
||||
while (precision--) {
|
||||
if (signbit == 15) {
|
||||
wc = *(const char16_t *)p;
|
||||
if (IsUcs2(wc)) {
|
||||
p += sizeof(char16_t);
|
||||
} else if ((wc & UTF16_MASK) == UTF16_CONT) {
|
||||
} else if (IsUtf16Cont(wc)) {
|
||||
p += sizeof(char16_t);
|
||||
continue;
|
||||
} else if (!precision) {
|
||||
break;
|
||||
} else {
|
||||
char16_t buf[4] = {wc};
|
||||
if (!(flags & FLAGS_PRECISION) || precision > 1) {
|
||||
buf[1] = ((const char16_t *)p)[1];
|
||||
--precision;
|
||||
wc = MergeUtf16(wc, *(const char16_t *)p);
|
||||
}
|
||||
} else if (signbit == 63) {
|
||||
wc = *(const wint_t *)p;
|
||||
p += sizeof(wint_t);
|
||||
if (!wc) break;
|
||||
} else {
|
||||
wc = *p++ & 0xff;
|
||||
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++);
|
||||
}
|
||||
p += max(1, getutf16((const char16_t *)p, &wc)) * sizeof(char16_t);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (signbit == 63) {
|
||||
wc = *(const wint_t *)p;
|
||||
p += sizeof(wint_t);
|
||||
if (!wc) break;
|
||||
} else if (flags & FLAGS_HASH) {
|
||||
c = *p & 0xff;
|
||||
if (!c && !ignorenul) break;
|
||||
wc = (*weaken(kCp437))[c];
|
||||
p++;
|
||||
} else {
|
||||
if ((wc = *p & 0xff) || ignorenul) {
|
||||
if (1 <= wc && wc <= 0x7f) {
|
||||
++p;
|
||||
} else if (iscont(wc & 0xff)) {
|
||||
++p;
|
||||
continue;
|
||||
} else {
|
||||
char buf[8];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, p,
|
||||
!(flags & FLAGS_PRECISION) ? 7 : MIN(7, precision - 1));
|
||||
p += max(1, tpdecode(p, &wc));
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (emit(out, arg, wc) == -1) return -1;
|
||||
}
|
||||
if (emitwc(out, arg, flags, wc) == -1) return -1;
|
||||
}
|
||||
|
||||
if (w <= width && (flags & FLAGS_LEFT)) {
|
||||
if (spacepad(out, arg, width - w) == -1) return -1;
|
||||
if (pad && (flags & FLAGS_LEFT)) {
|
||||
if (spacepad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
|
|
|
@ -25,17 +25,13 @@
|
|||
|
||||
struct SprintfStr {
|
||||
char *p;
|
||||
size_t i, n;
|
||||
size_t i;
|
||||
size_t n;
|
||||
};
|
||||
|
||||
static int vsnprintfputchar(unsigned char c, struct SprintfStr *str) {
|
||||
if (str->i < str->n) {
|
||||
if (str->p) str->p[str->i] = c;
|
||||
str->i++;
|
||||
} else {
|
||||
if (!IsTrustworthy() && str->i >= INT_MAX) abort();
|
||||
str->i++;
|
||||
}
|
||||
if (str->i < str->n) str->p[str->i] = c;
|
||||
str->i++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -48,15 +44,11 @@ static int vsnprintfputchar(unsigned char c, struct SprintfStr *str) {
|
|||
* @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
|
||||
* @throw EOVERFLOW when a formatted field exceeds its limit, which can
|
||||
* be checked by setting errno to 0 before calling
|
||||
* @see palandprintf() and printf() for detailed documentation
|
||||
*/
|
||||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||
struct SprintfStr str = {buf, 0, size};
|
||||
palandprintf(vsnprintfputchar, &str, fmt, va);
|
||||
if (str.p && str.n) {
|
||||
str.p[min(str.i, str.n - 1)] = '\0';
|
||||
}
|
||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
||||
return str.i;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue