* libc/stdio/vfprintf.c: Include locale.h also if _WANT_IO_C99_FORMATS

is defined.  Raise conversion buffer size to make sure it has enough
	room for numbers plus grouping character.  Define GROUPING flag.
	(_VFPRINTF_R): Add PRINTANDPAD macro.  Handle grouping flag character.
	Handle grouping for decimal integer and float values.
	* libc/stdio/vfwprintf.c: Ditto.
This commit is contained in:
Corinna Vinschen 2010-02-05 08:35:35 +00:00
parent 6e3f2c626d
commit b0776ebd41
3 changed files with 330 additions and 76 deletions

View File

@ -1,3 +1,12 @@
2010-02-05 Corinna Vinschen <corinna@vinschen.de>
* libc/stdio/vfprintf.c: Include locale.h also if _WANT_IO_C99_FORMATS
is defined. Raise conversion buffer size to make sure it has enough
room for numbers plus grouping character. Define GROUPING flag.
(_VFPRINTF_R): Add PRINTANDPAD macro. Handle grouping flag character.
Handle grouping for decimal integer and float values.
* libc/stdio/vfwprintf.c: Ditto.
2010-02-01 Christopher Faylor <me+cygwin@cgf.cx> 2010-02-01 Christopher Faylor <me+cygwin@cgf.cx>
* libc/stdlib/__atexit.c (__atexit_lock): Define a global lock for * libc/stdlib/__atexit.c (__atexit_lock): Define a global lock for

View File

@ -375,8 +375,10 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
#endif /* !STRING_ONLY */ #endif /* !STRING_ONLY */
#ifdef FLOATING_POINT #if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
# include <locale.h> # include <locale.h>
#endif
#ifdef FLOATING_POINT
# include <math.h> # include <math.h>
/* For %La, an exponent of 15 bits occupies the exponent character, a /* For %La, an exponent of 15 bits occupies the exponent character, a
@ -423,8 +425,16 @@ static int exponent(char *, int, int);
reentrant storage shared with mprec. All other formats that use reentrant storage shared with mprec. All other formats that use
buf get by with fewer characters. Making BUF slightly bigger buf get by with fewer characters. Making BUF slightly bigger
reduces the need for malloc in %.*a and %S, when large precision or reduces the need for malloc in %.*a and %S, when large precision or
long strings are processed. */ long strings are processed.
The bigger size of 100 bytes is used on systems which allow number
strings using the locale's grouping character. Since that's a multibyte
value, we should use a conservative value.
*/
#ifdef _WANT_IO_C99_FORMATS
#define BUF 100
#else
#define BUF 40 #define BUF 40
#endif
#if defined _MB_CAPABLE && MB_LEN_MAX > BUF #if defined _MB_CAPABLE && MB_LEN_MAX > BUF
# undef BUF # undef BUF
# define BUF MB_LEN_MAX # define BUF MB_LEN_MAX
@ -508,6 +518,9 @@ _EXFUN(get_arg, (struct _reent *data, int n, char *fmt,
#else /* define as 0, to make SARG and UARG occupy fewer instructions */ #else /* define as 0, to make SARG and UARG occupy fewer instructions */
# define CHARINT 0 # define CHARINT 0
#endif #endif
#ifdef _WANT_IO_C99_FORMATS
# define GROUPING 0x400 /* use grouping ("'" flag) */
#endif
int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list)); int _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, _CONST char *, va_list));
@ -552,6 +565,12 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
int width; /* width from format (%8d), or 0 */ int width; /* width from format (%8d), or 0 */
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 _WANT_IO_C99_FORMATS
/* locale specific numeric grouping */
char *thousands_sep;
size_t thsnd_len;
const char *grouping;
#endif
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
char *decimal_point = _localeconv_r (data)->decimal_point; char *decimal_point = _localeconv_r (data)->decimal_point;
size_t decp_len = strlen (decimal_point); size_t decp_len = strlen (decimal_point);
@ -560,9 +579,16 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
# define _fpvalue (_double_.fp) # define _fpvalue (_double_.fp)
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 */
char expstr[MAXEXPLEN]; /* buffer for exponent string */ char expstr[MAXEXPLEN]; /* buffer for exponent string */
int lead; /* sig figs before decimal or group sep */
#endif /* FLOATING_POINT */ #endif /* FLOATING_POINT */
#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
int ndig = 0; /* actual number of digits returned by cvt */
#endif
#ifdef _WANT_IO_C99_FORMATS
int nseps; /* number of group separators with ' */
int nrepeats; /* number of repeats of the last group */
#endif
u_quad_t _uquad; /* integer arguments %[diouxX] */ u_quad_t _uquad; /* integer arguments %[diouxX] */
enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
@ -617,6 +643,14 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
PRINT (with, n); \ PRINT (with, n); \
} \ } \
} }
#define PRINTANDPAD(p, ep, len, with) { \
int n = (ep) - (p); \
if (n > (len)) \
n = (len); \
if (n > 0) \
PRINT((p), n); \
PAD((len) - (n > 0 ? n : 0), (with)); \
}
#define FLUSH() { \ #define FLUSH() { \
if (uio.uio_resid && __SPRINT(data, fp, &uio)) \ if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
goto error; \ goto error; \
@ -757,6 +791,12 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
width = 0; width = 0;
prec = -1; prec = -1;
sign = '\0'; sign = '\0';
#ifdef FLOATING_POINT
lead = 0;
#endif
#ifdef _WANT_IO_C99_FORMATS
nseps = nrepeats = 0;
#endif
#ifndef _NO_POS_ARGS #ifndef _NO_POS_ARGS
N = arg_index; N = arg_index;
is_pos_arg = 0; is_pos_arg = 0;
@ -766,11 +806,11 @@ rflag: ch = *fmt++;
reswitch: switch (ch) { reswitch: switch (ch) {
#ifdef _WANT_IO_C99_FORMATS #ifdef _WANT_IO_C99_FORMATS
case '\'': case '\'':
/* The ' flag is required by POSIX, but not C99. thousands_sep = _localeconv_r (data)->thousands_sep;
In the C locale, LC_NUMERIC requires thsnd_len = strlen (thousands_sep);
thousands_sep to be the empty string. And since grouping = _localeconv_r (data)->grouping;
no other locales are supported (yet), this flag if (thsnd_len > 0 && grouping && *grouping)
is currently a no-op. */ flags |= GROUPING;
goto rflag; goto rflag;
#endif #endif
case ' ': case ' ':
@ -1140,7 +1180,11 @@ reswitch: switch (ch) {
size = expsize + ndig; size = expsize + ndig;
if (ndig > 1 || flags & ALT) if (ndig > 1 || flags & ALT)
++size; ++size;
} else if (ch == 'f') { /* f fmt */ # ifdef _WANT_IO_C99_FORMATS
flags &= ~GROUPING;
# endif
} else {
if (ch == 'f') { /* f fmt */
if (expt > 0) { if (expt > 0) {
size = expt; size = expt;
if (prec || flags & ALT) if (prec || flags & ALT)
@ -1156,6 +1200,26 @@ reswitch: switch (ch) {
} else } else
size = ndig + (expt > 0 ? size = ndig + (expt > 0 ?
1 : 2 - expt); 1 : 2 - expt);
# ifdef _WANT_IO_C99_FORMATS
if ((flags & GROUPING) && expt > 0) {
/* space for thousands' grouping */
nseps = nrepeats = 0;
lead = expt;
while (*grouping != CHAR_MAX) {
if (lead <= *grouping)
break;
lead -= *grouping;
if (grouping[1]) {
nseps++;
grouping++;
} else
nrepeats++;
}
size += (nseps + nrepeats) * thsnd_len;
} else
# endif
lead = expt;
}
if (softsign) if (softsign)
sign = '-'; sign = '-';
@ -1184,6 +1248,9 @@ reswitch: switch (ch) {
case 'o': case 'o':
_uquad = UARG (); _uquad = UARG ();
base = OCT; base = OCT;
#ifdef _WANT_IO_C99_FORMATS
flags &= ~GROUPING;
#endif
goto nosign; goto nosign;
case 'p': case 'p':
/* /*
@ -1320,6 +1387,9 @@ hex: _uquad = UARG ();
flags |= HEXPREFIX; flags |= HEXPREFIX;
} }
#ifdef _WANT_IO_C99_FORMATS
flags &= ~GROUPING;
#endif
/* unsigned conversions */ /* unsigned conversions */
nosign: sign = '\0'; nosign: sign = '\0';
/* /*
@ -1355,12 +1425,38 @@ number: if ((dprec = prec) >= 0)
case DEC: case DEC:
/* many numbers are 1 digit */ /* many numbers are 1 digit */
while (_uquad >= 10) { if (_uquad < 10) {
*--cp = to_char (_uquad % 10);
_uquad /= 10;
}
*--cp = to_char(_uquad); *--cp = to_char(_uquad);
break; break;
}
#ifdef _WANT_IO_C99_FORMATS
ndig = 0;
#endif
do {
*--cp = to_char (_uquad % 10);
#ifdef _WANT_IO_C99_FORMATS
ndig++;
/* If (*grouping == CHAR_MAX) then no
more grouping */
if ((flags & GROUPING)
&& ndig == *grouping
&& *grouping != CHAR_MAX
&& _uquad > 9) {
cp -= thsnd_len;
strncpy (cp, thousands_sep,
thsnd_len);
ndig = 0;
/* If (grouping[1] == '\0') then we
have to use *grouping character
(last grouping rule) for all
next cases. */
if (grouping[1] != '\0')
grouping++;
}
#endif
_uquad /= 10;
} while (_uquad != 0);
break;
case HEX: case HEX:
do { do {
@ -1459,16 +1555,33 @@ number: if ((dprec = prec) >= 0)
PAD (-expt, zeroes); PAD (-expt, zeroes);
PRINT (cp, ndig); PRINT (cp, ndig);
} }
} else if (expt >= ndig) {
PRINT (cp, ndig);
PAD (expt - ndig, zeroes);
if (flags & ALT)
PRINT (decimal_point, decp_len);
} else { } else {
PRINT (cp, expt); char *convbuf = cp;
cp += expt; PRINTANDPAD(cp, convbuf + ndig,
lead, zeroes);
cp += lead;
#ifdef _WANT_IO_C99_FORMATS
if (flags & GROUPING) {
while (nseps > 0 || nrepeats > 0) {
if (nrepeats > 0)
nrepeats--;
else {
grouping--;
nseps--;
}
PRINT(thousands_sep, thsnd_len);
PRINTANDPAD (cp, convbuf + ndig,
*grouping, zeroes);
cp += *grouping;
}
if (cp > convbuf + ndig)
cp = convbuf + ndig;
}
#endif
if (prec || flags & ALT)
PRINT (decimal_point, decp_len); PRINT (decimal_point, decp_len);
PRINT (cp, ndig - expt); PRINTANDPAD (cp, convbuf + ndig,
ndig - expt, zeroes);
} }
} else { /* 'a', 'A', 'e', or 'E' */ } else { /* 'a', 'A', 'e', or 'E' */
if (ndig > 1 || flags & ALT) { if (ndig > 1 || flags & ALT) {

View File

@ -201,8 +201,10 @@ _DEFUN(__sbwprintf, (rptr, fp, fmt, ap),
#endif /* !STRING_ONLY */ #endif /* !STRING_ONLY */
#ifdef FLOATING_POINT #if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
# include <locale.h> # include <locale.h>
#endif
#ifdef FLOATING_POINT
# include <math.h> # include <math.h>
/* For %La, an exponent of 15 bits occupies the exponent character, a /* For %La, an exponent of 15 bits occupies the exponent character, a
@ -249,8 +251,16 @@ static int wexponent(wchar_t *, int, int);
reentrant storage shared with mprec. All other formats that use reentrant storage shared with mprec. All other formats that use
buf get by with fewer characters. Making BUF slightly bigger buf get by with fewer characters. Making BUF slightly bigger
reduces the need for malloc in %.*a and %ls/%S, when large precision or reduces the need for malloc in %.*a and %ls/%S, when large precision or
long strings are processed. */ long strings are processed.
The bigger size of 100 bytes is used on systems which allow number
strings using the locale's grouping character. Since that's a multibyte
value, we should use a conservative value.
*/
#ifdef _WANT_IO_C99_FORMATS
#define BUF 100
#else
#define BUF 40 #define BUF 40
#endif
#if defined _MB_CAPABLE && MB_LEN_MAX > BUF #if defined _MB_CAPABLE && MB_LEN_MAX > BUF
# undef BUF # undef BUF
# define BUF MB_LEN_MAX # define BUF MB_LEN_MAX
@ -336,6 +346,9 @@ _EXFUN(get_arg, (struct _reent *data, int n, wchar_t *fmt,
#else /* define as 0, to make SARG and UARG occupy fewer instructions */ #else /* define as 0, to make SARG and UARG occupy fewer instructions */
# define CHARINT 0 # define CHARINT 0
#endif #endif
#ifdef _WANT_IO_C99_FORMATS
# define GROUPING 0x400 /* use grouping ("'" flag) */
#endif
#ifndef STRING_ONLY #ifndef STRING_ONLY
int int
@ -378,19 +391,31 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
int width; /* width from format (%8d), or 0 */ int width; /* width from format (%8d), or 0 */
int prec; /* precision from format (%.3d), or -1 */ int prec; /* precision from format (%.3d), or -1 */
wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */
#ifdef FLOATING_POINT #ifdef _WANT_IO_C99_FORMATS
wchar_t decimal_point; /* locale specific numeric grouping */
wchar_t thousands_sep;
const char *grouping;
#endif
#ifdef _MB_CAPABLE #ifdef _MB_CAPABLE
mbstate_t state; /* mbtowc calls from library must not change state */ mbstate_t state; /* mbtowc calls from library must not change state */
#endif #endif
#ifdef FLOATING_POINT
wchar_t decimal_point;
wchar_t softsign; /* temporary negative sign for floats */ wchar_t softsign; /* temporary negative sign for floats */
union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0}; union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
# define _fpvalue (_double_.fp) # define _fpvalue (_double_.fp)
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 wcvt */
wchar_t expstr[MAXEXPLEN]; /* buffer for exponent string */ wchar_t expstr[MAXEXPLEN]; /* buffer for exponent string */
int lead; /* sig figs before decimal or group sep */
#endif /* FLOATING_POINT */ #endif /* FLOATING_POINT */
#if defined (FLOATING_POINT) || defined (_WANT_IO_C99_FORMATS)
int ndig = 0; /* actual number of digits returned by cvt */
#endif
#ifdef _WANT_IO_C99_FORMATS
int nseps; /* number of group separators with ' */
int nrepeats; /* number of repeats of the last group */
#endif
u_quad_t _uquad; /* integer arguments %[diouxX] */ u_quad_t _uquad; /* integer arguments %[diouxX] */
enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
@ -419,9 +444,16 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
#ifdef _MB_CAPABLE #ifdef _MB_CAPABLE
{
size_t nconv;
memset (&state, '\0', sizeof (state)); memset (&state, '\0', sizeof (state));
_mbrtowc_r (data, &decimal_point, _localeconv_r (data)->decimal_point, nconv = _mbrtowc_r (data, &decimal_point,
_localeconv_r (data)->decimal_point,
MB_CUR_MAX, &state); MB_CUR_MAX, &state);
if (nconv == (size_t) -1 || nconv == (size_t) -2)
decimal_point = L'.';
}
#else #else
decimal_point = (wchar_t) *_localeconv_r (data)->decimal_point; decimal_point = (wchar_t) *_localeconv_r (data)->decimal_point;
#endif #endif
@ -449,6 +481,14 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
PRINT (with, n); \ PRINT (with, n); \
} \ } \
} }
#define PRINTANDPAD(p, ep, len, with) { \
int n = (ep) - (p); \
if (n > (len)) \
n = (len); \
if (n > 0) \
PRINT((p), n); \
PAD((len) - (n > 0 ? n : 0), (with)); \
}
#define FLUSH() { \ #define FLUSH() { \
if (uio.uio_resid && __SPRINT(data, fp, &uio)) \ if (uio.uio_resid && __SPRINT(data, fp, &uio)) \
goto error; \ goto error; \
@ -570,6 +610,12 @@ _DEFUN(_VFWPRINTF_R, (data, fp, fmt0, ap),
width = 0; width = 0;
prec = -1; prec = -1;
sign = L'\0'; sign = L'\0';
#ifdef FLOATING_POINT
lead = 0;
#endif
#ifdef _WANT_IO_C99_FORMATS
nseps = nrepeats = 0;
#endif
#ifndef _NO_POS_ARGS #ifndef _NO_POS_ARGS
N = arg_index; N = arg_index;
is_pos_arg = 0; is_pos_arg = 0;
@ -579,8 +625,23 @@ rflag: ch = *fmt++;
reswitch: switch (ch) { reswitch: switch (ch) {
#ifdef _WANT_IO_C99_FORMATS #ifdef _WANT_IO_C99_FORMATS
case L'\'': case L'\'':
/* The ' flag is required by POSIX, but not C99. #ifdef _MB_CAPABLE
FIXME: this flag is currently a no-op. */ {
size_t nconv;
memset (&state, '\0', sizeof (state));
nconv = _mbrtowc_r (data, &thousands_sep,
_localeconv_r (data)->thousands_sep,
MB_CUR_MAX, &state);
if (nconv == (size_t) -1 || nconv == (size_t) -2)
thousands_sep = L'\0';
}
#else
thousands_sep = (wchar_t) *_localeconv_r(data)->thousands_sep;
#endif
grouping = _localeconv_r (data)->grouping;
if (thousands_sep && grouping && *grouping)
flags |= GROUPING;
goto rflag; goto rflag;
#endif #endif
case L' ': case L' ':
@ -942,7 +1003,11 @@ reswitch: switch (ch) {
size = expsize + ndig; size = expsize + ndig;
if (ndig > 1 || flags & ALT) if (ndig > 1 || flags & ALT)
++size; ++size;
} else if (ch == L'f') { /* f fmt */ # ifdef _WANT_IO_C99_FORMATS
flags &= ~GROUPING;
# endif
} else {
if (ch == L'f') { /* f fmt */
if (expt > 0) { if (expt > 0) {
size = expt; size = expt;
if (prec || flags & ALT) if (prec || flags & ALT)
@ -958,7 +1023,26 @@ reswitch: switch (ch) {
} else } else
size = ndig + (expt > 0 ? size = ndig + (expt > 0 ?
1 : 2 - expt); 1 : 2 - expt);
# ifdef _WANT_IO_C99_FORMATS
if ((flags & GROUPING) && expt > 0) {
/* space for thousands' grouping */
nseps = nrepeats = 0;
lead = expt;
while (*grouping != CHAR_MAX) {
if (lead <= *grouping)
break;
lead -= *grouping;
if (grouping[1]) {
nseps++;
grouping++;
} else
nrepeats++;
}
size += nseps + nrepeats;
} else
# endif
lead = expt;
}
if (softsign) if (softsign)
sign = L'-'; sign = L'-';
break; break;
@ -983,6 +1067,9 @@ reswitch: switch (ch) {
case L'o': case L'o':
_uquad = UARG (); _uquad = UARG ();
base = OCT; base = OCT;
#ifdef _WANT_IO_C99_FORMATS
flags &= ~GROUPING;
#endif
goto nosign; goto nosign;
case L'p': case L'p':
/* /*
@ -1106,6 +1193,9 @@ hex: _uquad = UARG ();
flags |= HEXPREFIX; flags |= HEXPREFIX;
} }
#ifdef _WANT_IO_C99_FORMATS
flags &= ~GROUPING;
#endif
/* unsigned conversions */ /* unsigned conversions */
nosign: sign = L'\0'; nosign: sign = L'\0';
/* /*
@ -1141,12 +1231,36 @@ number: if ((dprec = prec) >= 0)
case DEC: case DEC:
/* many numbers are 1 digit */ /* many numbers are 1 digit */
while (_uquad >= 10) { if (_uquad < 10) {
*--cp = to_char (_uquad % 10);
_uquad /= 10;
}
*--cp = to_char(_uquad); *--cp = to_char(_uquad);
break; break;
}
#ifdef _WANT_IO_C99_FORMATS
ndig = 0;
#endif
do {
*--cp = to_char (_uquad % 10);
#ifdef _WANT_IO_C99_FORMATS
ndig++;
/* If (*grouping == CHAR_MAX) then no
more grouping */
if ((flags & GROUPING)
&& ndig == *grouping
&& *grouping != CHAR_MAX
&& _uquad > 9) {
*--cp = thousands_sep;
ndig = 0;
/* If (grouping[1] == '\0') then we
have to use *grouping character
(last grouping rule) for all
next cases. */
if (grouping[1] != '\0')
grouping++;
}
#endif
_uquad /= 10;
} while (_uquad != 0);
break;
case HEX: case HEX:
do { do {
@ -1245,17 +1359,35 @@ number: if ((dprec = prec) >= 0)
PAD (-expt, zeroes); PAD (-expt, zeroes);
PRINT (cp, ndig); PRINT (cp, ndig);
} }
} else if (expt >= ndig) {
PRINT (cp, ndig);
PAD (expt - ndig, zeroes);
if (flags & ALT)
PRINT (&decimal_point, 1);
} else { } else {
PRINT (cp, expt); wchar_t *convbuf = cp;
cp += expt; PRINTANDPAD(cp, convbuf + ndig,
PRINT (&decimal_point, 1); lead, zeroes);
PRINT (cp, ndig - expt); cp += lead;
#ifdef _WANT_IO_C99_FORMATS
if (flags & GROUPING) {
while (nseps > 0 || nrepeats > 0) {
if (nrepeats > 0)
nrepeats--;
else {
grouping--;
nseps--;
} }
PRINT (&thousands_sep, 1);
PRINTANDPAD (cp, convbuf + ndig,
*grouping, zeroes);
cp += *grouping;
}
if (cp > convbuf + ndig)
cp = convbuf + ndig;
}
#endif
if (prec || flags & ALT)
PRINT (&decimal_point, 1);
PRINTANDPAD (cp, convbuf + ndig,
ndig - expt, zeroes);
}
} else { /* 'a', 'A', 'e', or 'E' */ } else { /* 'a', 'A', 'e', or 'E' */
if (ndig > 1 || flags & ALT) { if (ndig > 1 || flags & ALT) {
PRINT (cp, 1); PRINT (cp, 1);