sl@0: /* sl@0: * FUNCTION sl@0: * <>, <>, <>---format argument list sl@0: * INDEX sl@0: * vprintf sl@0: * INDEX sl@0: * vfprintf sl@0: * INDEX sl@0: * vsprintf sl@0: * ANSI_SYNOPSIS sl@0: * #include sl@0: * #include sl@0: * int vprintf(const char *<[fmt]>, va_list <[list]>); sl@0: * int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>); sl@0: * int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>); sl@0: * int _vprintf_r(void *<[reent]>, const char *<[fmt]>, sl@0: * va_list <[list]>); sl@0: * int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, sl@0: * va_list <[list]>); sl@0: * int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>, sl@0: * va_list <[list]>); sl@0: * TRAD_SYNOPSIS sl@0: * #include sl@0: * #include sl@0: * int vprintf( <[fmt]>, <[list]>) sl@0: * char *<[fmt]>; sl@0: * va_list <[list]>; sl@0: * int vfprintf(<[fp]>, <[fmt]>, <[list]>) sl@0: * FILE *<[fp]>; sl@0: * char *<[fmt]>; sl@0: * va_list <[list]>; sl@0: * int vsprintf(<[str]>, <[fmt]>, <[list]>) sl@0: * char *<[str]>; sl@0: * char *<[fmt]>; sl@0: * va_list <[list]>; sl@0: * int _vprintf_r(<[reent]>, <[fmt]>, <[list]>) sl@0: * char *<[reent]>; sl@0: * char *<[fmt]>; sl@0: * va_list <[list]>; sl@0: * int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>) sl@0: * char *<[reent]>; sl@0: * FILE *<[fp]>; sl@0: * char *<[fmt]>; sl@0: * va_list <[list]>; sl@0: * int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>) sl@0: * char *<[reent]>; sl@0: * char *<[str]>; sl@0: * char *<[fmt]>; sl@0: * va_list <[list]>; sl@0: * <>, <>, and <> are (respectively) sl@0: * variants of <>, <>, and <>. They differ sl@0: * only in allowing their caller to pass the variable argument list as a sl@0: * <> object (initialized by <>) rather than directly sl@0: * accepting a variable number of arguments. sl@0: * RETURNS sl@0: * The return values are consistent with the corresponding functions: sl@0: * <> returns the number of bytes in the output string, sl@0: * save that the concluding <> is not counted. sl@0: * <> and <> return the number of characters transmitted. sl@0: * If an error occurs, <> and <> return <>. No sl@0: * error returns occur for <>. sl@0: * PORTABILITY sl@0: * ANSI C requires all three functions. sl@0: * Supporting OS subroutines required: <>, <>, <>, sl@0: * <>, <>, <>, <>. sl@0: * sl@0: * sl@0: */ sl@0: sl@0: sl@0: sl@0: /*- sl@0: * Copyright (c) 1990 The Regents of the University of California. sl@0: * All rights reserved. sl@0: * sl@0: * This code is derived from software contributed to Berkeley by sl@0: * Chris Torek. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * This product includes software developed by the University of sl@0: * California, Berkeley and its contributors. sl@0: * 4. Neither the name of the University nor the names of its contributors sl@0: * may be used to endorse or promote products derived from this software sl@0: * without specific prior written permission. sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: */ sl@0: sl@0: /* sl@0: * Actual printf innards. sl@0: * sl@0: * This code is large and complicated... sl@0: */ sl@0: sl@0: #if 1 sl@0: #define _NO_LONGLONG sl@0: #endif sl@0: sl@0: #include <_ansi.h> sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: sl@0: #include "LOCAL.H" sl@0: #include "FVWRITE.H" sl@0: sl@0: sl@0: //cm sl@0: #include sl@0: sl@0: sl@0: /* sl@0: * Flush out all the vectors defined by the given uio, sl@0: * then reset it so that it can be reused. sl@0: */ sl@0: static int sl@0: __sprint(FILE *fp,register struct __suio *uio) sl@0: { sl@0: register int err; sl@0: sl@0: if (uio->uio_resid == 0) { sl@0: uio->uio_iovcnt = 0; sl@0: return (0); sl@0: } sl@0: err = __sfvwrite(fp, uio); sl@0: uio->uio_resid = 0; sl@0: uio->uio_iovcnt = 0; sl@0: return (err); sl@0: } sl@0: sl@0: /* sl@0: * Helper function for `fprintf to unbuffered unix file': creates a sl@0: * temporary buffer. We only work on write-only files; this avoids sl@0: * worries about ungetc buffers and so forth. sl@0: */ sl@0: static int sl@0: __sbprintf(register FILE *fp,const char *fmt,va_list ap) sl@0: { sl@0: int ret; sl@0: FILE fake; sl@0: unsigned char buf[BUFSIZ]; sl@0: sl@0: /* copy the important variables */ sl@0: fake._data = fp->_data; sl@0: fake._flags = (short)(fp->_flags & ~__SNBF); sl@0: fake._file = fp->_file; sl@0: fake._cookie = fp->_cookie; sl@0: fake._write = fp->_write; sl@0: sl@0: /* set up the buffer */ sl@0: fake._bf._base = fake._p = buf; sl@0: fake._bf._size = fake._w = sizeof(buf); sl@0: fake._lbfsize = 0; /* not actually used, but Just In Case */ sl@0: sl@0: /* do the work, then copy any error status */ sl@0: ret = vfprintf(&fake, fmt, ap); sl@0: if (ret >= 0 && fflush(&fake)) sl@0: ret = EOF; sl@0: if (fake._flags & __SERR) sl@0: fp->_flags |= __SERR; sl@0: return (ret); sl@0: } sl@0: sl@0: sl@0: /* #include for decimal_point */ sl@0: #include sl@0: #include "FLOATIO.H" sl@0: sl@0: #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ sl@0: #define DEFPREC 6 sl@0: sl@0: extern int e32cvt (char *buf, int buflen, double, int width, int prec, int flags, int fmt); sl@0: sl@0: sl@0: /* sl@0: * Macros for converting digits to letters and vice versa sl@0: */ sl@0: #define to_digit(c) ((c) - '0') sl@0: #define is_digit(c) ((unsigned)to_digit(c) <= 9) sl@0: #define to_char(n) ((n) + '0') sl@0: sl@0: /* sl@0: * Flags used during conversion. sl@0: */ sl@0: #define ALT 0x001 /* alternate form */ sl@0: #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ sl@0: #define LADJUST 0x004 /* left adjustment */ sl@0: #define LONGDBL 0x008 /* long double; unimplemented */ sl@0: #define LONGINT 0x010 /* long integer */ sl@0: #define QUADINT 0x020 /* quad integer */ sl@0: #define SHORTINT 0x040 /* short integer */ sl@0: #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ sl@0: #define FPT 0x100 /* Floating point number */ sl@0: sl@0: EXPORT_C int sl@0: vfprintf (FILE * fp, const char *fmt0, va_list ap) sl@0: { sl@0: return _vfprintf_r (fp->_data, fp, fmt0, ap); sl@0: } sl@0: sl@0: /** sl@0: A reentrant version of vfprintf(). sl@0: */ sl@0: EXPORT_C int sl@0: _vfprintf_r (struct _reent *data, FILE * fp, const char *fmt0, va_list ap) sl@0: { sl@0: register char *fmt; /* format string */ sl@0: register int ch; /* character from fmt */ sl@0: register int n, m; /* handy integers (short term usage) */ sl@0: register char *cp; /* handy char pointer (short term usage) */ sl@0: register struct __siov *iovp;/* for PRINT macro */ sl@0: register int flags; /* flags as above */ sl@0: int ret; /* return value accumulator */ sl@0: int width; /* width from format (%8d), or 0 */ sl@0: int prec; /* precision from format (%.3d), or -1 */ sl@0: char sign; /* sign prefix (' ', '+', '-', or \0) */ sl@0: wchar_t wc; sl@0: #if 0 sl@0: char *decimal_point = "."; /* localeconv()->decimal_point; */ sl@0: #endif sl@0: // char softsign; /* temporary negative sign for floats */ sl@0: double _double; /* double precision arguments %[eEfgG] */ sl@0: // int expt; /* integer value of exponent */ sl@0: // int expsize; /* character count for expstr */ sl@0: // int ndig; /* actual number of digits returned by cvt */ sl@0: // char expstr[7]; /* buffer for exponent string */ sl@0: sl@0: #ifndef _NO_LONGLONG sl@0: #define quad_t long long sl@0: #define u_quad_t unsigned long long sl@0: #endif sl@0: sl@0: #ifndef _NO_LONGLONG sl@0: u_quad_t _uquad; /* integer arguments %[diouxX] */ sl@0: #else sl@0: u_long _uquad; sl@0: #endif sl@0: enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ sl@0: int dprec; /* a copy of prec if [diouxX], 0 otherwise */ sl@0: int realsz; /* field size expanded by dprec */ sl@0: int size; /* size of converted field or string */ sl@0: char *xdigs = NULL; /* digits for [xX] conversion */ sl@0: #define NIOV 8 sl@0: struct __suio uio; /* output information: summary */ sl@0: struct __siov iov[NIOV];/* ... and individual io vectors */ sl@0: char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ sl@0: char ox[2]; /* space for 0x hex-prefix */ sl@0: sl@0: /* sl@0: * Choose PADSIZE to trade efficiency vs. size. If larger printf sl@0: * fields occur frequently, increase PADSIZE and make the initialisers sl@0: * below longer. sl@0: */ sl@0: #define PADSIZE 16 /* pad chunk size */ sl@0: static const char blanks[PADSIZE] = sl@0: {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; sl@0: static const char zeroes[PADSIZE] = sl@0: {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; sl@0: sl@0: /* sl@0: * BEWARE, these `goto error' on error, and PAD uses `n'. sl@0: */ sl@0: #define PRINT(ptr, len) { \ sl@0: iovp->iov_base = (ptr); \ sl@0: iovp->iov_len = (len); \ sl@0: uio.uio_resid += (len); \ sl@0: iovp++; \ sl@0: if (++uio.uio_iovcnt >= NIOV) { \ sl@0: if (__sprint(fp, &uio)) \ sl@0: goto error; \ sl@0: iovp = iov; \ sl@0: } \ sl@0: } sl@0: #define PAD(howmany, with) { \ sl@0: if ((n = (howmany)) > 0) { \ sl@0: while (n > PADSIZE) { \ sl@0: PRINT(with, PADSIZE); \ sl@0: n -= PADSIZE; \ sl@0: } \ sl@0: PRINT(with, n); \ sl@0: } \ sl@0: } sl@0: #define FLUSH() { \ sl@0: if (uio.uio_resid && __sprint(fp, &uio)) \ sl@0: goto error; \ sl@0: uio.uio_iovcnt = 0; \ sl@0: iovp = iov; \ sl@0: } sl@0: sl@0: /* sl@0: * To extend shorts properly, we need both signed and unsigned sl@0: * argument extraction methods. sl@0: */ sl@0: #ifndef _NO_LONGLONG sl@0: #define SARG() \ sl@0: (flags&QUADINT ? va_arg(ap, quad_t) : \ sl@0: flags&LONGINT ? va_arg(ap, long) : \ sl@0: flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ sl@0: (long)va_arg(ap, int)) sl@0: #define UARG() \ sl@0: (flags&QUADINT ? va_arg(ap, u_quad_t) : \ sl@0: flags&LONGINT ? va_arg(ap, u_long) : \ sl@0: flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ sl@0: (u_long)va_arg(ap, u_int)) sl@0: #else sl@0: #define SARG() \ sl@0: (flags&LONGINT ? va_arg(ap, long) : \ sl@0: flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ sl@0: (long)va_arg(ap, int)) sl@0: #define UARG() \ sl@0: (flags&LONGINT ? va_arg(ap, u_long) : \ sl@0: flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ sl@0: (u_long)va_arg(ap, u_int)) sl@0: #endif sl@0: sl@0: CHECK_INIT (fp); sl@0: sl@0: /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ sl@0: if (cantwrite(fp)) sl@0: return (EOF); sl@0: sl@0: /* optimise fprintf(stderr) (and other unbuffered Unix files) */ sl@0: if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && sl@0: fp->_file >= 0) sl@0: return (__sbprintf(fp, fmt0, ap)); sl@0: sl@0: fmt = (char *)fmt0; sl@0: uio.uio_iov = iovp = iov; sl@0: uio.uio_resid = 0; sl@0: uio.uio_iovcnt = 0; sl@0: ret = 0; sl@0: sl@0: /* sl@0: * Scan the format for conversions (`%' character). sl@0: */ sl@0: for (;;) { sl@0: cp = fmt; sl@0: while ((n = mbtowc(&wc, fmt, MB_CUR_MAX)) > 0) { sl@0: fmt += n; sl@0: if (wc == L'%') { sl@0: fmt--; sl@0: break; sl@0: } sl@0: } sl@0: if ((m = fmt - cp) != 0) { sl@0: PRINT(cp, m); sl@0: ret += m; sl@0: } sl@0: if (n <= 0) sl@0: goto done; sl@0: fmt++; /* skip over '%' */ sl@0: sl@0: flags = 0; sl@0: dprec = 0; sl@0: width = 0; sl@0: prec = -1; sl@0: sign = '\0'; sl@0: sl@0: rflag: ch = *fmt++; sl@0: reswitch: switch (ch) { sl@0: case ' ': sl@0: /* sl@0: * ``If the space and + flags both appear, the space sl@0: * flag will be ignored.'' sl@0: * -- ANSI X3J11 sl@0: */ sl@0: if (!sign) sl@0: sign = ' '; sl@0: goto rflag; sl@0: case '#': sl@0: flags |= ALT; sl@0: goto rflag; sl@0: case '*': sl@0: /* sl@0: * ``A negative field width argument is taken as a sl@0: * - flag followed by a positive field width.'' sl@0: * -- ANSI X3J11 sl@0: * They don't exclude field widths read from args. sl@0: */ sl@0: if ((width = va_arg(ap, int)) >= 0) sl@0: goto rflag; sl@0: width = -width; sl@0: /* FALLTHROUGH */ sl@0: case '-': sl@0: flags |= LADJUST; sl@0: goto rflag; sl@0: case '+': sl@0: sign = '+'; sl@0: goto rflag; sl@0: case '.': sl@0: if ((ch = *fmt++) == '*') { sl@0: n = va_arg(ap, int); sl@0: prec = n < 0 ? -1 : n; sl@0: goto rflag; sl@0: } sl@0: n = 0; sl@0: while (is_digit(ch)) { sl@0: n = 10 * n + to_digit(ch); sl@0: ch = *fmt++; sl@0: } sl@0: prec = n < 0 ? -1 : n; sl@0: goto reswitch; sl@0: case '0': sl@0: /* sl@0: * ``Note that 0 is taken as a flag, not as the sl@0: * beginning of a field width.'' sl@0: * -- ANSI X3J11 sl@0: */ sl@0: flags |= ZEROPAD; sl@0: goto rflag; sl@0: case '1': case '2': case '3': case '4': sl@0: case '5': case '6': case '7': case '8': case '9': sl@0: n = 0; sl@0: do { sl@0: n = 10 * n + to_digit(ch); sl@0: ch = *fmt++; sl@0: } while (is_digit(ch)); sl@0: width = n; sl@0: goto reswitch; sl@0: case 'L': sl@0: flags |= LONGDBL; sl@0: goto rflag; sl@0: case 'h': sl@0: flags |= SHORTINT; sl@0: goto rflag; sl@0: case 'l': sl@0: if (*fmt == 'l') { sl@0: fmt++; sl@0: flags |= QUADINT; sl@0: } else { sl@0: flags |= LONGINT; sl@0: } sl@0: goto rflag; sl@0: case 'q': sl@0: flags |= QUADINT; sl@0: goto rflag; sl@0: case 'c': sl@0: *(cp = buf) = (char)va_arg(ap, int); sl@0: size = 1; sl@0: sign = '\0'; sl@0: break; sl@0: case 'D': sl@0: flags |= LONGINT; sl@0: /*FALLTHROUGH*/ sl@0: case 'd': sl@0: case 'i': sl@0: _uquad = SARG(); sl@0: #ifndef _NO_LONGLONG sl@0: if ((quad_t)_uquad < 0) sl@0: #else sl@0: if ((long) _uquad < 0) sl@0: #endif sl@0: { sl@0: sl@0: #ifndef _NO_LONGLONG sl@0: _uquad = -_uquad; sl@0: #else sl@0: _uquad = (u_long)(-(long)_uquad); sl@0: #endif sl@0: sign = '-'; sl@0: } sl@0: base = DEC; sl@0: goto number; sl@0: sl@0: case 'e': sl@0: case 'E': sl@0: case 'f': sl@0: case 'g': sl@0: case 'G': sl@0: if (prec == -1) { sl@0: prec = DEFPREC; sl@0: } else if ((ch == 'g' || ch == 'G') && prec == 0) { sl@0: prec = 1; sl@0: } sl@0: sl@0: if (flags & LONGDBL) { sl@0: _double = (double) va_arg(ap, long double); sl@0: } else { sl@0: _double = va_arg(ap, double); sl@0: } sl@0: sl@0: /* do this before tricky precision changes */ sl@0: if (isinf(_double)) { sl@0: if (_double < 0) sl@0: sign = '-'; sl@0: cp = "Inf"; sl@0: size = 3; sl@0: break; sl@0: } sl@0: if (isnan(_double)) { sl@0: cp = "NaN"; sl@0: size = 3; sl@0: break; sl@0: } sl@0: flags |= FPT; sl@0: #if 0 sl@0: cp = cvt(data, _double, prec, flags, &softsign, sl@0: &expt, ch, &ndig); sl@0: if (ch == 'g' || ch == 'G') { sl@0: if (expt <= -4 || expt > prec) sl@0: ch = (ch == 'g') ? 'e' : 'E'; sl@0: else sl@0: ch = 'g'; sl@0: } sl@0: if (ch <= 'e') { /* 'e' or 'E' fmt */ sl@0: --expt; sl@0: expsize = exponent(expstr, expt, ch); sl@0: size = expsize + ndig; sl@0: if (ndig > 1 || flags & ALT) sl@0: ++size; sl@0: } else if (ch == 'f') { /* f fmt */ sl@0: if (expt > 0) { sl@0: size = expt; sl@0: if (prec || flags & ALT) sl@0: size += prec + 1; sl@0: } else /* "0.X" */ sl@0: size = prec + 2; sl@0: } else if (expt >= ndig) { /* fixed g fmt */ sl@0: size = expt; sl@0: if (flags & ALT) sl@0: ++size; sl@0: } else sl@0: size = ndig + (expt > 0 ? sl@0: 1 : 2 - expt); sl@0: sl@0: if (softsign) sl@0: sign = '-'; sl@0: #else sl@0: if (_double < 0) { sl@0: _double = -_double; sl@0: sign = '-'; sl@0: } sl@0: size = e32cvt(buf, BUF, _double, width, prec, flags, ch); sl@0: cp=buf; sl@0: #endif sl@0: break; sl@0: sl@0: case 'n': sl@0: #ifndef _NO_LONGLONG sl@0: if (flags & QUADINT) sl@0: *va_arg(ap, quad_t *) = ret; sl@0: else sl@0: #endif sl@0: if (flags & LONGINT) sl@0: *va_arg(ap, long *) = ret; sl@0: else if (flags & SHORTINT) sl@0: *va_arg(ap, short *) = (short)ret; sl@0: else sl@0: *va_arg(ap, int *) = ret; sl@0: continue; /* no output */ sl@0: case 'O': sl@0: flags |= LONGINT; sl@0: /*FALLTHROUGH*/ sl@0: case 'o': sl@0: _uquad = UARG(); sl@0: base = OCT; sl@0: goto nosign; sl@0: case 'p': sl@0: /* sl@0: * ``The argument shall be a pointer to void. The sl@0: * value of the pointer is converted to a sequence sl@0: * of printable characters, in an implementation- sl@0: * defined manner.'' sl@0: * -- ANSI X3J11 sl@0: */ sl@0: /* NOSTRICT */ sl@0: _uquad = (u_long)va_arg(ap, void *); sl@0: base = HEX; sl@0: xdigs = "0123456789abcdef"; sl@0: flags |= HEXPREFIX; sl@0: ch = 'x'; sl@0: goto nosign; sl@0: case 's': sl@0: if ((cp = va_arg(ap, char *)) == NULL) sl@0: cp = "(null)"; sl@0: if (prec >= 0) { sl@0: /* sl@0: * can't use strlen; can only look for the sl@0: * NUL in the first `prec' characters, and sl@0: * strlen() will go further. sl@0: */ sl@0: char *p = (char *)memchr(cp, 0, prec); sl@0: sl@0: if (p != NULL) { sl@0: size = p - cp; sl@0: if (size > prec) sl@0: size = prec; sl@0: } else sl@0: size = prec; sl@0: } else sl@0: size = strlen(cp); sl@0: sign = '\0'; sl@0: break; sl@0: case 'U': sl@0: flags |= LONGINT; sl@0: /*FALLTHROUGH*/ sl@0: case 'u': sl@0: _uquad = UARG(); sl@0: base = DEC; sl@0: goto nosign; sl@0: case 'X': sl@0: xdigs = "0123456789ABCDEF"; sl@0: goto hex; sl@0: case 'x': sl@0: xdigs = "0123456789abcdef"; sl@0: hex: _uquad = UARG(); sl@0: base = HEX; sl@0: /* leading 0x/X only if non-zero */ sl@0: if (flags & ALT && _uquad != 0) sl@0: flags |= HEXPREFIX; sl@0: sl@0: /* unsigned conversions */ sl@0: nosign: sign = '\0'; sl@0: /* sl@0: * ``... diouXx conversions ... if a precision is sl@0: * specified, the 0 flag will be ignored.'' sl@0: * -- ANSI X3J11 sl@0: */ sl@0: number: if ((dprec = prec) >= 0) sl@0: flags &= ~ZEROPAD; sl@0: sl@0: /* sl@0: * ``The result of converting a zero value with an sl@0: * explicit precision of zero is no characters.'' sl@0: * -- ANSI X3J11 sl@0: */ sl@0: cp = buf + BUF; sl@0: if (_uquad != 0 || prec != 0) { sl@0: /* sl@0: * Unsigned mod is hard, and unsigned mod sl@0: * by a constant is easier than that by sl@0: * a variable; hence this switch. sl@0: */ sl@0: switch (base) { sl@0: case OCT: sl@0: do { sl@0: *--cp = (char)to_char(_uquad & 7); sl@0: _uquad >>= 3; sl@0: } while (_uquad); sl@0: /* handle octal leading 0 */ sl@0: if (flags & ALT && *cp != '0') sl@0: *--cp = '0'; sl@0: break; sl@0: sl@0: case DEC: sl@0: /* many numbers are 1 digit */ sl@0: while (_uquad >= 10) { sl@0: *--cp = (char)to_char(_uquad % 10); sl@0: _uquad /= 10; sl@0: } sl@0: *--cp = (char)to_char(_uquad); sl@0: break; sl@0: sl@0: case HEX: sl@0: do { sl@0: *--cp = xdigs[_uquad & 15]; sl@0: _uquad >>= 4; sl@0: } while (_uquad); sl@0: break; sl@0: sl@0: default: sl@0: cp = "bug in vfprintf: bad base"; sl@0: size = strlen(cp); sl@0: goto skipsize; sl@0: } sl@0: } sl@0: /* Workaround GCC compiler bug: size = buf + BUF - cp */ sl@0: { sl@0: char *temp = buf+BUF; sl@0: size = temp - cp; sl@0: } sl@0: skipsize: sl@0: break; sl@0: default: /* "%?" prints ?, unless ? is NUL */ sl@0: if (ch == '\0') sl@0: goto done; sl@0: /* pretend it was %c with argument ch */ sl@0: cp = buf; sl@0: *cp = (char)ch; sl@0: size = 1; sl@0: sign = '\0'; sl@0: break; sl@0: } sl@0: sl@0: /* sl@0: * All reasonable formats wind up here. At this point, `cp' sl@0: * points to a string which (if not flags&LADJUST) should be sl@0: * padded out to `width' places. If flags&ZEROPAD, it should sl@0: * first be prefixed by any sign or other prefix; otherwise, sl@0: * it should be blank padded before the prefix is emitted. sl@0: * After any left-hand padding and prefixing, emit zeroes sl@0: * required by a decimal [diouxX] precision, then print the sl@0: * string proper, then emit zeroes required by any leftover sl@0: * floating precision; finally, if LADJUST, pad with blanks. sl@0: * sl@0: * Compute actual size, so we know how much to pad. sl@0: * size excludes decimal prec; realsz includes it. sl@0: */ sl@0: realsz = dprec > size ? dprec : size; sl@0: if (sign) sl@0: realsz++; sl@0: else if (flags & HEXPREFIX) sl@0: realsz+= 2; sl@0: sl@0: /* right-adjusting blank padding */ sl@0: if ((flags & (LADJUST|ZEROPAD)) == 0) sl@0: PAD(width - realsz, blanks); sl@0: sl@0: /* prefix */ sl@0: if (sign) { sl@0: PRINT(&sign, 1); sl@0: } else if (flags & HEXPREFIX) { sl@0: ox[0] = '0'; sl@0: ox[1] = (char)ch; sl@0: PRINT(ox, 2); sl@0: } sl@0: sl@0: /* right-adjusting zero padding */ sl@0: if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) sl@0: PAD(width - realsz, zeroes); sl@0: sl@0: /* leading zeroes from decimal precision */ sl@0: PAD(dprec - size, zeroes); sl@0: sl@0: /* the string or number proper */ sl@0: PRINT(cp, size); sl@0: #if 0 sl@0: } else { /* glue together f_p fragments */ sl@0: if (ch >= 'f') { /* 'f' or 'g' */ sl@0: if (_double == 0) { sl@0: /* kludge for __dtoa irregularity */ sl@0: PRINT("0", 1); sl@0: if (expt < ndig || (flags & ALT) != 0) { sl@0: PRINT(decimal_point, 1); sl@0: PAD(ndig - 1, zeroes); sl@0: } sl@0: } else if (expt <= 0) { sl@0: PRINT("0", 1); sl@0: PRINT(decimal_point, 1); sl@0: PAD(-expt, zeroes); sl@0: PRINT(cp, ndig); sl@0: } else if (expt >= ndig) { sl@0: PRINT(cp, ndig); sl@0: PAD(expt - ndig, zeroes); sl@0: if (flags & ALT) sl@0: PRINT(".", 1); sl@0: } else { sl@0: PRINT(cp, expt); sl@0: cp += expt; sl@0: PRINT(".", 1); sl@0: PRINT(cp, ndig-expt); sl@0: } sl@0: } else { /* 'e' or 'E' */ sl@0: if (ndig > 1 || flags & ALT) { sl@0: ox[0] = *cp++; sl@0: ox[1] = '.'; sl@0: PRINT(ox, 2); sl@0: if (_double || (flags & ALT) == 0) { sl@0: PRINT(cp, ndig-1); sl@0: } else /* 0.[0..] */ sl@0: /* __dtoa irregularity */ sl@0: PAD(ndig - 1, zeroes); sl@0: } else /* XeYYY */ sl@0: PRINT(cp, 1); sl@0: PRINT(expstr, expsize); sl@0: } sl@0: } sl@0: #endif sl@0: /* left-adjusting padding (always blank) */ sl@0: if (flags & LADJUST) sl@0: PAD(width - realsz, blanks); sl@0: sl@0: /* finally, adjust ret */ sl@0: ret += width > realsz ? width : realsz; sl@0: sl@0: FLUSH(); /* copy out the I/O vectors */ sl@0: } sl@0: done: sl@0: FLUSH(); sl@0: error: sl@0: return (__sferror(fp) ? EOF : ret); sl@0: /* NOTREACHED */ sl@0: } sl@0: sl@0: #if 0 sl@0: static char * sl@0: cvt(struct _reent *data,double value,int ndigits, int flags, char *sign, int *decpt, int ch, int *length) sl@0: { sl@0: int mode, dsgn; sl@0: char *digits, *bp, *rve; sl@0: sl@0: if (ch == 'f') { sl@0: mode = 3; /* ndigits after the decimal point */ sl@0: } else { sl@0: /* To obtain ndigits after the decimal point for the 'e' sl@0: * and 'E' formats, round to ndigits + 1 significant sl@0: * figures. sl@0: */ sl@0: if (ch == 'e' || ch == 'E') { sl@0: ndigits++; sl@0: } sl@0: mode = 2; /* ndigits significant digits */ sl@0: } sl@0: sl@0: if (value < 0) { sl@0: value = -value; sl@0: *sign = '-'; sl@0: } else sl@0: *sign = '\000'; sl@0: digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve); sl@0: if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ sl@0: bp = digits + ndigits; sl@0: if (ch == 'f') { sl@0: if (*digits == '0' && value) sl@0: *decpt = -ndigits + 1; sl@0: bp += *decpt; sl@0: } sl@0: if (value == 0) /* kludge for __dtoa irregularity */ sl@0: rve = bp; sl@0: while (rve < bp) sl@0: *rve++ = '0'; sl@0: } sl@0: *length = rve - digits; sl@0: return (digits); sl@0: } sl@0: sl@0: static int sl@0: exponent(char *p0, int exp, int fmtch) sl@0: { sl@0: register char *p, *t; sl@0: char expbuf[MAXEXP]; sl@0: sl@0: p = p0; sl@0: *p++ = (char)fmtch; sl@0: if (exp < 0) { sl@0: exp = -exp; sl@0: *p++ = '-'; sl@0: } sl@0: else sl@0: *p++ = '+'; sl@0: t = expbuf + MAXEXP; sl@0: if (exp > 9) { sl@0: do { sl@0: *--t = (char)to_char(exp % 10); sl@0: } while ((exp /= 10) > 9); sl@0: *--t = (char)to_char(exp); sl@0: for (; t < expbuf + MAXEXP; *p++ = *t++); sl@0: } sl@0: else { sl@0: *p++ = '0'; sl@0: *p++ = (char)to_char(exp); sl@0: } sl@0: return (p - p0); sl@0: } sl@0: #endif