4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-18 12:29:32 +08:00

* libc/stdio/vfprintf.c (_VFPRINTF_R, cvt, exponent, chclass)

(get_arg): Support '%a' and '%A'.
This commit is contained in:
Eric Blake 2007-05-11 13:09:44 +00:00
parent a7af95ad76
commit b8a37af936
2 changed files with 148 additions and 84 deletions

View File

@ -1,3 +1,8 @@
2007-05-11 Eric Blake <ebb9@byu.net>
* libc/stdio/vfprintf.c (_VFPRINTF_R, cvt, exponent, chclass)
(get_arg): Support '%a' and '%A'.
2007-05-09 Eric Blake <ebb9@byu.net> 2007-05-09 Eric Blake <ebb9@byu.net>
Allow zero size with non-null buf in *asnprintf. Allow zero size with non-null buf in *asnprintf.

View File

@ -138,13 +138,8 @@ static char *rcsid = "$Id$";
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <wchar.h> #include <wchar.h>
#include <string.h>
#include <sys/lock.h> #include <sys/lock.h>
#ifdef _HAVE_STDC
#include <stdarg.h> #include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "local.h" #include "local.h"
#include "fvwrite.h" #include "fvwrite.h"
#include "vfieeefp.h" #include "vfieeefp.h"
@ -243,10 +238,12 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
#ifdef _NO_LONGDBL #ifdef _NO_LONGDBL
static char * static char *
_EXFUN(cvt, (struct _reent *, double, int, int, char *, int *, int, int *)); _EXFUN(cvt, (struct _reent *, double, int, int, char *, int *, int, int *,
char *));
#else #else
static char * static char *
_EXFUN(cvt, (struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *)); _EXFUN(cvt, (struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int,
int *, char *));
extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *)); extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
#endif #endif
@ -375,16 +372,16 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
int prec; /* precision from format (%.3d), or -1 */ int prec; /* precision from format (%.3d), or -1 */
char sign; /* sign prefix (' ', '+', '-', or \0) */ char sign; /* sign prefix (' ', '+', '-', or \0) */
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
char *decimal_point = localeconv()->decimal_point; char *decimal_point = _localeconv_r (data)->decimal_point;
char softsign; /* temporary negative sign for floats */ char softsign; /* temporary negative sign for floats */
#ifdef _NO_LONGDBL # ifdef _NO_LONGDBL
union { int i; double d; } _double_ = {0}; union { int i; double d; } _double_ = {0};
#define _fpvalue (_double_.d) # define _fpvalue (_double_.d)
#else # else
union { int i; _LONG_DOUBLE ld; } _long_double_ = {0}; union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
#define _fpvalue (_long_double_.ld) # define _fpvalue (_long_double_.ld)
int tmp; int tmp;
#endif # endif
int expt; /* integer value of exponent */ int expt; /* integer value of exponent */
int expsize = 0; /* character count for expstr */ int expsize = 0; /* character count for expstr */
int ndig = 0; /* actual number of digits returned by cvt */ int ndig = 0; /* actual number of digits returned by cvt */
@ -814,19 +811,15 @@ reswitch: switch (ch) {
base = DEC; base = DEC;
goto number; goto number;
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
case 'a':
case 'A':
case 'e': case 'e':
case 'E': case 'E':
case 'f': case 'f':
case 'F': case 'F':
case 'g': case 'g':
case 'G': case 'G':
if (prec == -1) { # ifdef _NO_LONGDBL
prec = DEFPREC;
} else if ((ch == 'g' || ch == 'G') && prec == 0) {
prec = 1;
}
#ifdef _NO_LONGDBL
if (flags & LONGDBL) { if (flags & LONGDBL) {
_fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE); _fpvalue = (double) GET_ARG (N, ap, _LONG_DOUBLE);
} else { } else {
@ -860,7 +853,7 @@ reswitch: switch (ch) {
break; break;
} }
#else /* !_NO_LONGDBL */ # else /* !_NO_LONGDBL */
if (flags & LONGDBL) { if (flags & LONGDBL) {
_fpvalue = GET_ARG (N, ap, _LONG_DOUBLE); _fpvalue = GET_ARG (N, ap, _LONG_DOUBLE);
@ -890,12 +883,35 @@ reswitch: switch (ch) {
flags &= ~ZEROPAD; flags &= ~ZEROPAD;
break; break;
} }
#endif /* !_NO_LONGDBL */ # endif /* !_NO_LONGDBL */
if (ch == 'a' || ch == 'A') {
ox[0] = '0';
ox[1] = ch == 'a' ? 'x' : 'X';
flags |= HEXPREFIX;
if (prec >= BUF)
{
if ((malloc_buf =
(char *)_malloc_r (data, prec + 1))
== NULL)
{
fp->_flags |= __SERR;
goto error;
}
cp = malloc_buf;
}
else
cp = buf;
} else if (prec == -1) {
prec = DEFPREC;
} else if ((ch == 'g' || ch == 'G') && prec == 0) {
prec = 1;
}
flags |= FPT; flags |= FPT;
cp = cvt (data, _fpvalue, prec, flags, &softsign, cp = cvt (data, _fpvalue, prec, flags, &softsign,
&expt, ch, &ndig); &expt, ch, &ndig, cp);
if (ch == 'g' || ch == 'G') { if (ch == 'g' || ch == 'G') {
if (expt <= -4 || expt > prec) if (expt <= -4 || expt > prec)
@ -905,7 +921,7 @@ reswitch: switch (ch) {
} }
else if (ch == 'F') else if (ch == 'F')
ch = 'f'; ch = 'f';
if (ch <= 'e') { /* 'e' or 'E' fmt */ if (ch <= 'e') { /* 'a', 'A', 'e', or 'E' fmt */
--expt; --expt;
expsize = exponent (expstr, expt, ch); expsize = exponent (expstr, expt, ch);
size = expsize + ndig; size = expsize + ndig;
@ -1067,8 +1083,11 @@ reswitch: switch (ch) {
hex: _uquad = UARG (); hex: _uquad = UARG ();
base = HEX; base = HEX;
/* leading 0x/X only if non-zero */ /* leading 0x/X only if non-zero */
if (flags & ALT && _uquad != 0) if (flags & ALT && _uquad != 0) {
ox[0] = '0';
ox[1] = ch;
flags |= HEXPREFIX; flags |= HEXPREFIX;
}
/* unsigned conversions */ /* unsigned conversions */
nosign: sign = '\0'; nosign: sign = '\0';
@ -1161,7 +1180,7 @@ number: if ((dprec = prec) >= 0)
* required by a decimal [diouxX] precision, then print the * required by a decimal [diouxX] precision, then print the
* string proper, then emit zeroes required by any leftover * string proper, then emit zeroes required by any leftover
* floating precision; finally, if LADJUST, pad with blanks. * floating precision; finally, if LADJUST, pad with blanks.
* If flags&FPT, ch must be in [eEfg]. * If flags&FPT, ch must be in [aAeEfg].
* *
* Compute actual size, so we know how much to pad. * Compute actual size, so we know how much to pad.
* size excludes decimal prec; realsz includes it. * size excludes decimal prec; realsz includes it.
@ -1169,7 +1188,7 @@ number: if ((dprec = prec) >= 0)
realsz = dprec > size ? dprec : size; realsz = dprec > size ? dprec : size;
if (sign) if (sign)
realsz++; realsz++;
else if (flags & HEXPREFIX) if (flags & HEXPREFIX)
realsz+= 2; realsz+= 2;
/* right-adjusting blank padding */ /* right-adjusting blank padding */
@ -1177,13 +1196,10 @@ number: if ((dprec = prec) >= 0)
PAD (width - realsz, blanks); PAD (width - realsz, blanks);
/* prefix */ /* prefix */
if (sign) { if (sign)
PRINT (&sign, 1); PRINT (&sign, 1);
} else if (flags & HEXPREFIX) { if (flags & HEXPREFIX)
ox[0] = '0';
ox[1] = ch;
PRINT (ox, 2); PRINT (ox, 2);
}
/* right-adjusting zero padding */ /* right-adjusting zero padding */
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
@ -1223,11 +1239,11 @@ number: if ((dprec = prec) >= 0)
PRINT (".", 1); PRINT (".", 1);
PRINT (cp, ndig - expt); PRINT (cp, ndig - expt);
} }
} else { /* 'e' or 'E' */ } else { /* 'a', 'A', 'e', or 'E' */
if (ndig > 1 || flags & ALT) { if (ndig > 1 || flags & ALT) {
ox[0] = *cp++; PRINT (cp, 1);
ox[1] = '.'; cp++;
PRINT (ox, 2); PRINT (decimal_point, 1);
if (_fpvalue) { if (_fpvalue) {
PRINT (cp, ndig - 1); PRINT (cp, ndig - 1);
} else /* 0.[0..] */ } else /* 0.[0..] */
@ -1238,7 +1254,7 @@ number: if ((dprec = prec) >= 0)
PRINT (expstr, expsize); PRINT (expstr, expsize);
} }
} }
#else #else /* !FLOATING_POINT */
PRINT (cp, size); PRINT (cp, size);
#endif #endif
/* left-adjusting padding (always blank) */ /* left-adjusting padding (always blank) */
@ -1267,19 +1283,31 @@ error:
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
#ifdef _NO_LONGDBL # ifdef _NO_LONGDBL
extern char *_dtoa_r _PARAMS((struct _reent *, double, int, extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
int, int *, int *, char **)); int, int *, int *, char **));
#else # define _DTOA_R _dtoa_r
# define FREXP frexp
# else
extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int, extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
int, int *, int *, char **)); int, int *, int *, char **));
#undef word0 # define _DTOA_R _ldtoa_r
#define word0(x) ldword0(x) /* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
#endif converts a finite value into infinity. */
/* # define FREXP frexpl */
# define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
# endif
#ifdef _NO_LONGDBL /* Using reentrant DATA, convert finite VALUE into a string of digits
with no decimal point, using NDIGITS precision and FLAGS as guides
to whether trailing zeros must be included. Set *SIGN to nonzero
if VALUE was negative. Set *DECPT to the exponent plus one. Set
*LENGTH to the length of the returned string. CH must be one of
[aAeEfFgG]; if it is [aA], then the return string lives in BUF,
otherwise the return value shares the mprec reentrant storage. */
# ifdef _NO_LONGDBL
static char * static char *
_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length), _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf),
struct _reent *data _AND struct _reent *data _AND
double value _AND double value _AND
int ndigits _AND int ndigits _AND
@ -1287,10 +1315,11 @@ _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length),
char *sign _AND char *sign _AND
int *decpt _AND int *decpt _AND
int ch _AND int ch _AND
int *length) int *length _AND
#else char *buf)
# else
static char * static char *
_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length), _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf),
struct _reent *data _AND struct _reent *data _AND
_LONG_DOUBLE value _AND _LONG_DOUBLE value _AND
int ndigits _AND int ndigits _AND
@ -1298,22 +1327,67 @@ _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length),
char *sign _AND char *sign _AND
int *decpt _AND int *decpt _AND
int ch _AND int ch _AND
int *length) int *length _AND
#endif char *buf)
# endif
{ {
int mode, dsgn; int mode, dsgn;
char *digits, *bp, *rve; char *digits, *bp, *rve;
#ifdef _NO_LONGDBL # ifdef _NO_LONGDBL
union double_union tmp; union double_union tmp;
#else
tmp.d = value;
if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
value = -value;
*sign = '-';
} else
*sign = '\000';
# else /* !_NO_LONGDBL */
union union
{ {
struct ldieee ieee; struct ldieee ieee;
_LONG_DOUBLE val; _LONG_DOUBLE val;
} ld; } ld;
#endif
if (ch == 'f' || ch == 'F') { ld.val = value;
if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
value = -value;
*sign = '-';
} else
*sign = '\000';
# endif /* !_NO_LONGDBL */
if (ch == 'a' || ch == 'A') {
/* This code assumes FLT_RADIX is a power of 2. The initial
division ensures the digit before the decimal will be less
than FLT_RADIX (unless it is rounded later). There is no
loss of precision in these calculations. */
value = FREXP (value, decpt) / 8;
if (!value)
*decpt = 1;
digits = ch == 'a' ? "0123456789abcdef" : "0123456789ABCDEF";
bp = buf;
do {
value *= 16;
mode = (int) value;
value -= mode;
*bp++ = digits[mode];
} while (ndigits-- && value);
if (value > 0.5 || (value == 0.5 && mode & 1)) {
/* round to even */
rve = bp;
while (*--rve == digits[0xf]) {
*rve = '0';
}
*rve = *rve == '9' ? digits[0xa] : *rve + 1;
} else {
while (ndigits-- >= 0) {
*bp++ = '0';
}
}
*length = bp - buf;
return buf;
} else if (ch == 'f' || ch == 'F') {
mode = 3; /* ndigits after the decimal point */ mode = 3; /* ndigits after the decimal point */
} else { } else {
/* To obtain ndigits after the decimal point for the 'e' /* To obtain ndigits after the decimal point for the 'e'
@ -1326,26 +1400,7 @@ _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length),
mode = 2; /* ndigits significant digits */ mode = 2; /* ndigits significant digits */
} }
#ifdef _NO_LONGDBL digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
tmp.d = value;
if (word0 (tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
value = -value;
*sign = '-';
} else
*sign = '\000';
digits = _dtoa_r (data, value, mode, ndigits, decpt, &dsgn, &rve);
#else /* !_NO_LONGDBL */
ld.val = value;
if (ld.ieee.sign) { /* this will check for < 0 and -0.0 */
value = -value;
*sign = '-';
} else
*sign = '\000';
digits = _ldtoa_r (data, value, mode, ndigits, decpt, &dsgn, &rve);
#endif /* !_NO_LONGDBL */
if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
bp = digits + ndigits; bp = digits + ndigits;
@ -1370,25 +1425,27 @@ _DEFUN(exponent, (p0, exp, fmtch),
int fmtch) int fmtch)
{ {
register char *p, *t; register char *p, *t;
char expbuf[40]; char expbuf[10];
int isa = fmtch == 'a' || fmtch == 'A';
p = p0; p = p0;
*p++ = fmtch; *p++ = isa ? 'p' - 'a' + fmtch : fmtch;
if (exp < 0) { if (exp < 0) {
exp = -exp; exp = -exp;
*p++ = '-'; *p++ = '-';
} }
else else
*p++ = '+'; *p++ = '+';
t = expbuf + 40; t = expbuf + 10;
if (exp > 9) { if (exp > 9) {
do { do {
*--t = to_char (exp % 10); *--t = to_char (exp % 10);
} while ((exp /= 10) > 9); } while ((exp /= 10) > 9);
*--t = to_char (exp); *--t = to_char (exp);
for (; t < expbuf + 40; *p++ = *t++); for (; t < expbuf + 10; *p++ = *t++);
} }
else { else {
if (!isa)
*p++ = '0'; *p++ = '0';
*p++ = to_char (exp); *p++ = to_char (exp);
} }
@ -1480,11 +1537,11 @@ _CONST static CH_CLASS chclass[256] = {
/* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER, /* 28-2f */ OTHER, OTHER, STAR, FLAG, OTHER, FLAG, DOT, OTHER,
/* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, /* 30-37 */ ZERO, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT,
/* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 38-3f */ DIGIT, DIGIT, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
/* 40-47 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC, /* 40-47 */ OTHER, SPEC, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC,
/* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC, /* 48-4f */ OTHER, OTHER, OTHER, OTHER, MODFR, OTHER, OTHER, SPEC,
/* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, OTHER, /* 50-57 */ OTHER, OTHER, OTHER, SPEC, OTHER, SPEC, OTHER, OTHER,
/* 58-5f */ SPEC, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, /* 58-5f */ SPEC, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,
/* 60-67 */ OTHER, OTHER, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC, /* 60-67 */ OTHER, SPEC, OTHER, SPEC, SPEC, SPEC, SPEC, SPEC,
/* 68-6f */ MODFR, SPEC, MODFR, OTHER, MODFR, OTHER, SPEC, SPEC, /* 68-6f */ MODFR, SPEC, MODFR, OTHER, MODFR, OTHER, SPEC, SPEC,
/* 70-77 */ SPEC, MODFR, OTHER, SPEC, MODFR, SPEC, OTHER, OTHER, /* 70-77 */ SPEC, MODFR, OTHER, SPEC, MODFR, SPEC, OTHER, OTHER,
/* 78-7f */ SPEC, OTHER, MODFR, OTHER, OTHER, OTHER, OTHER, OTHER, /* 78-7f */ SPEC, OTHER, MODFR, OTHER, OTHER, OTHER, OTHER, OTHER,
@ -1693,6 +1750,8 @@ _DEFUN(get_arg, (data, n, fmt, ap, numargs_p, args, arg_type, last_fmt),
case 'O': case 'O':
spec_type = LONG_INT; spec_type = LONG_INT;
break; break;
case 'a':
case 'A':
case 'f': case 'f':
case 'F': case 'F':
case 'g': case 'g':