summaryrefslogtreecommitdiff
path: root/vsnprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'vsnprintf.c')
-rw-r--r--vsnprintf.c163
1 files changed, 72 insertions, 91 deletions
diff --git a/vsnprintf.c b/vsnprintf.c
index 1e4cdc5eba..ecd5573dd5 100644
--- a/vsnprintf.c
+++ b/vsnprintf.c
@@ -95,29 +95,18 @@
# ifdef HAVE_LIMITS_H
# include <limits.h>
# else
- /* assuming 32bit(2's compliment) long */
+ /* assuming 32bit(2's complement) long */
# define LONG_MAX 2147483647
# endif
# endif
#endif
-#if defined(__hpux) && !defined(__GNUC__) && !defined(__STDC__)
-#define const
-#endif
-
#if defined(sgi)
#undef __const
#define __const
#endif /* People who don't like const sys_error */
#include <stddef.h>
-#if defined(__hpux) && !defined(__GNUC__) || defined(__DECC)
-#include <string.h>
-#endif
-
-#if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__)
-#include <stdlib.h>
-#endif
#ifndef NULL
#define NULL 0
@@ -127,12 +116,6 @@
# include <errno.h>
#endif
-#if __GNUC__ >= 3
-#define UNINITIALIZED_VAR(x) x = x
-#else
-#define UNINITIALIZED_VAR(x) x
-#endif
-
/*
* NB: to fit things in six character monocase externals, the stdio
* code uses the prefix `__s' for stdio objects, typically followed
@@ -167,11 +150,13 @@ struct __sbuf {
* _ub, _up, and _ur are used when ungetc() pushes back more characters
* than fit in the current _bf, or when ungetc() pushes back a character
* that does not match the previous one in _bf. When this happens,
- * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
+ * _ub._base becomes non-nil (i.e., a stream has ungetc() data if and only if
* _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
*
* NB: see WARNING above before changing the layout of this structure!
*/
+struct __suio;
+
typedef struct __sFILE {
unsigned char *_p; /* current position in (some) buffer */
#if 0
@@ -181,9 +166,11 @@ typedef struct __sFILE {
short _flags; /* flags, below; this FILE is free if 0 */
short _file; /* fileno, if Unix descriptor, else -1 */
struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
+#if 0
size_t _lbfsize; /* 0 or -_bf._size, for inline putc */
- int (*vwrite)(/* struct __sFILE*, struct __suio * */);
- char *(*vextra)(/* struct __sFILE*, size_t, void*, long*, int */);
+#endif
+ int (*vwrite)(struct __sFILE*, struct __suio *);
+ const char *(*vextra)(struct __sFILE*, size_t, void*, long*, int);
} FILE;
@@ -200,7 +187,7 @@ typedef struct __sFILE {
#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
#define __SOPT 0x0400 /* do fseek() optimisation */
#define __SNPT 0x0800 /* do not do fseek() optimisation */
-#define __SOFF 0x1000 /* set iff _offset is in fact correct */
+#define __SOFF 0x1000 /* set if and only if _offset is in fact correct */
#define __SMOD 0x2000 /* true => fgetln modified _p text */
@@ -253,9 +240,7 @@ BSD__sfvwrite(register FILE *fp, register struct __suio *uio)
if ((len = uio->uio_resid) == 0)
return (0);
-#ifndef __hpux
#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
iov = uio->uio_iov;
@@ -489,14 +474,19 @@ BSD__ultoa(register u_long val, char *endp, int base, int octzero, const char *x
#ifdef FLOATING_POINT
#include <math.h>
+#include <float.h>
/* #include "floatio.h" */
#ifndef MAXEXP
-# define MAXEXP 1024
+# if DBL_MAX_10_EXP > -DBL_MIN_10_EXP
+# define MAXEXP (DBL_MAX_10_EXP)
+# else
+# define MAXEXP (-DBL_MIN_10_EXP)
+# endif
#endif
#ifndef MAXFRACT
-# define MAXFRACT 64
+# define MAXFRACT (MAXEXP*10/3)
#endif
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
@@ -511,6 +501,12 @@ static int exponent(char *, int, int);
#endif /* FLOATING_POINT */
+#ifndef lower_hexdigits
+# define lower_hexdigits "0123456789abcdef"
+#endif
+#ifndef upper_hexdigits
+# define upper_hexdigits "0123456789ABCDEF"
+#endif
/*
* Flags used during conversion.
@@ -528,9 +524,13 @@ static int exponent(char *, int, int);
#define SHORTINT 0x040 /* short integer */
#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
#define FPT 0x100 /* Floating point number */
+ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static ssize_t BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap));
static ssize_t
BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
{
+#ifdef PRI_EXTRA_MARK
+ const int PRI_EXTRA_MARK_LEN = rb_strlen_lit(PRI_EXTRA_MARK);
+#endif
register const char *fmt; /* format string */
register int ch; /* character from fmt */
register int n; /* handy integer (short term usage) */
@@ -547,11 +547,12 @@ BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
int expt; /* integer value of exponent */
int expsize = 0; /* character count for expstr */
int ndig = 0; /* actual number of digits returned by cvt */
+ int fprec = 0; /* floating point precision */
char expstr[7]; /* buffer for exponent string */
#endif
- u_long UNINITIALIZED_VAR(ulval); /* integer arguments %[diouxX] */
+ u_long MAYBE_UNUSED(ulval) = 0; /* integer arguments %[diouxX] */
#ifdef _HAVE_SANE_QUAD_
- u_quad_t UNINITIALIZED_VAR(uqval); /* %q integers */
+ u_quad_t MAYBE_UNUSED(uqval) = 0; /* %q integers */
#endif /* _HAVE_SANE_QUAD_ */
int base; /* base for [diouxX] conversion */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
@@ -636,7 +637,7 @@ BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
(u_long)va_arg(ap, u_int))
- /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ /* optimize fprintf(stderr) (and other unbuffered Unix files) */
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
fp->_file >= 0)
return (BSD__sbprintf(fp, fmt0, ap));
@@ -806,7 +807,20 @@ reswitch: switch (ch) {
#else
# define INTPTR_FLAG 0
#endif
- if (fp->vextra && (flags & INTPTR_MASK) == INTPTR_FLAG) {
+#ifdef PRI_EXTRA_MARK
+# define IS_PRI_EXTRA_MARK(s) \
+ (PRI_EXTRA_MARK_LEN < 1 || \
+ (*(s) == PRI_EXTRA_MARK[0] && \
+ (PRI_EXTRA_MARK_LEN == 1 || \
+ strncmp((s)+1, &PRI_EXTRA_MARK[1], \
+ PRI_EXTRA_MARK_LEN-1) == 0)))
+#else
+# define PRI_EXTRA_MARK_LEN 0
+# define IS_PRI_EXTRA_MARK(s) 1
+#endif
+ if (fp->vextra && (flags & INTPTR_MASK) == INTPTR_FLAG &&
+ IS_PRI_EXTRA_MARK(fmt)) {
+ fmt += PRI_EXTRA_MARK_LEN;
FLUSH();
#if defined _HAVE_SANE_QUAD_ && SIZEOF_VOIDP == SIZEOF_LONG_LONG
uqval = va_arg(ap, u_quad_t);
@@ -851,6 +865,7 @@ reswitch: switch (ch) {
if (prec > 0) {
flags |= ALT;
prec++;
+ fprec = prec;
}
goto fp_begin;
case 'e': /* anomalous precision */
@@ -858,7 +873,7 @@ reswitch: switch (ch) {
if (prec != 0)
flags |= ALT;
prec = (prec == -1) ?
- DEFPREC + 1 : prec + 1;
+ DEFPREC + 1 : (fprec = prec + 1);
/* FALLTHROUGH */
goto fp_begin;
case 'f': /* always print trailing zeroes */
@@ -868,6 +883,8 @@ reswitch: switch (ch) {
case 'G':
if (prec == -1)
prec = DEFPREC;
+ else
+ fprec = prec;
fp_begin: _double = va_arg(ap, double);
/* do this before tricky precision changes */
if (isinf(_double)) {
@@ -883,7 +900,7 @@ fp_begin: _double = va_arg(ap, double);
break;
}
flags |= FPT;
- cp = cvt(_double, prec, flags, &softsign,
+ cp = cvt(_double, (prec < MAXFRACT ? prec : MAXFRACT), flags, &softsign,
&expt, ch, &ndig, buf);
if (ch == 'g' || ch == 'G') {
if (expt <= -4 || (expt > prec && expt > 1))
@@ -905,7 +922,7 @@ fp_begin: _double = va_arg(ap, double);
expsize = exponent(expstr, expt, ch);
size = expsize + ndig;
if (ndig > 1 || flags & ALT)
- ++size;
+ ++fprec, ++size;
} else if (ch == 'f') { /* f fmt */
if (expt > 0) {
size = expt;
@@ -976,7 +993,7 @@ fp_begin: _double = va_arg(ap, double);
#endif /* _HAVE_SANE_QUAD_ */
#endif
base = 16;
- xdigs = "0123456789abcdef";
+ xdigs = lower_hexdigits;
ch = 'x';
goto nosign;
case 's':
@@ -990,7 +1007,7 @@ fp_begin: _double = va_arg(ap, double);
*/
const char *p = (char *)memchr(cp, 0, prec);
- if (p != NULL && (p - cp) > prec)
+ if (p != NULL && (p - cp) < prec)
size = (int)(p - cp);
else
size = prec;
@@ -1014,10 +1031,10 @@ fp_begin: _double = va_arg(ap, double);
base = 10;
goto nosign;
case 'X':
- xdigs = "0123456789ABCDEF";
+ xdigs = upper_hexdigits;
goto hex;
case 'x':
- xdigs = "0123456789abcdef";
+ xdigs = lower_hexdigits;
hex:
#ifdef _HAVE_SANE_QUAD_
if (flags & QUADINT)
@@ -1051,6 +1068,7 @@ number: if ((dprec = prec) >= 0)
* explicit precision of zero is no characters.''
* -- ANSI X3J11
*/
+ cp = ebuf;
#ifdef _HAVE_SANE_QUAD_
if (flags & QUADINT) {
if (uqval != 0 || prec != 0)
@@ -1093,11 +1111,11 @@ number: if ((dprec = prec) >= 0)
*/
fieldsz = size;
long_len:
+ realsz = dprec > fieldsz ? dprec : fieldsz;
if (sign)
- fieldsz++;
+ realsz++;
if (flags & HEXPREFIX)
- fieldsz += 2;
- realsz = dprec > fieldsz ? dprec : fieldsz;
+ realsz += 2;
/* right-adjusting blank padding */
if ((flags & (LADJUST|ZEROPAD)) == 0)
@@ -1119,10 +1137,6 @@ long_len:
/* leading zeroes from decimal precision */
PAD_L(dprec - fieldsz, zeroes);
- if (sign)
- fieldsz--;
- if (flags & HEXPREFIX)
- fieldsz -= 2;
/* the string or number proper */
#ifdef FLOATING_POINT
@@ -1137,6 +1151,7 @@ long_len:
if (ndig > 0) PRINT(cp, ndig-1);
} else /* XpYYY */
PRINT(cp, 1);
+ PAD(fprec-ndig, zeroes);
PRINT(expstr, expsize);
}
else if (ch >= 'f') { /* 'f' or 'g' */
@@ -1147,7 +1162,8 @@ long_len:
PRINT("0", 1);
} else {
PRINT("0.", 2);
- PAD(ndig - 1, zeroes);
+ PAD((ndig >= fprec ? ndig - 1 : fprec - (ch != 'f')),
+ zeroes);
}
} else if (expt == 0 && ndig == 0 && (flags & ALT) == 0) {
PRINT("0", 1);
@@ -1155,6 +1171,8 @@ long_len:
PRINT("0.", 2);
PAD(-expt, zeroes);
PRINT(cp, ndig);
+ if (flags & ALT)
+ PAD(fprec - ndig + (ch == 'f' ? expt : 0), zeroes);
} else if (expt >= ndig) {
PRINT(cp, ndig);
PAD(expt - ndig, zeroes);
@@ -1165,6 +1183,8 @@ long_len:
cp += expt;
PRINT(".", 1);
PRINT(cp, ndig-expt);
+ if (flags & ALT)
+ PAD(fprec - ndig + (ch == 'f' ? expt : 0), zeroes);
}
} else { /* 'e' or 'E' */
if (ndig > 1 || flags & ALT) {
@@ -1176,6 +1196,7 @@ long_len:
} else /* 0.[0..] */
/* __dtoa irregularity */
PAD(ndig - 1, zeroes);
+ if (flags & ALT) PAD(fprec - ndig - 1, zeroes);
} else /* XeYYY */
PRINT(cp, 1);
PRINT(expstr, expsize);
@@ -1219,14 +1240,14 @@ cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch, int *l
if (value < 0) {
value = -value;
*sign = '-';
- } else if (value == 0.0 && 1.0/value < 0) {
+ } else if (value == 0.0 && signbit(value)) {
*sign = '-';
} else {
*sign = '\000';
}
if (ch == 'a' || ch =='A') {
digits = BSD__hdtoa(value,
- ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF",
+ ch == 'a' ? lower_hexdigits : upper_hexdigits,
ndigits, decpt, &dsgn, &rve);
}
else {
@@ -1234,8 +1255,8 @@ cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch, int *l
}
buf[0] = 0; /* rve - digits may be 0 */
memcpy(buf, digits, rve - digits);
- xfree(digits);
rve = buf + (rve - digits);
+ free(digits);
digits = buf;
if (flags & ALT) { /* Print trailing zeros */
bp = digits + ndigits;
@@ -1255,7 +1276,7 @@ static int
exponent(char *p0, int exp, int fmtch)
{
register char *p, *t;
- char expbuf[MAXEXP];
+ char expbuf[2 + (MAXEXP < 1000 ? 3 : MAXEXP < 10000 ? 4 : 5)]; /* >= 2 + ceil(log10(MAXEXP)) */
p = p0;
*p++ = fmtch;
@@ -1265,13 +1286,13 @@ exponent(char *p0, int exp, int fmtch)
}
else
*p++ = '+';
- t = expbuf + MAXEXP;
+ t = expbuf + sizeof(expbuf);
if (exp > 9) {
do {
*--t = to_char(exp % 10);
} while ((exp /= 10) > 9);
*--t = to_char(exp);
- for (; t < expbuf + MAXEXP; *p++ = *t++);
+ for (; t < expbuf + sizeof(expbuf); *p++ = *t++);
}
else {
if (fmtch & 15) *p++ = '0'; /* other than p or P */
@@ -1280,43 +1301,3 @@ exponent(char *p0, int exp, int fmtch)
return (int)(p - p0);
}
#endif /* FLOATING_POINT */
-
-int
-ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
-{
- int ret;
- FILE f;
-
- if ((int)n < 1)
- return (EOF);
- f._flags = __SWR | __SSTR;
- f._bf._base = f._p = (unsigned char *)str;
- f._bf._size = f._w = n - 1;
- f.vwrite = BSD__sfvwrite;
- f.vextra = 0;
- ret = (int)BSD_vfprintf(&f, fmt, ap);
- *f._p = 0;
- return (ret);
-}
-
-int
-ruby_snprintf(char *str, size_t n, char const *fmt, ...)
-{
- int ret;
- va_list ap;
- FILE f;
-
- if ((int)n < 1)
- return (EOF);
-
- va_start(ap, fmt);
- f._flags = __SWR | __SSTR;
- f._bf._base = f._p = (unsigned char *)str;
- f._bf._size = f._w = n - 1;
- f.vwrite = BSD__sfvwrite;
- f.vextra = 0;
- ret = (int)BSD_vfprintf(&f, fmt, ap);
- *f._p = 0;
- va_end(ap);
- return (ret);
-}