diff options
Diffstat (limited to 'vsnprintf.c')
| -rw-r--r-- | vsnprintf.c | 163 |
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); -} |
