146076Sbostic /*- 246076Sbostic * Copyright (c) 1990 The Regents of the University of California. 334233Sbostic * All rights reserved. 434226Sbostic * 546076Sbostic * This code is derived from software contributed to Berkeley by 646076Sbostic * Chris Torek. 746076Sbostic * 842631Sbostic * %sccs.include.redist.c% 934226Sbostic */ 1034226Sbostic 1134233Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*57154Sbostic static char sccsid[] = "@(#)vfprintf.c 5.50 (Berkeley) 12/16/92"; 1334233Sbostic #endif /* LIBC_SCCS and not lint */ 1434233Sbostic 1546076Sbostic /* 1646076Sbostic * Actual printf innards. 1746076Sbostic * 1846076Sbostic * This code is large and complicated... 1946076Sbostic */ 2046076Sbostic 2134261Sbostic #include <sys/types.h> 22*57154Sbostic 2346076Sbostic #include <stdio.h> 24*57154Sbostic #include <stdlib.h> 2546076Sbostic #include <string.h> 26*57154Sbostic 2746076Sbostic #if __STDC__ 2846076Sbostic #include <stdarg.h> 2946076Sbostic #else 3034233Sbostic #include <varargs.h> 3146076Sbostic #endif 32*57154Sbostic 3346076Sbostic #include "local.h" 3446076Sbostic #include "fvwrite.h" 3534226Sbostic 3650438Sbostic /* Define FLOATING_POINT to get floating point. */ 3746076Sbostic #define FLOATING_POINT 3834226Sbostic 3946076Sbostic /* 4046076Sbostic * Flush out all the vectors defined by the given uio, 4146076Sbostic * then reset it so that it can be reused. 4246076Sbostic */ 4346180Storek static int 4446076Sbostic __sprint(fp, uio) 4546076Sbostic FILE *fp; 4646076Sbostic register struct __suio *uio; 4746076Sbostic { 4846076Sbostic register int err; 4946076Sbostic 5046076Sbostic if (uio->uio_resid == 0) { 5146076Sbostic uio->uio_iovcnt = 0; 5246076Sbostic return (0); 5346076Sbostic } 5446076Sbostic err = __sfvwrite(fp, uio); 5546076Sbostic uio->uio_resid = 0; 5646076Sbostic uio->uio_iovcnt = 0; 5746076Sbostic return (err); 5846076Sbostic } 5946076Sbostic 6046076Sbostic /* 6146076Sbostic * Helper function for `fprintf to unbuffered unix file': creates a 6246076Sbostic * temporary buffer. We only work on write-only files; this avoids 6346076Sbostic * worries about ungetc buffers and so forth. 6446076Sbostic */ 6546180Storek static int 6646076Sbostic __sbprintf(fp, fmt, ap) 6746076Sbostic register FILE *fp; 6846180Storek const char *fmt; 6946076Sbostic va_list ap; 7046076Sbostic { 7146076Sbostic int ret; 7246076Sbostic FILE fake; 7346076Sbostic unsigned char buf[BUFSIZ]; 7446076Sbostic 7546076Sbostic /* copy the important variables */ 7646076Sbostic fake._flags = fp->_flags & ~__SNBF; 7746076Sbostic fake._file = fp->_file; 7846076Sbostic fake._cookie = fp->_cookie; 7946076Sbostic fake._write = fp->_write; 8046076Sbostic 8146076Sbostic /* set up the buffer */ 8246076Sbostic fake._bf._base = fake._p = buf; 8346076Sbostic fake._bf._size = fake._w = sizeof(buf); 8446076Sbostic fake._lbfsize = 0; /* not actually used, but Just In Case */ 8546076Sbostic 8646076Sbostic /* do the work, then copy any error status */ 8746076Sbostic ret = vfprintf(&fake, fmt, ap); 8846076Sbostic if (ret >= 0 && fflush(&fake)) 8946076Sbostic ret = EOF; 9046076Sbostic if (fake._flags & __SERR) 9146076Sbostic fp->_flags |= __SERR; 9246076Sbostic return (ret); 9346076Sbostic } 9446076Sbostic 9546076Sbostic 9646076Sbostic #ifdef FLOATING_POINT 97*57154Sbostic #include <math.h> 9846180Storek #include "floatio.h" 9946076Sbostic 10034328Sbostic #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 10146076Sbostic #define DEFPREC 6 10234328Sbostic 103*57154Sbostic static char *cvt __P((double, int, int, char *, int *, int, int *)); 104*57154Sbostic static int exponent __P((char *, int, int)); 10534236Sbostic 10646076Sbostic #else /* no FLOATING_POINT */ 10734235Sbostic 10846076Sbostic #define BUF 40 10934331Sbostic 11046076Sbostic #endif /* FLOATING_POINT */ 11134318Sbostic 11246076Sbostic 11346076Sbostic /* 11446076Sbostic * Macros for converting digits to letters and vice versa 11546076Sbostic */ 11646076Sbostic #define to_digit(c) ((c) - '0') 11746076Sbostic #define is_digit(c) ((unsigned)to_digit(c) <= 9) 11846076Sbostic #define to_char(n) ((n) + '0') 11946076Sbostic 12046076Sbostic /* 12146076Sbostic * Flags used during conversion. 12246076Sbostic */ 12353810Sbostic #define ALT 0x001 /* alternate form */ 12453810Sbostic #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 12553810Sbostic #define LADJUST 0x004 /* left adjustment */ 12653810Sbostic #define LONGDBL 0x008 /* long double; unimplemented */ 12753810Sbostic #define LONGINT 0x010 /* long integer */ 12853810Sbostic #define QUADINT 0x020 /* quad integer */ 12953810Sbostic #define SHORTINT 0x040 /* short integer */ 13053810Sbostic #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 131*57154Sbostic #define FPT 0x100 /* Floating point number */ 13246180Storek int 13346076Sbostic vfprintf(fp, fmt0, ap) 13446076Sbostic FILE *fp; 13546180Storek const char *fmt0; 13646076Sbostic va_list ap; 13734226Sbostic { 13846076Sbostic register char *fmt; /* format string */ 13934427Sbostic register int ch; /* character from fmt */ 14046076Sbostic register int n; /* handy integer (short term usage) */ 14146076Sbostic register char *cp; /* handy char pointer (short term usage) */ 14246076Sbostic register struct __siov *iovp;/* for PRINT macro */ 14346076Sbostic register int flags; /* flags as above */ 14446076Sbostic int ret; /* return value accumulator */ 14546076Sbostic int width; /* width from format (%8d), or 0 */ 14646076Sbostic int prec; /* precision from format (%.3d), or -1 */ 14746076Sbostic char sign; /* sign prefix (' ', '+', '-', or \0) */ 14846076Sbostic #ifdef FLOATING_POINT 14946076Sbostic char softsign; /* temporary negative sign for floats */ 15034427Sbostic double _double; /* double precision arguments %[eEfgG] */ 151*57154Sbostic int expt; /* integer value of exponent */ 152*57154Sbostic int expsize; /* character count for expstr */ 153*57154Sbostic int ndig; /* actual number of digits returned by cvt */ 154*57154Sbostic char expstr[7]; /* buffer for exponent string */ 15546076Sbostic #endif 15653810Sbostic u_quad_t _uquad; /* integer arguments %[diouxX] */ 15746076Sbostic enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ 15846076Sbostic int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 15934624Sbostic int fieldsz; /* field size expanded by sign, etc */ 16046076Sbostic int realsz; /* field size expanded by dprec */ 16134427Sbostic int size; /* size of converted field or string */ 16246076Sbostic char *xdigs; /* digits for [xX] conversion */ 16346076Sbostic #define NIOV 8 16446076Sbostic struct __suio uio; /* output information: summary */ 16546076Sbostic struct __siov iov[NIOV];/* ... and individual io vectors */ 16634427Sbostic char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 16746076Sbostic char ox[2]; /* space for 0x hex-prefix */ 16834226Sbostic 16946076Sbostic /* 17053810Sbostic * Choose PADSIZE to trade efficiency vs. size. If larger printf 17153810Sbostic * fields occur frequently, increase PADSIZE and make the initialisers 17253810Sbostic * below longer. 17346076Sbostic */ 17446076Sbostic #define PADSIZE 16 /* pad chunk size */ 17546076Sbostic static char blanks[PADSIZE] = 17646076Sbostic {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 17746076Sbostic static char zeroes[PADSIZE] = 17846076Sbostic {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 17946076Sbostic 18046076Sbostic /* 18146076Sbostic * BEWARE, these `goto error' on error, and PAD uses `n'. 18246076Sbostic */ 18346076Sbostic #define PRINT(ptr, len) { \ 18446076Sbostic iovp->iov_base = (ptr); \ 18546076Sbostic iovp->iov_len = (len); \ 18646076Sbostic uio.uio_resid += (len); \ 18746076Sbostic iovp++; \ 18846076Sbostic if (++uio.uio_iovcnt >= NIOV) { \ 18946076Sbostic if (__sprint(fp, &uio)) \ 19046076Sbostic goto error; \ 19146076Sbostic iovp = iov; \ 19246076Sbostic } \ 19346076Sbostic } 19446076Sbostic #define PAD(howmany, with) { \ 19546076Sbostic if ((n = (howmany)) > 0) { \ 19646076Sbostic while (n > PADSIZE) { \ 19746076Sbostic PRINT(with, PADSIZE); \ 19846076Sbostic n -= PADSIZE; \ 19946076Sbostic } \ 20046076Sbostic PRINT(with, n); \ 20146076Sbostic } \ 20246076Sbostic } 20346076Sbostic #define FLUSH() { \ 20446076Sbostic if (uio.uio_resid && __sprint(fp, &uio)) \ 20546076Sbostic goto error; \ 20646076Sbostic uio.uio_iovcnt = 0; \ 20746076Sbostic iovp = iov; \ 20846076Sbostic } 20946076Sbostic 21046076Sbostic /* 21146076Sbostic * To extend shorts properly, we need both signed and unsigned 21246076Sbostic * argument extraction methods. 21346076Sbostic */ 21446076Sbostic #define SARG() \ 21553810Sbostic (flags&QUADINT ? va_arg(ap, quad_t) : \ 21653810Sbostic flags&LONGINT ? va_arg(ap, long) : \ 21746076Sbostic flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 21846076Sbostic (long)va_arg(ap, int)) 21946076Sbostic #define UARG() \ 22053810Sbostic (flags&QUADINT ? va_arg(ap, u_quad_t) : \ 22153810Sbostic flags&LONGINT ? va_arg(ap, u_long) : \ 22246076Sbostic flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ 22346076Sbostic (u_long)va_arg(ap, u_int)) 22446076Sbostic 22546076Sbostic /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 22646076Sbostic if (cantwrite(fp)) 22734428Sbostic return (EOF); 22834428Sbostic 22946076Sbostic /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 23046076Sbostic if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 23146076Sbostic fp->_file >= 0) 23246076Sbostic return (__sbprintf(fp, fmt0, ap)); 23346076Sbostic 23446076Sbostic fmt = (char *)fmt0; 23546076Sbostic uio.uio_iov = iovp = iov; 23646076Sbostic uio.uio_resid = 0; 23746076Sbostic uio.uio_iovcnt = 0; 23846076Sbostic ret = 0; 23946076Sbostic 24046076Sbostic /* 24146076Sbostic * Scan the format for conversions (`%' character). 24246076Sbostic */ 24346076Sbostic for (;;) { 24446076Sbostic for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 24546076Sbostic /* void */; 24646076Sbostic if ((n = fmt - cp) != 0) { 24746076Sbostic PRINT(cp, n); 24846076Sbostic ret += n; 24946076Sbostic } 25046076Sbostic if (ch == '\0') 25146076Sbostic goto done; 25246076Sbostic fmt++; /* skip over '%' */ 25346076Sbostic 25446076Sbostic flags = 0; 25546076Sbostic dprec = 0; 25646076Sbostic width = 0; 25734233Sbostic prec = -1; 25834318Sbostic sign = '\0'; 25934226Sbostic 26046076Sbostic rflag: ch = *fmt++; 26146076Sbostic reswitch: switch (ch) { 26234318Sbostic case ' ': 26334669Sbostic /* 26434669Sbostic * ``If the space and + flags both appear, the space 26534669Sbostic * flag will be ignored.'' 26634669Sbostic * -- ANSI X3J11 26734669Sbostic */ 26834669Sbostic if (!sign) 26934669Sbostic sign = ' '; 27034318Sbostic goto rflag; 27134233Sbostic case '#': 27234318Sbostic flags |= ALT; 27334318Sbostic goto rflag; 27434233Sbostic case '*': 27534235Sbostic /* 27634235Sbostic * ``A negative field width argument is taken as a 27746076Sbostic * - flag followed by a positive field width.'' 27834235Sbostic * -- ANSI X3J11 27934235Sbostic * They don't exclude field widths read from args. 28034235Sbostic */ 28146076Sbostic if ((width = va_arg(ap, int)) >= 0) 28234318Sbostic goto rflag; 28334235Sbostic width = -width; 28434427Sbostic /* FALLTHROUGH */ 28534235Sbostic case '-': 28634318Sbostic flags |= LADJUST; 28734318Sbostic goto rflag; 28834233Sbostic case '+': 28934314Sbostic sign = '+'; 29034318Sbostic goto rflag; 29134233Sbostic case '.': 29246076Sbostic if ((ch = *fmt++) == '*') { 29346076Sbostic n = va_arg(ap, int); 29446076Sbostic prec = n < 0 ? -1 : n; 29546076Sbostic goto rflag; 29634226Sbostic } 29746076Sbostic n = 0; 29846076Sbostic while (is_digit(ch)) { 29946076Sbostic n = 10 * n + to_digit(ch); 30046076Sbostic ch = *fmt++; 30146076Sbostic } 30234318Sbostic prec = n < 0 ? -1 : n; 30346076Sbostic goto reswitch; 30434233Sbostic case '0': 30534427Sbostic /* 30634427Sbostic * ``Note that 0 is taken as a flag, not as the 30734427Sbostic * beginning of a field width.'' 30834427Sbostic * -- ANSI X3J11 30934427Sbostic */ 31034427Sbostic flags |= ZEROPAD; 31134427Sbostic goto rflag; 31234233Sbostic case '1': case '2': case '3': case '4': 31334233Sbostic case '5': case '6': case '7': case '8': case '9': 31434318Sbostic n = 0; 31534233Sbostic do { 31646076Sbostic n = 10 * n + to_digit(ch); 31746076Sbostic ch = *fmt++; 31846076Sbostic } while (is_digit(ch)); 31934318Sbostic width = n; 32046076Sbostic goto reswitch; 32146076Sbostic #ifdef FLOATING_POINT 32234235Sbostic case 'L': 32334329Sbostic flags |= LONGDBL; 32434318Sbostic goto rflag; 32546076Sbostic #endif 32634235Sbostic case 'h': 32734318Sbostic flags |= SHORTINT; 32834318Sbostic goto rflag; 32934233Sbostic case 'l': 33034318Sbostic flags |= LONGINT; 33134318Sbostic goto rflag; 33253810Sbostic case 'q': 33353810Sbostic flags |= QUADINT; 33453810Sbostic goto rflag; 33534314Sbostic case 'c': 33646076Sbostic *(cp = buf) = va_arg(ap, int); 33734314Sbostic size = 1; 33834427Sbostic sign = '\0'; 33946076Sbostic break; 34034624Sbostic case 'D': 34134624Sbostic flags |= LONGINT; 34234624Sbostic /*FALLTHROUGH*/ 34334314Sbostic case 'd': 34434318Sbostic case 'i': 34553810Sbostic _uquad = SARG(); 34653810Sbostic if ((quad_t)_uquad < 0) { 34753810Sbostic _uquad = -_uquad; 34834314Sbostic sign = '-'; 34934241Sbostic } 35046076Sbostic base = DEC; 35134327Sbostic goto number; 35246076Sbostic #ifdef FLOATING_POINT 353*57154Sbostic case 'e': /* anomalous precision */ 35434236Sbostic case 'E': 355*57154Sbostic prec = (prec == -1) ? 356*57154Sbostic DEFPREC + 1 : prec + 1; 357*57154Sbostic /* FALLTHROUGH */ 358*57154Sbostic goto fp_begin; 359*57154Sbostic case 'f': /* always print trailing zeroes */ 360*57154Sbostic if (prec != 0) 361*57154Sbostic flags |= ALT; 36234261Sbostic case 'g': 36334243Sbostic case 'G': 364*57154Sbostic if (prec == -1) 365*57154Sbostic prec = DEFPREC; 366*57154Sbostic fp_begin: _double = va_arg(ap, double); 36746126Storek /* do this before tricky precision changes */ 36847607Sbostic if (isinf(_double)) { 36947607Sbostic if (_double < 0) 37047607Sbostic sign = '-'; 37147607Sbostic cp = "Inf"; 37247607Sbostic size = 3; 37346126Storek break; 37446126Storek } 37547607Sbostic if (isnan(_double)) { 37647607Sbostic cp = "NaN"; 37747607Sbostic size = 3; 37847607Sbostic break; 37947607Sbostic } 380*57154Sbostic flags |= FPT; 381*57154Sbostic cp = cvt(_double, prec, flags, &softsign, 382*57154Sbostic &expt, ch, &ndig); 383*57154Sbostic if (ch == 'g' || ch == 'G') { 384*57154Sbostic if (expt <= -4 || expt > prec) 385*57154Sbostic ch = (ch == 'g') ? 'e' : 'E'; 386*57154Sbostic else 387*57154Sbostic ch = 'g'; 388*57154Sbostic } 389*57154Sbostic if (ch <= 'e') { /* 'e' or 'E' fmt */ 390*57154Sbostic --expt; 391*57154Sbostic expsize = exponent(expstr, expt, ch); 392*57154Sbostic size = expsize + ndig; 393*57154Sbostic if (ndig > 1 || flags & ALT) 394*57154Sbostic ++size; 395*57154Sbostic } else if (ch == 'f') { /* f fmt */ 396*57154Sbostic if (expt > 0) { 397*57154Sbostic size = expt; 398*57154Sbostic if (prec || flags & ALT) 399*57154Sbostic size += prec + 1; 400*57154Sbostic } else /* "0.X" */ 401*57154Sbostic size = prec + 2; 402*57154Sbostic } else if (expt >= ndig) { /* fixed g fmt */ 403*57154Sbostic size = expt; 404*57154Sbostic if (flags & ALT) 405*57154Sbostic ++size; 406*57154Sbostic } else 407*57154Sbostic size = ndig + (expt > 0 ? 408*57154Sbostic 1 : 2 - expt); 409*57154Sbostic 41034669Sbostic if (softsign) 41134669Sbostic sign = '-'; 41246076Sbostic break; 41346076Sbostic #endif /* FLOATING_POINT */ 41434235Sbostic case 'n': 41553810Sbostic if (flags & QUADINT) 41653810Sbostic *va_arg(ap, quad_t *) = ret; 41753810Sbostic else if (flags & LONGINT) 41846076Sbostic *va_arg(ap, long *) = ret; 41934427Sbostic else if (flags & SHORTINT) 42046076Sbostic *va_arg(ap, short *) = ret; 42134318Sbostic else 42246076Sbostic *va_arg(ap, int *) = ret; 42346076Sbostic continue; /* no output */ 42434624Sbostic case 'O': 42534624Sbostic flags |= LONGINT; 42634624Sbostic /*FALLTHROUGH*/ 42734226Sbostic case 'o': 42853810Sbostic _uquad = UARG(); 42946076Sbostic base = OCT; 43034327Sbostic goto nosign; 43134235Sbostic case 'p': 43234320Sbostic /* 43334321Sbostic * ``The argument shall be a pointer to void. The 43434321Sbostic * value of the pointer is converted to a sequence 43534321Sbostic * of printable characters, in an implementation- 43634321Sbostic * defined manner.'' 43734321Sbostic * -- ANSI X3J11 43834320Sbostic */ 43934427Sbostic /* NOSTRICT */ 44053810Sbostic _uquad = (u_quad_t)va_arg(ap, void *); 44146076Sbostic base = HEX; 44246076Sbostic xdigs = "0123456789abcdef"; 44346076Sbostic flags |= HEXPREFIX; 44446076Sbostic ch = 'x'; 44534327Sbostic goto nosign; 44634226Sbostic case 's': 44746076Sbostic if ((cp = va_arg(ap, char *)) == NULL) 44846076Sbostic cp = "(null)"; 44934321Sbostic if (prec >= 0) { 45034321Sbostic /* 45134321Sbostic * can't use strlen; can only look for the 45234321Sbostic * NUL in the first `prec' characters, and 45334321Sbostic * strlen() will go further. 45434321Sbostic */ 45546076Sbostic char *p = memchr(cp, 0, prec); 45634321Sbostic 45746076Sbostic if (p != NULL) { 45846076Sbostic size = p - cp; 45934321Sbostic if (size > prec) 46034321Sbostic size = prec; 46134427Sbostic } else 46234321Sbostic size = prec; 46334427Sbostic } else 46446076Sbostic size = strlen(cp); 46534427Sbostic sign = '\0'; 46646076Sbostic break; 46734624Sbostic case 'U': 46834624Sbostic flags |= LONGINT; 46934624Sbostic /*FALLTHROUGH*/ 47034226Sbostic case 'u': 47153810Sbostic _uquad = UARG(); 47246076Sbostic base = DEC; 47334327Sbostic goto nosign; 47434226Sbostic case 'X': 47546076Sbostic xdigs = "0123456789ABCDEF"; 47646076Sbostic goto hex; 47734226Sbostic case 'x': 47846076Sbostic xdigs = "0123456789abcdef"; 47953810Sbostic hex: _uquad = UARG(); 48046076Sbostic base = HEX; 48134326Sbostic /* leading 0x/X only if non-zero */ 48253810Sbostic if (flags & ALT && _uquad != 0) 48334427Sbostic flags |= HEXPREFIX; 48434327Sbostic 48534327Sbostic /* unsigned conversions */ 48634427Sbostic nosign: sign = '\0'; 48734326Sbostic /* 48834330Sbostic * ``... diouXx conversions ... if a precision is 48934330Sbostic * specified, the 0 flag will be ignored.'' 49034330Sbostic * -- ANSI X3J11 49134330Sbostic */ 49234427Sbostic number: if ((dprec = prec) >= 0) 49334427Sbostic flags &= ~ZEROPAD; 49434427Sbostic 49534330Sbostic /* 49634326Sbostic * ``The result of converting a zero value with an 49734326Sbostic * explicit precision of zero is no characters.'' 49834326Sbostic * -- ANSI X3J11 49934326Sbostic */ 50046076Sbostic cp = buf + BUF; 50153810Sbostic if (_uquad != 0 || prec != 0) { 50246076Sbostic /* 50353810Sbostic * Unsigned mod is hard, and unsigned mod 50446076Sbostic * by a constant is easier than that by 50546076Sbostic * a variable; hence this switch. 50646076Sbostic */ 50746076Sbostic switch (base) { 50846076Sbostic case OCT: 50946076Sbostic do { 51053810Sbostic *--cp = to_char(_uquad & 7); 51153810Sbostic _uquad >>= 3; 51253810Sbostic } while (_uquad); 51346076Sbostic /* handle octal leading 0 */ 51446076Sbostic if (flags & ALT && *cp != '0') 51546076Sbostic *--cp = '0'; 51646076Sbostic break; 51734327Sbostic 51846076Sbostic case DEC: 51946076Sbostic /* many numbers are 1 digit */ 52053810Sbostic while (_uquad >= 10) { 52153810Sbostic *--cp = to_char(_uquad % 10); 52253810Sbostic _uquad /= 10; 52346076Sbostic } 52453810Sbostic *--cp = to_char(_uquad); 52546076Sbostic break; 52634327Sbostic 52746076Sbostic case HEX: 52846076Sbostic do { 52953810Sbostic *--cp = xdigs[_uquad & 15]; 53053810Sbostic _uquad >>= 4; 53153810Sbostic } while (_uquad); 53246076Sbostic break; 53334327Sbostic 53446076Sbostic default: 53546076Sbostic cp = "bug in vfprintf: bad base"; 53646180Storek size = strlen(cp); 53746076Sbostic goto skipsize; 53846076Sbostic } 53934327Sbostic } 54046076Sbostic size = buf + BUF - cp; 54146076Sbostic skipsize: 54234226Sbostic break; 54346076Sbostic default: /* "%?" prints ?, unless ? is NUL */ 54446076Sbostic if (ch == '\0') 54546076Sbostic goto done; 54646076Sbostic /* pretend it was %c with argument ch */ 54746076Sbostic cp = buf; 54846076Sbostic *cp = ch; 54946076Sbostic size = 1; 55046076Sbostic sign = '\0'; 55146076Sbostic break; 55234226Sbostic } 55346076Sbostic 55446076Sbostic /* 555*57154Sbostic * All reasonable formats wind up here. At this point, `cp' 556*57154Sbostic * points to a string which (if not flags&LADJUST) should be 557*57154Sbostic * padded out to `width' places. If flags&ZEROPAD, it should 558*57154Sbostic * first be prefixed by any sign or other prefix; otherwise, 559*57154Sbostic * it should be blank padded before the prefix is emitted. 560*57154Sbostic * After any left-hand padding and prefixing, emit zeroes 561*57154Sbostic * required by a decimal [diouxX] precision, then print the 562*57154Sbostic * string proper, then emit zeroes required by any leftover 563*57154Sbostic * floating precision; finally, if LADJUST, pad with blanks. 564*57154Sbostic * 565*57154Sbostic * Compute actual size, so we know how much to pad. 566*57154Sbostic * fieldsz excludes decimal prec; realsz includes it. 56746076Sbostic */ 56846076Sbostic fieldsz = size; 56946076Sbostic if (sign) 57046076Sbostic fieldsz++; 57146076Sbostic else if (flags & HEXPREFIX) 57246076Sbostic fieldsz += 2; 57346076Sbostic realsz = dprec > fieldsz ? dprec : fieldsz; 57446076Sbostic 57546076Sbostic /* right-adjusting blank padding */ 57646076Sbostic if ((flags & (LADJUST|ZEROPAD)) == 0) 57746076Sbostic PAD(width - realsz, blanks); 57846076Sbostic 57946076Sbostic /* prefix */ 58046076Sbostic if (sign) { 58146076Sbostic PRINT(&sign, 1); 58246076Sbostic } else if (flags & HEXPREFIX) { 58346076Sbostic ox[0] = '0'; 58446076Sbostic ox[1] = ch; 58546076Sbostic PRINT(ox, 2); 58646076Sbostic } 58746076Sbostic 58846076Sbostic /* right-adjusting zero padding */ 58946076Sbostic if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 59046076Sbostic PAD(width - realsz, zeroes); 59146076Sbostic 59246076Sbostic /* leading zeroes from decimal precision */ 59346076Sbostic PAD(dprec - fieldsz, zeroes); 59446076Sbostic 59546076Sbostic /* the string or number proper */ 596*57154Sbostic #ifdef FLOATING_POINT 597*57154Sbostic if ((flags & FPT) == 0) { 598*57154Sbostic PRINT(cp, size); 599*57154Sbostic } else { /* glue together f_p fragments */ 600*57154Sbostic if (ch >= 'f') { /* 'f' or 'g' */ 601*57154Sbostic if (_double == 0) { 602*57154Sbostic /* kludge for __dtoa irregularity */ 603*57154Sbostic if (prec == 0 || 604*57154Sbostic (flags & ALT) == 0) { 605*57154Sbostic PRINT("0", 1); 606*57154Sbostic } else { 607*57154Sbostic PRINT("0.", 2); 608*57154Sbostic PAD(ndig - 1, zeroes); 609*57154Sbostic } 610*57154Sbostic } else if (expt <= 0) { 611*57154Sbostic PRINT("0.", 2); 612*57154Sbostic PAD(-expt, zeroes); 613*57154Sbostic PRINT(cp, ndig); 614*57154Sbostic } else if (expt >= ndig) { 615*57154Sbostic PRINT(cp, ndig); 616*57154Sbostic PAD(expt - ndig, zeroes); 617*57154Sbostic if (flags & ALT) 618*57154Sbostic PRINT(".", 1); 619*57154Sbostic } else { 620*57154Sbostic PRINT(cp, expt); 621*57154Sbostic cp += expt; 622*57154Sbostic PRINT(".", 1); 623*57154Sbostic PRINT(cp, ndig-expt); 624*57154Sbostic } 625*57154Sbostic } else { /* 'e' or 'E' */ 626*57154Sbostic if (ndig > 1 || flags & ALT) { 627*57154Sbostic ox[0] = *cp++; 628*57154Sbostic ox[1] = '.'; 629*57154Sbostic PRINT(ox, 2); 630*57154Sbostic if (_double || flags & ALT == 0) { 631*57154Sbostic PRINT(cp, ndig-1); 632*57154Sbostic } else /* 0.[0..] */ 633*57154Sbostic /* __dtoa irregularity */ 634*57154Sbostic PAD(ndig - 1, zeroes); 635*57154Sbostic } else /* XeYYY */ 636*57154Sbostic PRINT(cp, 1); 637*57154Sbostic PRINT(expstr, expsize); 638*57154Sbostic } 639*57154Sbostic } 640*57154Sbostic #else 64146076Sbostic PRINT(cp, size); 64246076Sbostic #endif 64346076Sbostic /* left-adjusting padding (always blank) */ 64446076Sbostic if (flags & LADJUST) 64546076Sbostic PAD(width - realsz, blanks); 64646076Sbostic 64746076Sbostic /* finally, adjust ret */ 64846076Sbostic ret += width > realsz ? width : realsz; 64946076Sbostic 65046076Sbostic FLUSH(); /* copy out the I/O vectors */ 65134226Sbostic } 65246076Sbostic done: 65346076Sbostic FLUSH(); 65446076Sbostic error: 65546076Sbostic return (__sferror(fp) ? EOF : ret); 65634427Sbostic /* NOTREACHED */ 65734226Sbostic } 65834242Sbostic 65946076Sbostic #ifdef FLOATING_POINT 66046180Storek 661*57154Sbostic extern char *__dtoa __P((double, int, int, int *, int *, char **)); 66246076Sbostic 663*57154Sbostic static char * 664*57154Sbostic cvt(value, ndigits, flags, sign, decpt, ch, length) 665*57154Sbostic double value; 666*57154Sbostic int ndigits, flags, *decpt, ch, *length; 667*57154Sbostic char *sign; 66834242Sbostic { 669*57154Sbostic int mode, dsgn; 670*57154Sbostic char *digits, *bp, *rve; 67134242Sbostic 672*57154Sbostic if (ch == 'f') 673*57154Sbostic mode = 3; 674*57154Sbostic else { 675*57154Sbostic mode = 2; 676*57154Sbostic } 677*57154Sbostic if (value < 0) { 678*57154Sbostic value = -value; 679*57154Sbostic *sign = '-'; 68046076Sbostic } else 681*57154Sbostic *sign = '\000'; 682*57154Sbostic digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 683*57154Sbostic if (flags & ALT) { /* Print trailing zeros */ 684*57154Sbostic bp = digits + ndigits; 685*57154Sbostic if (ch == 'f') { 686*57154Sbostic if (*digits == '0' && value) 687*57154Sbostic *decpt = -ndigits + 1; 688*57154Sbostic bp += *decpt; 68934624Sbostic } 690*57154Sbostic if (value == 0) /* kludge for __dtoa irregularity */ 691*57154Sbostic rve = bp; 692*57154Sbostic while (rve < bp) 693*57154Sbostic *rve++ = '0'; 69434624Sbostic } 695*57154Sbostic *length = rve - digits; 696*57154Sbostic return (digits); 69734624Sbostic } 69834248Sbostic 699*57154Sbostic static int 700*57154Sbostic exponent(p0, exp, fmtch) 701*57154Sbostic char *p0; 702*57154Sbostic int exp, fmtch; 70334624Sbostic { 704*57154Sbostic register char *p, *t; 70534624Sbostic char expbuf[MAXEXP]; 70634248Sbostic 707*57154Sbostic p = p0; 70834624Sbostic *p++ = fmtch; 70934624Sbostic if (exp < 0) { 71034624Sbostic exp = -exp; 71134624Sbostic *p++ = '-'; 71234242Sbostic } 71334624Sbostic else 71434624Sbostic *p++ = '+'; 71534624Sbostic t = expbuf + MAXEXP; 71634624Sbostic if (exp > 9) { 71734624Sbostic do { 71846076Sbostic *--t = to_char(exp % 10); 71934624Sbostic } while ((exp /= 10) > 9); 72046076Sbostic *--t = to_char(exp); 72134624Sbostic for (; t < expbuf + MAXEXP; *p++ = *t++); 72234624Sbostic } 72334624Sbostic else { 72434624Sbostic *p++ = '0'; 72546076Sbostic *p++ = to_char(exp); 72634624Sbostic } 727*57154Sbostic return (p - p0); 72834242Sbostic } 72946076Sbostic #endif /* FLOATING_POINT */ 730