Mercurial > flash_v2
view packages/language/c/libc/stdio/current/src/output/vfnprintf.cxx @ 1045:2c741788379c
* src/output/vfnprintf.cxx (SARG): Cast size_t to long. This seems
to stop gcc from producing wrong code for the plain int clause. The
wrong code causes negative numbers to be printed as positive because
the sign extend from 32 bits to 64 bits is wrong.
| author | asl |
|---|---|
| date | Tue, 10 Jun 2003 10:27:13 +0000 |
| parents | fb853432c81a |
| children | 871b38a618f4 |
line wrap: on
line source
//=========================================================================== // // vfnprintf.c // // I/O routines for vfnprintf() for use with ANSI C library // //=========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //=========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): jlarmour // Contributors: // Date: 2000-04-20 // Purpose: // Description: // Usage: // //####DESCRIPTIONEND#### // //=========================================================================== // // This code is based on original code with the following copyright: // /*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // CONFIGURATION #include <pkgconf/libc_stdio.h> // Configuration header #include <pkgconf/libc_i18n.h> // Configuration header for mb support // INCLUDES #include <cyg/infra/cyg_type.h> // Common type definitions and support #include <stdarg.h> // Variable argument definitions #include <stdio.h> // Standard header for all stdio files #include <string.h> // memchr() and strlen() functions #include <cyg/libc/stdio/stream.hxx> // C library streams #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT # include <float.h> // for DBL_DIG etc. below # include <math.h> // for modf() # include <sys/ieeefp.h> // Cyg_libm_ieee_double_shape_type # define MAXFRACT DBL_DIG # define MAXEXP DBL_MAX_10_EXP # define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ # define DEFPREC 6 static int cvt( double, int, int, char *, int, char *, char * ); #else // ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT # define BUF 40 #endif // ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT /* * Actual printf innards. * * This code is large and complicated... */ #ifdef CYGINT_LIBC_I18N_MB_REQUIRED typedef int (*mbtowc_fn_type)(wchar_t *, const char *, size_t, int *); externC mbtowc_fn_type __get_current_locale_mbtowc_fn(); #endif /* * Macros for converting digits to letters and vice versa */ #define to_digit(c) ((c) - '0') #define is_digit(c) ((unsigned)to_digit(c) <= 9) #define to_char(n) ((n) + '0') /* * Flags used during conversion. */ #define ALT 0x001 /* alternate form */ #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ #define LADJUST 0x004 /* left adjustment */ #define LONGDBL 0x008 /* long double; unimplemented */ #define LONGINT 0x010 /* long integer */ #define QUADINT 0x020 /* quad integer */ #define SHORTINT 0x040 /* short integer */ #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ #define FPT 0x100 /* Floating point number */ #define SIZET 0x200 /* size_t */ externC int vfnprintf ( FILE *stream, size_t n, const char *format, va_list arg) { char *fmt; /* format string */ int ch; /* character from fmt */ int x, y; /* handy integers (short term usage) */ char *cp; /* handy char pointer (short term usage) */ int flags; /* flags as above */ #ifdef CYGINT_LIBC_I18N_MB_REQUIRED int state = 0; /* state for mbtowc conversion */ mbtowc_fn_type mbtowc_fn; #endif int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format (%.3d), or -1 */ char sign; /* sign prefix (' ', '+', '-', or \0) */ wchar_t wc; #define quad_t long long #define u_quad_t unsigned long long u_quad_t _uquad; /* integer arguments %[diouxX] */ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int fieldsz; /* field size expanded by sign, etc */ int realsz; /* field size expanded by dprec */ int size; /* size of converted field or string */ char *xdigs; /* digits for [xX] conversion */ #define NIOV 8 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ char ox[2]; /* space for 0x hex-prefix */ #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT char softsign; /* temporary negative sign for floats */ double _double; /* double precision arguments %[eEfgG] */ int fpprec; /* `extra' floating precision in [eEfgG] */ #endif /* * Choose PADSIZE to trade efficiency vs. size. If larger printf * fields occur frequently, increase PADSIZE and make the initialisers * below longer. */ #define PADSIZE 16 /* pad chunk size */ static char blanks[PADSIZE] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; static char zeroes[PADSIZE] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; #define MIN(a, b) ((a) < (b) ? (a) : (b)) /* * BEWARE, these `goto error' on error, and PAD uses `n'. */ #define PRINT(ptr, len) \ CYG_MACRO_START \ cyg_ucount32 length = MIN( (cyg_ucount32) len, n - ret - 1); \ if (((Cyg_StdioStream *)stream)->write( (const cyg_uint8 *)ptr, \ length, &length )) \ goto error; \ if (length < (cyg_ucount32)len) { \ ret += length; \ goto done; \ } \ CYG_MACRO_END #define PAD(howmany, with) \ CYG_MACRO_START \ if ((x = (howmany)) > 0) { \ while (x > PADSIZE) { \ PRINT(with, PADSIZE); \ x -= PADSIZE; \ } \ PRINT(with, x); \ } \ CYG_MACRO_END /* * To extend shorts properly, we need both signed and unsigned * argument extraction methods. */ #define SARG() \ (flags&QUADINT ? va_arg(arg, cyg_int64) : \ flags&LONGINT ? va_arg(arg, long) : \ flags&SHORTINT ? (long)(short)va_arg(arg, int) : \ flags&SIZET ? (long)va_arg(arg, size_t) : \ (long)va_arg(arg, int)) #define UARG() \ (flags&QUADINT ? va_arg(arg, cyg_uint64) : \ flags&LONGINT ? va_arg(arg, unsigned long) : \ flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(arg, int) : \ flags&SIZET ? va_arg(arg, size_t) : \ (unsigned long)va_arg(arg, unsigned int)) xdigs = NULL; // stop compiler whinging fmt = (char *)format; ret = 0; #ifdef CYGINT_LIBC_I18N_MB_REQUIRED mbtowc_fn = __get_current_locale_mbtowc_fn(); #endif /* * Scan the format for conversions (`%' character). */ for (;;) { cp = (char *)fmt; #ifndef CYGINT_LIBC_I18N_MB_REQUIRED while ((x = ((wc = *fmt) != 0))) { #else while ((x = mbtowc_fn (&wc, fmt, MB_CUR_MAX, &state)) > 0) { #endif fmt += x; if (wc == '%') { fmt--; break; } } if ((y = fmt - cp) != 0) { PRINT(cp, y); ret += y; } if ((x <= 0) || (ret >= (int)n)) // @@@ this check with n isn't good enough goto done; fmt++; /* skip over '%' */ flags = 0; dprec = 0; #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT fpprec = 0; #endif width = 0; prec = -1; sign = '\0'; rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': /* * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 */ if (!sign) sign = ' '; goto rflag; case '#': flags |= ALT; goto rflag; case '*': /* * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ if ((width = va_arg(arg, int)) >= 0) goto rflag; width = -width; /* FALLTHROUGH */ case '-': flags |= LADJUST; goto rflag; case '+': sign = '+'; goto rflag; case '.': if ((ch = *fmt++) == '*') { x = va_arg(arg, int); prec = x < 0 ? -1 : x; goto rflag; } x = 0; while (is_digit(ch)) { x = 10 * x + to_digit(ch); ch = *fmt++; } prec = x < 0 ? -1 : x; goto reswitch; case '0': /* * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 */ flags |= ZEROPAD; goto rflag; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': x = 0; do { x = 10 * x + to_digit(ch); ch = *fmt++; } while (is_digit(ch)); width = x; goto reswitch; #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT case 'L': flags |= LONGDBL; goto rflag; #endif case 'h': flags |= SHORTINT; goto rflag; case 'l': if (*fmt == 'l') { fmt++; flags |= QUADINT; } else { flags |= LONGINT; } goto rflag; case 'q': flags |= QUADINT; goto rflag; case 'c': *(cp = buf) = va_arg(arg, int); size = 1; sign = '\0'; break; case 'D': flags |= LONGINT; /*FALLTHROUGH*/ case 'd': case 'i': _uquad = SARG(); #ifndef _NO_LONGLONG if ((quad_t)_uquad < 0) #else if ((long) _uquad < 0) #endif { _uquad = -_uquad; sign = '-'; } base = DEC; goto number; #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT case 'e': case 'E': case 'f': case 'g': case 'G': _double = va_arg(arg, double); /* * don't do unrealistic precision; just pad it with * zeroes later, so buffer size stays rational. */ if (prec > MAXFRACT) { if ((ch != 'g' && ch != 'G') || (flags&ALT)) fpprec = prec - MAXFRACT; prec = MAXFRACT; } else if (prec == -1) prec = DEFPREC; /* * cvt may have to round up before the "start" of * its buffer, i.e. ``intf("%.2f", (double)9.999);''; * if the first character is still NUL, it did. * softsign avoids negative 0 if _double < 0 but * no significant digits will be shown. */ cp = buf; *cp = '\0'; size = cvt(_double, prec, flags, &softsign, ch, cp, buf + sizeof(buf)); if (softsign) sign = '-'; if (*cp == '\0') cp++; break; #else case 'e': case 'E': case 'f': case 'g': case 'G': // Output nothing at all (void) va_arg(arg, double); // take off arg anyway cp = ""; size = 0; sign = '\0'; break; #endif // ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT case 'n': #ifndef _NO_LONGLONG if (flags & QUADINT) *va_arg(arg, quad_t *) = ret; else #endif if (flags & LONGINT) *va_arg(arg, long *) = ret; else if (flags & SHORTINT) *va_arg(arg, short *) = ret; else if (flags & SIZET) *va_arg(arg, size_t *) = ret; else *va_arg(arg, int *) = ret; continue; /* no output */ case 'O': flags |= LONGINT; /*FALLTHROUGH*/ case 'o': _uquad = UARG(); base = OCT; goto nosign; case 'p': /* * ``The argument shall be a pointer to void. The * value of the pointer is converted to a sequence * of printable characters, in an implementation- * defined manner.'' * -- ANSI X3J11 */ /* NOSTRICT */ _uquad = (unsigned long)va_arg(arg, void *); base = HEX; xdigs = "0123456789abcdef"; flags |= HEXPREFIX; ch = 'x'; goto nosign; case 's': if ((cp = va_arg(arg, char *)) == NULL) cp = "(null)"; if (prec >= 0) { /* * can't use strlen; can only look for the * NUL in the first `prec' characters, and * strlen() will go further. */ char *p = (char *)memchr(cp, 0, prec); if (p != NULL) { size = p - cp; if (size > prec) size = prec; } else size = prec; } else size = strlen(cp); sign = '\0'; break; case 'U': flags |= LONGINT; /*FALLTHROUGH*/ case 'u': _uquad = UARG(); base = DEC; goto nosign; case 'X': xdigs = "0123456789ABCDEF"; goto hex; case 'x': xdigs = "0123456789abcdef"; hex: _uquad = UARG(); base = HEX; /* leading 0x/X only if non-zero */ if (flags & ALT && _uquad != 0) flags |= HEXPREFIX; /* unsigned conversions */ nosign: sign = '\0'; /* * ``... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored.'' * -- ANSI X3J11 */ number: if ((dprec = prec) >= 0) flags &= ~ZEROPAD; /* * ``The result of converting a zero value with an * explicit precision of zero is no characters.'' * -- ANSI X3J11 */ cp = buf + BUF; if (_uquad != 0 || prec != 0) { /* * Unsigned mod is hard, and unsigned mod * by a constant is easier than that by * a variable; hence this switch. */ switch (base) { case OCT: do { *--cp = to_char(_uquad & 7); _uquad >>= 3; } while (_uquad); /* handle octal leading 0 */ if (flags & ALT && *cp != '0') *--cp = '0'; break; case DEC: /* many numbers are 1 digit */ while (_uquad >= 10) { *--cp = to_char(_uquad % 10); _uquad /= 10; } *--cp = to_char(_uquad); break; case HEX: do { *--cp = xdigs[_uquad & 15]; _uquad >>= 4; } while (_uquad); break; default: cp = "bug in vfprintf: bad base"; size = strlen(cp); goto skipsize; } } size = buf + BUF - cp; skipsize: break; case 'z': flags |= SIZET; goto rflag; default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') goto done; /* pretend it was %c with argument ch */ cp = buf; *cp = ch; size = 1; sign = '\0'; break; } /* * All reasonable formats wind up here. At this point, `cp' * points to a string which (if not flags&LADJUST) should be * padded out to `width' places. If flags&ZEROPAD, it should * first be prefixed by any sign or other prefix; otherwise, * it should be blank padded before the prefix is emitted. * After any left-hand padding and prefixing, emit zeroes * required by a decimal [diouxX] precision, then print the * string proper, then emit zeroes required by any leftover * floating precision; finally, if LADJUST, pad with blanks. * * Compute actual size, so we know how much to pad. * fieldsz excludes decimal prec; realsz includes it. */ #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT fieldsz = size + fpprec; #else fieldsz = size; #endif if (sign) fieldsz++; else if (flags & HEXPREFIX) fieldsz+= 2; realsz = dprec > fieldsz ? dprec : fieldsz; /* right-adjusting blank padding */ if ((flags & (LADJUST|ZEROPAD)) == 0) { if (width - realsz > 0) { PAD(width - realsz, blanks); ret += width - realsz; } } /* prefix */ if (sign) { PRINT(&sign, 1); ret++; } else if (flags & HEXPREFIX) { ox[0] = '0'; ox[1] = ch; PRINT(ox, 2); ret += 2; } /* right-adjusting zero padding */ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) { if (width - realsz > 0) { PAD(width - realsz, zeroes); ret += width - realsz; } } if (dprec - fieldsz > 0) { /* leading zeroes from decimal precision */ PAD(dprec - fieldsz, zeroes); ret += dprec - fieldsz; } /* the string or number proper */ PRINT(cp, size); ret += size; #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT /* trailing f.p. zeroes */ PAD(fpprec, zeroes); ret += fpprec; #endif /* left-adjusting padding (always blank) */ if (flags & LADJUST) { if (width - realsz > 0) { PAD(width - realsz, blanks); ret += width - realsz; } } } done: error: return (((Cyg_StdioStream *) stream)->get_error() ? EOF : ret); /* NOTREACHED */ } #ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT static char * round(double fract, int *exp, char *start, char *end, char ch, char *signp) { double tmp; if (fract) (void)modf(fract * 10, &tmp); else tmp = to_digit(ch); if (tmp > 4) for (;; --end) { if (*end == '.') --end; if (++*end <= '9') break; *end = '0'; if (end == start) { if (exp) { /* e/E; increment exponent */ *end = '1'; ++*exp; } else { /* f; add extra digit */ *--end = '1'; --start; } break; } } /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ else if (*signp == '-') for (;; --end) { if (*end == '.') --end; if (*end != '0') break; if (end == start) *signp = 0; } return (start); } // round() static char * exponent(char *p, int exp, int fmtch) { char *t; char expbuf[MAXEXP]; *p++ = fmtch; if (exp < 0) { exp = -exp; *p++ = '-'; } else *p++ = '+'; t = expbuf + MAXEXP; if (exp > 9) { do { *--t = to_char(exp % 10); } while ((exp /= 10) > 9); *--t = to_char(exp); for (; t < expbuf + MAXEXP; *p++ = *t++); } else { *p++ = '0'; *p++ = to_char(exp); } return (p); } // exponent() static int cvt(double number, int prec, int flags, char *signp, int fmtch, char *startp, char *endp) { Cyg_libm_ieee_double_shape_type ieeefp; char *t = startp; ieeefp.value = number; *signp = 0; if ( ieeefp.number.sign ){ // this checks for <0.0 and -0.0 number = -number; *signp = '-'; } if (finite(number)) { char *p; double fract; int dotrim, expcnt, gformat; double integer, tmp; dotrim = expcnt = gformat = 0; fract = modf(number, &integer); /* get an extra slot for rounding. */ t = ++startp; /* * get integer portion of number; put into the end of the buffer; the * .01 is added for modf(356.0 / 10, &integer) returning .59999999... */ for (p = endp - 1; integer; ++expcnt) { tmp = modf(integer / 10, &integer); *p-- = to_char((int)((tmp + .01) * 10)); } switch (fmtch) { case 'f': /* reverse integer into beginning of buffer */ if (expcnt) for (; ++p < endp; *t++ = *p); else *t++ = '0'; /* * if precision required or alternate flag set, add in a * decimal point. */ if (prec || flags&ALT) *t++ = '.'; /* if requires more precision and some fraction left */ if (fract) { if (prec) do { fract = modf(fract * 10, &tmp); *t++ = to_char((int)tmp); } while (--prec && fract); if (fract) startp = round(fract, (int *)NULL, startp, t - 1, (char)0, signp); } for (; prec--; *t++ = '0'); break; case 'e': case 'E': eformat: if (expcnt) { *t++ = *++p; if (prec || flags&ALT) *t++ = '.'; /* if requires more precision and some integer left */ for (; prec && ++p < endp; --prec) *t++ = *p; /* * if done precision and more of the integer component, * round using it; adjust fract so we don't re-round * later. */ if (!prec && ++p < endp) { fract = 0; startp = round((double)0, &expcnt, startp, t - 1, *p, signp); } /* adjust expcnt for digit in front of decimal */ --expcnt; } /* until first fractional digit, decrement exponent */ else if (fract) { /* adjust expcnt for digit in front of decimal */ for (expcnt = -1;; --expcnt) { fract = modf(fract * 10, &tmp); if (tmp) break; } *t++ = to_char((int)tmp); if (prec || flags&ALT) *t++ = '.'; } else { *t++ = '0'; if (prec || flags&ALT) *t++ = '.'; } /* if requires more precision and some fraction left */ if (fract) { if (prec) do { fract = modf(fract * 10, &tmp); *t++ = to_char((int)tmp); } while (--prec && fract); if (fract) startp = round(fract, &expcnt, startp, t - 1, (char)0, signp); } /* if requires more precision */ for (; prec--; *t++ = '0'); /* unless alternate flag, trim any g/G format trailing 0's */ if (gformat && !(flags&ALT)) { while (t > startp && *--t == '0'); if (*t == '.') --t; ++t; } t = exponent(t, expcnt, fmtch); break; case 'g': case 'G': /* a precision of 0 is treated as a precision of 1. */ if (!prec) ++prec; /* * ``The style used depends on the value converted; style e * will be used only if the exponent resulting from the * conversion is less than -4 or greater than the precision.'' * -- ANSI X3J11 */ if (expcnt > prec || (!expcnt && fract && fract < .0001)) { /* * g/G format counts "significant digits, not digits of * precision; for the e/E format, this just causes an * off-by-one problem, i.e. g/G considers the digit * before the decimal point significant and e/E doesn't * count it as precision. */ --prec; fmtch -= 2; /* G->E, g->e */ gformat = 1; goto eformat; } /* * reverse integer into beginning of buffer, * note, decrement precision */ if (expcnt) for (; ++p < endp; *t++ = *p, --prec); else *t++ = '0'; /* * if precision required or alternate flag set, add in a * decimal point. If no digits yet, add in leading 0. */ if (prec || flags&ALT) { dotrim = 1; *t++ = '.'; } else dotrim = 0; /* if requires more precision and some fraction left */ if (fract) { if (prec) { do { fract = modf(fract * 10, &tmp); *t++ = to_char((int)tmp); } while(!tmp); while (--prec && fract) { fract = modf(fract * 10, &tmp); *t++ = to_char((int)tmp); } } if (fract) startp = round(fract, (int *)NULL, startp, t - 1, (char)0, signp); } /* alternate format, adds 0's for precision, else trim 0's */ if (flags&ALT) for (; prec--; *t++ = '0'); else if (dotrim) { while (t > startp && *--t == '0'); if (*t != '.') ++t; } } } else { unsigned case_adj; switch (fmtch) { case 'f': case 'g': case 'e': case_adj = 'a' - 'A'; break; default: case_adj = 0; } if (isnan(number)) { *t++ = 'N' + case_adj; *t++ = 'A' + case_adj; *t++ = 'N' + case_adj; } else { // infinite *t++ = 'I' + case_adj; *t++ = 'N' + case_adj; *t++ = 'F' + case_adj; } } return (t - startp); } // cvt() #endif // ifdef CYGSEM_LIBC_STDIO_PRINTF_FLOATING_POINT // EOF vfnprintf.cxx
