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*61032Sbostic static char sccsid[] = "@(#)vfprintf.c 5.51 (Berkeley) 06/02/93"; 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> 2257154Sbostic 23*61032Sbostic #include <limits.h> 2446076Sbostic #include <stdio.h> 2557154Sbostic #include <stdlib.h> 2646076Sbostic #include <string.h> 2757154Sbostic 2846076Sbostic #if __STDC__ 2946076Sbostic #include <stdarg.h> 3046076Sbostic #else 3134233Sbostic #include <varargs.h> 3246076Sbostic #endif 3357154Sbostic 3446076Sbostic #include "local.h" 3546076Sbostic #include "fvwrite.h" 3634226Sbostic 3750438Sbostic /* Define FLOATING_POINT to get floating point. */ 3846076Sbostic #define FLOATING_POINT 3934226Sbostic 4046076Sbostic /* 4146076Sbostic * Flush out all the vectors defined by the given uio, 4246076Sbostic * then reset it so that it can be reused. 4346076Sbostic */ 4446180Storek static int 4546076Sbostic __sprint(fp, uio) 4646076Sbostic FILE *fp; 4746076Sbostic register struct __suio *uio; 4846076Sbostic { 4946076Sbostic register int err; 5046076Sbostic 5146076Sbostic if (uio->uio_resid == 0) { 5246076Sbostic uio->uio_iovcnt = 0; 5346076Sbostic return (0); 5446076Sbostic } 5546076Sbostic err = __sfvwrite(fp, uio); 5646076Sbostic uio->uio_resid = 0; 5746076Sbostic uio->uio_iovcnt = 0; 5846076Sbostic return (err); 5946076Sbostic } 6046076Sbostic 6146076Sbostic /* 6246076Sbostic * Helper function for `fprintf to unbuffered unix file': creates a 6346076Sbostic * temporary buffer. We only work on write-only files; this avoids 6446076Sbostic * worries about ungetc buffers and so forth. 6546076Sbostic */ 6646180Storek static int 6746076Sbostic __sbprintf(fp, fmt, ap) 6846076Sbostic register FILE *fp; 6946180Storek const char *fmt; 7046076Sbostic va_list ap; 7146076Sbostic { 7246076Sbostic int ret; 7346076Sbostic FILE fake; 7446076Sbostic unsigned char buf[BUFSIZ]; 7546076Sbostic 7646076Sbostic /* copy the important variables */ 7746076Sbostic fake._flags = fp->_flags & ~__SNBF; 7846076Sbostic fake._file = fp->_file; 7946076Sbostic fake._cookie = fp->_cookie; 8046076Sbostic fake._write = fp->_write; 8146076Sbostic 8246076Sbostic /* set up the buffer */ 8346076Sbostic fake._bf._base = fake._p = buf; 8446076Sbostic fake._bf._size = fake._w = sizeof(buf); 8546076Sbostic fake._lbfsize = 0; /* not actually used, but Just In Case */ 8646076Sbostic 8746076Sbostic /* do the work, then copy any error status */ 8846076Sbostic ret = vfprintf(&fake, fmt, ap); 8946076Sbostic if (ret >= 0 && fflush(&fake)) 9046076Sbostic ret = EOF; 9146076Sbostic if (fake._flags & __SERR) 9246076Sbostic fp->_flags |= __SERR; 9346076Sbostic return (ret); 9446076Sbostic } 9546076Sbostic 96*61032Sbostic /* 97*61032Sbostic * Macros for converting digits to letters and vice versa 98*61032Sbostic */ 99*61032Sbostic #define to_digit(c) ((c) - '0') 100*61032Sbostic #define is_digit(c) ((unsigned)to_digit(c) <= 9) 101*61032Sbostic #define to_char(n) ((n) + '0') 10246076Sbostic 103*61032Sbostic /* 104*61032Sbostic * Convert an unsigned long to ASCII for printf purposes, returning 105*61032Sbostic * a pointer to the first character of the string representation. 106*61032Sbostic * Octal numbers can be forced to have a leading zero; hex numbers 107*61032Sbostic * use the given digits. 108*61032Sbostic */ 109*61032Sbostic static char * 110*61032Sbostic __ultoa(val, endp, base, octzero, xdigs) 111*61032Sbostic register u_long val; 112*61032Sbostic char *endp; 113*61032Sbostic int base, octzero; 114*61032Sbostic char *xdigs; 115*61032Sbostic { 116*61032Sbostic register char *cp = endp; 117*61032Sbostic register long sval; 118*61032Sbostic 119*61032Sbostic /* 120*61032Sbostic * Handle the three cases separately, in the hope of getting 121*61032Sbostic * better/faster code. 122*61032Sbostic */ 123*61032Sbostic switch (base) { 124*61032Sbostic case 10: 125*61032Sbostic if (val < 10) { /* many numbers are 1 digit */ 126*61032Sbostic *--cp = to_char(val); 127*61032Sbostic return (cp); 128*61032Sbostic } 129*61032Sbostic /* 130*61032Sbostic * On many machines, unsigned arithmetic is harder than 131*61032Sbostic * signed arithmetic, so we do at most one unsigned mod and 132*61032Sbostic * divide; this is sufficient to reduce the range of 133*61032Sbostic * the incoming value to where signed arithmetic works. 134*61032Sbostic */ 135*61032Sbostic if (val > LONG_MAX) { 136*61032Sbostic *--cp = to_char(val % 10); 137*61032Sbostic sval = val / 10; 138*61032Sbostic } else 139*61032Sbostic sval = val; 140*61032Sbostic do { 141*61032Sbostic *--cp = to_char(sval % 10); 142*61032Sbostic sval /= 10; 143*61032Sbostic } while (sval != 0); 144*61032Sbostic break; 145*61032Sbostic 146*61032Sbostic case 8: 147*61032Sbostic do { 148*61032Sbostic *--cp = to_char(val & 7); 149*61032Sbostic val >>= 3; 150*61032Sbostic } while (val); 151*61032Sbostic if (octzero && *cp != '0') 152*61032Sbostic *--cp = '0'; 153*61032Sbostic break; 154*61032Sbostic 155*61032Sbostic case 16: 156*61032Sbostic do { 157*61032Sbostic *--cp = xdigs[val & 15]; 158*61032Sbostic val >>= 4; 159*61032Sbostic } while (val); 160*61032Sbostic break; 161*61032Sbostic 162*61032Sbostic default: /* oops */ 163*61032Sbostic abort(); 164*61032Sbostic } 165*61032Sbostic return (cp); 166*61032Sbostic } 167*61032Sbostic 168*61032Sbostic /* Identical to __ultoa, but for quads. */ 169*61032Sbostic static char * 170*61032Sbostic __uqtoa(val, endp, base, octzero, xdigs) 171*61032Sbostic register u_quad_t val; 172*61032Sbostic char *endp; 173*61032Sbostic int base, octzero; 174*61032Sbostic char *xdigs; 175*61032Sbostic { 176*61032Sbostic register char *cp = endp; 177*61032Sbostic register quad_t sval; 178*61032Sbostic 179*61032Sbostic /* quick test for small values; __ultoa is typically much faster */ 180*61032Sbostic /* (perhaps instead we should run until small, then call __ultoa?) */ 181*61032Sbostic if (val <= ULONG_MAX) 182*61032Sbostic return (__ultoa((u_long)val, endp, base, octzero, xdigs)); 183*61032Sbostic switch (base) { 184*61032Sbostic case 10: 185*61032Sbostic if (val < 10) { 186*61032Sbostic *--cp = to_char(val % 10); 187*61032Sbostic return (cp); 188*61032Sbostic } 189*61032Sbostic if (val > QUAD_MAX) { 190*61032Sbostic *--cp = to_char(val % 10); 191*61032Sbostic sval = val / 10; 192*61032Sbostic } else 193*61032Sbostic sval = val; 194*61032Sbostic do { 195*61032Sbostic *--cp = to_char(sval % 10); 196*61032Sbostic sval /= 10; 197*61032Sbostic } while (sval != 0); 198*61032Sbostic break; 199*61032Sbostic 200*61032Sbostic case 8: 201*61032Sbostic do { 202*61032Sbostic *--cp = to_char(val & 7); 203*61032Sbostic val >>= 3; 204*61032Sbostic } while (val); 205*61032Sbostic if (octzero && *cp != '0') 206*61032Sbostic *--cp = '0'; 207*61032Sbostic break; 208*61032Sbostic 209*61032Sbostic case 16: 210*61032Sbostic do { 211*61032Sbostic *--cp = xdigs[val & 15]; 212*61032Sbostic val >>= 4; 213*61032Sbostic } while (val); 214*61032Sbostic break; 215*61032Sbostic 216*61032Sbostic default: 217*61032Sbostic abort(); 218*61032Sbostic } 219*61032Sbostic return (cp); 220*61032Sbostic } 221*61032Sbostic 22246076Sbostic #ifdef FLOATING_POINT 22357154Sbostic #include <math.h> 22446180Storek #include "floatio.h" 22546076Sbostic 22634328Sbostic #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ 22746076Sbostic #define DEFPREC 6 22834328Sbostic 22957154Sbostic static char *cvt __P((double, int, int, char *, int *, int, int *)); 23057154Sbostic static int exponent __P((char *, int, int)); 23134236Sbostic 23246076Sbostic #else /* no FLOATING_POINT */ 23334235Sbostic 234*61032Sbostic #define BUF 68 23534331Sbostic 23646076Sbostic #endif /* FLOATING_POINT */ 23734318Sbostic 23846076Sbostic 23946076Sbostic /* 24046076Sbostic * Flags used during conversion. 24146076Sbostic */ 24253810Sbostic #define ALT 0x001 /* alternate form */ 24353810Sbostic #define HEXPREFIX 0x002 /* add 0x or 0X prefix */ 24453810Sbostic #define LADJUST 0x004 /* left adjustment */ 24553810Sbostic #define LONGDBL 0x008 /* long double; unimplemented */ 24653810Sbostic #define LONGINT 0x010 /* long integer */ 24753810Sbostic #define QUADINT 0x020 /* quad integer */ 24853810Sbostic #define SHORTINT 0x040 /* short integer */ 24953810Sbostic #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ 25057154Sbostic #define FPT 0x100 /* Floating point number */ 25146180Storek int 25246076Sbostic vfprintf(fp, fmt0, ap) 25346076Sbostic FILE *fp; 25446180Storek const char *fmt0; 25546076Sbostic va_list ap; 25634226Sbostic { 25746076Sbostic register char *fmt; /* format string */ 25834427Sbostic register int ch; /* character from fmt */ 25946076Sbostic register int n; /* handy integer (short term usage) */ 26046076Sbostic register char *cp; /* handy char pointer (short term usage) */ 26146076Sbostic register struct __siov *iovp;/* for PRINT macro */ 26246076Sbostic register int flags; /* flags as above */ 26346076Sbostic int ret; /* return value accumulator */ 26446076Sbostic int width; /* width from format (%8d), or 0 */ 26546076Sbostic int prec; /* precision from format (%.3d), or -1 */ 26646076Sbostic char sign; /* sign prefix (' ', '+', '-', or \0) */ 26746076Sbostic #ifdef FLOATING_POINT 26846076Sbostic char softsign; /* temporary negative sign for floats */ 26934427Sbostic double _double; /* double precision arguments %[eEfgG] */ 27057154Sbostic int expt; /* integer value of exponent */ 27157154Sbostic int expsize; /* character count for expstr */ 27257154Sbostic int ndig; /* actual number of digits returned by cvt */ 27357154Sbostic char expstr[7]; /* buffer for exponent string */ 27446076Sbostic #endif 275*61032Sbostic u_long ulval; /* integer arguments %[diouxX] */ 276*61032Sbostic u_quad_t uqval; /* %q integers */ 277*61032Sbostic int base; /* base for [diouxX] conversion */ 27846076Sbostic int dprec; /* a copy of prec if [diouxX], 0 otherwise */ 27934624Sbostic int fieldsz; /* field size expanded by sign, etc */ 28046076Sbostic int realsz; /* field size expanded by dprec */ 28134427Sbostic int size; /* size of converted field or string */ 28246076Sbostic char *xdigs; /* digits for [xX] conversion */ 28346076Sbostic #define NIOV 8 28446076Sbostic struct __suio uio; /* output information: summary */ 28546076Sbostic struct __siov iov[NIOV];/* ... and individual io vectors */ 28634427Sbostic char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ 28746076Sbostic char ox[2]; /* space for 0x hex-prefix */ 28834226Sbostic 28946076Sbostic /* 29053810Sbostic * Choose PADSIZE to trade efficiency vs. size. If larger printf 29153810Sbostic * fields occur frequently, increase PADSIZE and make the initialisers 29253810Sbostic * below longer. 29346076Sbostic */ 29446076Sbostic #define PADSIZE 16 /* pad chunk size */ 29546076Sbostic static char blanks[PADSIZE] = 29646076Sbostic {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 29746076Sbostic static char zeroes[PADSIZE] = 29846076Sbostic {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 29946076Sbostic 30046076Sbostic /* 30146076Sbostic * BEWARE, these `goto error' on error, and PAD uses `n'. 30246076Sbostic */ 30346076Sbostic #define PRINT(ptr, len) { \ 30446076Sbostic iovp->iov_base = (ptr); \ 30546076Sbostic iovp->iov_len = (len); \ 30646076Sbostic uio.uio_resid += (len); \ 30746076Sbostic iovp++; \ 30846076Sbostic if (++uio.uio_iovcnt >= NIOV) { \ 30946076Sbostic if (__sprint(fp, &uio)) \ 31046076Sbostic goto error; \ 31146076Sbostic iovp = iov; \ 31246076Sbostic } \ 31346076Sbostic } 31446076Sbostic #define PAD(howmany, with) { \ 31546076Sbostic if ((n = (howmany)) > 0) { \ 31646076Sbostic while (n > PADSIZE) { \ 31746076Sbostic PRINT(with, PADSIZE); \ 31846076Sbostic n -= PADSIZE; \ 31946076Sbostic } \ 32046076Sbostic PRINT(with, n); \ 32146076Sbostic } \ 32246076Sbostic } 32346076Sbostic #define FLUSH() { \ 32446076Sbostic if (uio.uio_resid && __sprint(fp, &uio)) \ 32546076Sbostic goto error; \ 32646076Sbostic uio.uio_iovcnt = 0; \ 32746076Sbostic iovp = iov; \ 32846076Sbostic } 32946076Sbostic 33046076Sbostic /* 33146076Sbostic * To extend shorts properly, we need both signed and unsigned 33246076Sbostic * argument extraction methods. 33346076Sbostic */ 33446076Sbostic #define SARG() \ 335*61032Sbostic (flags&LONGINT ? va_arg(ap, long) : \ 33646076Sbostic flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ 33746076Sbostic (long)va_arg(ap, int)) 33846076Sbostic #define UARG() \ 339*61032Sbostic (flags&LONGINT ? va_arg(ap, u_long) : \ 34046076Sbostic flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ 34146076Sbostic (u_long)va_arg(ap, u_int)) 34246076Sbostic 34346076Sbostic /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 34446076Sbostic if (cantwrite(fp)) 34534428Sbostic return (EOF); 34634428Sbostic 34746076Sbostic /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 34846076Sbostic if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 34946076Sbostic fp->_file >= 0) 35046076Sbostic return (__sbprintf(fp, fmt0, ap)); 35146076Sbostic 35246076Sbostic fmt = (char *)fmt0; 35346076Sbostic uio.uio_iov = iovp = iov; 35446076Sbostic uio.uio_resid = 0; 35546076Sbostic uio.uio_iovcnt = 0; 35646076Sbostic ret = 0; 35746076Sbostic 35846076Sbostic /* 35946076Sbostic * Scan the format for conversions (`%' character). 36046076Sbostic */ 36146076Sbostic for (;;) { 36246076Sbostic for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 36346076Sbostic /* void */; 36446076Sbostic if ((n = fmt - cp) != 0) { 36546076Sbostic PRINT(cp, n); 36646076Sbostic ret += n; 36746076Sbostic } 36846076Sbostic if (ch == '\0') 36946076Sbostic goto done; 37046076Sbostic fmt++; /* skip over '%' */ 37146076Sbostic 37246076Sbostic flags = 0; 37346076Sbostic dprec = 0; 37446076Sbostic width = 0; 37534233Sbostic prec = -1; 37634318Sbostic sign = '\0'; 37734226Sbostic 37846076Sbostic rflag: ch = *fmt++; 37946076Sbostic reswitch: switch (ch) { 38034318Sbostic case ' ': 38134669Sbostic /* 38234669Sbostic * ``If the space and + flags both appear, the space 38334669Sbostic * flag will be ignored.'' 38434669Sbostic * -- ANSI X3J11 38534669Sbostic */ 38634669Sbostic if (!sign) 38734669Sbostic sign = ' '; 38834318Sbostic goto rflag; 38934233Sbostic case '#': 39034318Sbostic flags |= ALT; 39134318Sbostic goto rflag; 39234233Sbostic case '*': 39334235Sbostic /* 39434235Sbostic * ``A negative field width argument is taken as a 39546076Sbostic * - flag followed by a positive field width.'' 39634235Sbostic * -- ANSI X3J11 39734235Sbostic * They don't exclude field widths read from args. 39834235Sbostic */ 39946076Sbostic if ((width = va_arg(ap, int)) >= 0) 40034318Sbostic goto rflag; 40134235Sbostic width = -width; 40234427Sbostic /* FALLTHROUGH */ 40334235Sbostic case '-': 40434318Sbostic flags |= LADJUST; 40534318Sbostic goto rflag; 40634233Sbostic case '+': 40734314Sbostic sign = '+'; 40834318Sbostic goto rflag; 40934233Sbostic case '.': 41046076Sbostic if ((ch = *fmt++) == '*') { 41146076Sbostic n = va_arg(ap, int); 41246076Sbostic prec = n < 0 ? -1 : n; 41346076Sbostic goto rflag; 41434226Sbostic } 41546076Sbostic n = 0; 41646076Sbostic while (is_digit(ch)) { 41746076Sbostic n = 10 * n + to_digit(ch); 41846076Sbostic ch = *fmt++; 41946076Sbostic } 42034318Sbostic prec = n < 0 ? -1 : n; 42146076Sbostic goto reswitch; 42234233Sbostic case '0': 42334427Sbostic /* 42434427Sbostic * ``Note that 0 is taken as a flag, not as the 42534427Sbostic * beginning of a field width.'' 42634427Sbostic * -- ANSI X3J11 42734427Sbostic */ 42834427Sbostic flags |= ZEROPAD; 42934427Sbostic goto rflag; 43034233Sbostic case '1': case '2': case '3': case '4': 43134233Sbostic case '5': case '6': case '7': case '8': case '9': 43234318Sbostic n = 0; 43334233Sbostic do { 43446076Sbostic n = 10 * n + to_digit(ch); 43546076Sbostic ch = *fmt++; 43646076Sbostic } while (is_digit(ch)); 43734318Sbostic width = n; 43846076Sbostic goto reswitch; 43946076Sbostic #ifdef FLOATING_POINT 44034235Sbostic case 'L': 44134329Sbostic flags |= LONGDBL; 44234318Sbostic goto rflag; 44346076Sbostic #endif 44434235Sbostic case 'h': 44534318Sbostic flags |= SHORTINT; 44634318Sbostic goto rflag; 44734233Sbostic case 'l': 44834318Sbostic flags |= LONGINT; 44934318Sbostic goto rflag; 45053810Sbostic case 'q': 45153810Sbostic flags |= QUADINT; 45253810Sbostic goto rflag; 45334314Sbostic case 'c': 45446076Sbostic *(cp = buf) = va_arg(ap, int); 45534314Sbostic size = 1; 45634427Sbostic sign = '\0'; 45746076Sbostic break; 45834624Sbostic case 'D': 45934624Sbostic flags |= LONGINT; 46034624Sbostic /*FALLTHROUGH*/ 46134314Sbostic case 'd': 46234318Sbostic case 'i': 463*61032Sbostic if (flags & QUADINT) { 464*61032Sbostic uqval = va_arg(ap, quad_t); 465*61032Sbostic if ((quad_t)uqval < 0) { 466*61032Sbostic uqval = -uqval; 467*61032Sbostic sign = '-'; 468*61032Sbostic } 469*61032Sbostic } else { 470*61032Sbostic ulval = SARG(); 471*61032Sbostic if ((long)ulval < 0) { 472*61032Sbostic ulval = -ulval; 473*61032Sbostic sign = '-'; 474*61032Sbostic } 47534241Sbostic } 476*61032Sbostic base = 10; 47734327Sbostic goto number; 47846076Sbostic #ifdef FLOATING_POINT 47957154Sbostic case 'e': /* anomalous precision */ 48034236Sbostic case 'E': 48157154Sbostic prec = (prec == -1) ? 48257154Sbostic DEFPREC + 1 : prec + 1; 48357154Sbostic /* FALLTHROUGH */ 48457154Sbostic goto fp_begin; 48557154Sbostic case 'f': /* always print trailing zeroes */ 48657154Sbostic if (prec != 0) 48757154Sbostic flags |= ALT; 48834261Sbostic case 'g': 48934243Sbostic case 'G': 49057154Sbostic if (prec == -1) 49157154Sbostic prec = DEFPREC; 49257154Sbostic fp_begin: _double = va_arg(ap, double); 49346126Storek /* do this before tricky precision changes */ 49447607Sbostic if (isinf(_double)) { 49547607Sbostic if (_double < 0) 49647607Sbostic sign = '-'; 49747607Sbostic cp = "Inf"; 49847607Sbostic size = 3; 49946126Storek break; 50046126Storek } 50147607Sbostic if (isnan(_double)) { 50247607Sbostic cp = "NaN"; 50347607Sbostic size = 3; 50447607Sbostic break; 50547607Sbostic } 50657154Sbostic flags |= FPT; 50757154Sbostic cp = cvt(_double, prec, flags, &softsign, 50857154Sbostic &expt, ch, &ndig); 50957154Sbostic if (ch == 'g' || ch == 'G') { 51057154Sbostic if (expt <= -4 || expt > prec) 51157154Sbostic ch = (ch == 'g') ? 'e' : 'E'; 51257154Sbostic else 51357154Sbostic ch = 'g'; 51457154Sbostic } 51557154Sbostic if (ch <= 'e') { /* 'e' or 'E' fmt */ 51657154Sbostic --expt; 51757154Sbostic expsize = exponent(expstr, expt, ch); 51857154Sbostic size = expsize + ndig; 51957154Sbostic if (ndig > 1 || flags & ALT) 52057154Sbostic ++size; 52157154Sbostic } else if (ch == 'f') { /* f fmt */ 52257154Sbostic if (expt > 0) { 52357154Sbostic size = expt; 52457154Sbostic if (prec || flags & ALT) 52557154Sbostic size += prec + 1; 52657154Sbostic } else /* "0.X" */ 52757154Sbostic size = prec + 2; 52857154Sbostic } else if (expt >= ndig) { /* fixed g fmt */ 52957154Sbostic size = expt; 53057154Sbostic if (flags & ALT) 53157154Sbostic ++size; 53257154Sbostic } else 53357154Sbostic size = ndig + (expt > 0 ? 53457154Sbostic 1 : 2 - expt); 53557154Sbostic 53634669Sbostic if (softsign) 53734669Sbostic sign = '-'; 53846076Sbostic break; 53946076Sbostic #endif /* FLOATING_POINT */ 54034235Sbostic case 'n': 54153810Sbostic if (flags & QUADINT) 54253810Sbostic *va_arg(ap, quad_t *) = ret; 54353810Sbostic else if (flags & LONGINT) 54446076Sbostic *va_arg(ap, long *) = ret; 54534427Sbostic else if (flags & SHORTINT) 54646076Sbostic *va_arg(ap, short *) = ret; 54734318Sbostic else 54846076Sbostic *va_arg(ap, int *) = ret; 54946076Sbostic continue; /* no output */ 55034624Sbostic case 'O': 55134624Sbostic flags |= LONGINT; 55234624Sbostic /*FALLTHROUGH*/ 55334226Sbostic case 'o': 554*61032Sbostic if (flags & QUADINT) 555*61032Sbostic uqval = va_arg(ap, u_quad_t); 556*61032Sbostic else 557*61032Sbostic ulval = UARG(); 558*61032Sbostic base = 8; 55934327Sbostic goto nosign; 56034235Sbostic case 'p': 56134320Sbostic /* 56234321Sbostic * ``The argument shall be a pointer to void. The 56334321Sbostic * value of the pointer is converted to a sequence 56434321Sbostic * of printable characters, in an implementation- 56534321Sbostic * defined manner.'' 56634321Sbostic * -- ANSI X3J11 56734320Sbostic */ 568*61032Sbostic ulval = (u_long)va_arg(ap, void *); 569*61032Sbostic base = 16; 57046076Sbostic xdigs = "0123456789abcdef"; 571*61032Sbostic flags = (flags & ~QUADINT) | HEXPREFIX; 57246076Sbostic ch = 'x'; 57334327Sbostic goto nosign; 57434226Sbostic case 's': 57546076Sbostic if ((cp = va_arg(ap, char *)) == NULL) 57646076Sbostic cp = "(null)"; 57734321Sbostic if (prec >= 0) { 57834321Sbostic /* 57934321Sbostic * can't use strlen; can only look for the 58034321Sbostic * NUL in the first `prec' characters, and 58134321Sbostic * strlen() will go further. 58234321Sbostic */ 58346076Sbostic char *p = memchr(cp, 0, prec); 58434321Sbostic 58546076Sbostic if (p != NULL) { 58646076Sbostic size = p - cp; 58734321Sbostic if (size > prec) 58834321Sbostic size = prec; 58934427Sbostic } else 59034321Sbostic size = prec; 59134427Sbostic } else 59246076Sbostic size = strlen(cp); 59334427Sbostic sign = '\0'; 59446076Sbostic break; 59534624Sbostic case 'U': 59634624Sbostic flags |= LONGINT; 59734624Sbostic /*FALLTHROUGH*/ 59834226Sbostic case 'u': 599*61032Sbostic if (flags & QUADINT) 600*61032Sbostic uqval = va_arg(ap, u_quad_t); 601*61032Sbostic else 602*61032Sbostic ulval = UARG(); 603*61032Sbostic base = 10; 60434327Sbostic goto nosign; 60534226Sbostic case 'X': 60646076Sbostic xdigs = "0123456789ABCDEF"; 60746076Sbostic goto hex; 60834226Sbostic case 'x': 60946076Sbostic xdigs = "0123456789abcdef"; 610*61032Sbostic hex: if (flags & QUADINT) 611*61032Sbostic uqval = va_arg(ap, u_quad_t); 612*61032Sbostic else 613*61032Sbostic ulval = UARG(); 614*61032Sbostic base = 16; 61534326Sbostic /* leading 0x/X only if non-zero */ 616*61032Sbostic if (flags & ALT && 617*61032Sbostic (flags & QUADINT ? uqval != 0 : ulval != 0)) 61834427Sbostic flags |= HEXPREFIX; 61934327Sbostic 62034327Sbostic /* unsigned conversions */ 62134427Sbostic nosign: sign = '\0'; 62234326Sbostic /* 62334330Sbostic * ``... diouXx conversions ... if a precision is 62434330Sbostic * specified, the 0 flag will be ignored.'' 62534330Sbostic * -- ANSI X3J11 62634330Sbostic */ 62734427Sbostic number: if ((dprec = prec) >= 0) 62834427Sbostic flags &= ~ZEROPAD; 62934427Sbostic 63034330Sbostic /* 63134326Sbostic * ``The result of converting a zero value with an 63234326Sbostic * explicit precision of zero is no characters.'' 63334326Sbostic * -- ANSI X3J11 63434326Sbostic */ 63546076Sbostic cp = buf + BUF; 636*61032Sbostic if (flags & QUADINT) { 637*61032Sbostic if (uqval != 0 || prec != 0) 638*61032Sbostic cp = __uqtoa(uqval, cp, base, 639*61032Sbostic flags & ALT, xdigs); 640*61032Sbostic } else { 641*61032Sbostic if (ulval != 0 || prec != 0) 642*61032Sbostic cp = __ultoa(ulval, cp, base, 643*61032Sbostic flags & ALT, xdigs); 64434327Sbostic } 64546076Sbostic size = buf + BUF - cp; 64634226Sbostic break; 64746076Sbostic default: /* "%?" prints ?, unless ? is NUL */ 64846076Sbostic if (ch == '\0') 64946076Sbostic goto done; 65046076Sbostic /* pretend it was %c with argument ch */ 65146076Sbostic cp = buf; 65246076Sbostic *cp = ch; 65346076Sbostic size = 1; 65446076Sbostic sign = '\0'; 65546076Sbostic break; 65634226Sbostic } 65746076Sbostic 65846076Sbostic /* 65957154Sbostic * All reasonable formats wind up here. At this point, `cp' 66057154Sbostic * points to a string which (if not flags&LADJUST) should be 66157154Sbostic * padded out to `width' places. If flags&ZEROPAD, it should 66257154Sbostic * first be prefixed by any sign or other prefix; otherwise, 66357154Sbostic * it should be blank padded before the prefix is emitted. 66457154Sbostic * After any left-hand padding and prefixing, emit zeroes 66557154Sbostic * required by a decimal [diouxX] precision, then print the 66657154Sbostic * string proper, then emit zeroes required by any leftover 66757154Sbostic * floating precision; finally, if LADJUST, pad with blanks. 66857154Sbostic * 66957154Sbostic * Compute actual size, so we know how much to pad. 67057154Sbostic * fieldsz excludes decimal prec; realsz includes it. 67146076Sbostic */ 67246076Sbostic fieldsz = size; 67346076Sbostic if (sign) 67446076Sbostic fieldsz++; 67546076Sbostic else if (flags & HEXPREFIX) 67646076Sbostic fieldsz += 2; 67746076Sbostic realsz = dprec > fieldsz ? dprec : fieldsz; 67846076Sbostic 67946076Sbostic /* right-adjusting blank padding */ 68046076Sbostic if ((flags & (LADJUST|ZEROPAD)) == 0) 68146076Sbostic PAD(width - realsz, blanks); 68246076Sbostic 68346076Sbostic /* prefix */ 68446076Sbostic if (sign) { 68546076Sbostic PRINT(&sign, 1); 68646076Sbostic } else if (flags & HEXPREFIX) { 68746076Sbostic ox[0] = '0'; 68846076Sbostic ox[1] = ch; 68946076Sbostic PRINT(ox, 2); 69046076Sbostic } 69146076Sbostic 69246076Sbostic /* right-adjusting zero padding */ 69346076Sbostic if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 69446076Sbostic PAD(width - realsz, zeroes); 69546076Sbostic 69646076Sbostic /* leading zeroes from decimal precision */ 69746076Sbostic PAD(dprec - fieldsz, zeroes); 69846076Sbostic 69946076Sbostic /* the string or number proper */ 70057154Sbostic #ifdef FLOATING_POINT 70157154Sbostic if ((flags & FPT) == 0) { 70257154Sbostic PRINT(cp, size); 70357154Sbostic } else { /* glue together f_p fragments */ 70457154Sbostic if (ch >= 'f') { /* 'f' or 'g' */ 70557154Sbostic if (_double == 0) { 70657154Sbostic /* kludge for __dtoa irregularity */ 70757154Sbostic if (prec == 0 || 70857154Sbostic (flags & ALT) == 0) { 70957154Sbostic PRINT("0", 1); 71057154Sbostic } else { 71157154Sbostic PRINT("0.", 2); 71257154Sbostic PAD(ndig - 1, zeroes); 71357154Sbostic } 71457154Sbostic } else if (expt <= 0) { 71557154Sbostic PRINT("0.", 2); 71657154Sbostic PAD(-expt, zeroes); 71757154Sbostic PRINT(cp, ndig); 71857154Sbostic } else if (expt >= ndig) { 71957154Sbostic PRINT(cp, ndig); 72057154Sbostic PAD(expt - ndig, zeroes); 72157154Sbostic if (flags & ALT) 72257154Sbostic PRINT(".", 1); 72357154Sbostic } else { 72457154Sbostic PRINT(cp, expt); 72557154Sbostic cp += expt; 72657154Sbostic PRINT(".", 1); 72757154Sbostic PRINT(cp, ndig-expt); 72857154Sbostic } 72957154Sbostic } else { /* 'e' or 'E' */ 73057154Sbostic if (ndig > 1 || flags & ALT) { 73157154Sbostic ox[0] = *cp++; 73257154Sbostic ox[1] = '.'; 73357154Sbostic PRINT(ox, 2); 73457154Sbostic if (_double || flags & ALT == 0) { 73557154Sbostic PRINT(cp, ndig-1); 73657154Sbostic } else /* 0.[0..] */ 73757154Sbostic /* __dtoa irregularity */ 73857154Sbostic PAD(ndig - 1, zeroes); 73957154Sbostic } else /* XeYYY */ 74057154Sbostic PRINT(cp, 1); 74157154Sbostic PRINT(expstr, expsize); 74257154Sbostic } 74357154Sbostic } 74457154Sbostic #else 74546076Sbostic PRINT(cp, size); 74646076Sbostic #endif 74746076Sbostic /* left-adjusting padding (always blank) */ 74846076Sbostic if (flags & LADJUST) 74946076Sbostic PAD(width - realsz, blanks); 75046076Sbostic 75146076Sbostic /* finally, adjust ret */ 75246076Sbostic ret += width > realsz ? width : realsz; 75346076Sbostic 75446076Sbostic FLUSH(); /* copy out the I/O vectors */ 75534226Sbostic } 75646076Sbostic done: 75746076Sbostic FLUSH(); 75846076Sbostic error: 75946076Sbostic return (__sferror(fp) ? EOF : ret); 76034427Sbostic /* NOTREACHED */ 76134226Sbostic } 76234242Sbostic 76346076Sbostic #ifdef FLOATING_POINT 76446180Storek 76557154Sbostic extern char *__dtoa __P((double, int, int, int *, int *, char **)); 76646076Sbostic 76757154Sbostic static char * 76857154Sbostic cvt(value, ndigits, flags, sign, decpt, ch, length) 76957154Sbostic double value; 77057154Sbostic int ndigits, flags, *decpt, ch, *length; 77157154Sbostic char *sign; 77234242Sbostic { 77357154Sbostic int mode, dsgn; 77457154Sbostic char *digits, *bp, *rve; 77534242Sbostic 77657154Sbostic if (ch == 'f') 77757154Sbostic mode = 3; 77857154Sbostic else { 77957154Sbostic mode = 2; 78057154Sbostic } 78157154Sbostic if (value < 0) { 78257154Sbostic value = -value; 78357154Sbostic *sign = '-'; 78446076Sbostic } else 78557154Sbostic *sign = '\000'; 78657154Sbostic digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); 78757154Sbostic if (flags & ALT) { /* Print trailing zeros */ 78857154Sbostic bp = digits + ndigits; 78957154Sbostic if (ch == 'f') { 79057154Sbostic if (*digits == '0' && value) 79157154Sbostic *decpt = -ndigits + 1; 79257154Sbostic bp += *decpt; 79334624Sbostic } 79457154Sbostic if (value == 0) /* kludge for __dtoa irregularity */ 79557154Sbostic rve = bp; 79657154Sbostic while (rve < bp) 79757154Sbostic *rve++ = '0'; 79834624Sbostic } 79957154Sbostic *length = rve - digits; 80057154Sbostic return (digits); 80134624Sbostic } 80234248Sbostic 80357154Sbostic static int 80457154Sbostic exponent(p0, exp, fmtch) 80557154Sbostic char *p0; 80657154Sbostic int exp, fmtch; 80734624Sbostic { 80857154Sbostic register char *p, *t; 80934624Sbostic char expbuf[MAXEXP]; 81034248Sbostic 81157154Sbostic p = p0; 81234624Sbostic *p++ = fmtch; 81334624Sbostic if (exp < 0) { 81434624Sbostic exp = -exp; 81534624Sbostic *p++ = '-'; 81634242Sbostic } 81734624Sbostic else 81834624Sbostic *p++ = '+'; 81934624Sbostic t = expbuf + MAXEXP; 82034624Sbostic if (exp > 9) { 82134624Sbostic do { 82246076Sbostic *--t = to_char(exp % 10); 82334624Sbostic } while ((exp /= 10) > 9); 82446076Sbostic *--t = to_char(exp); 82534624Sbostic for (; t < expbuf + MAXEXP; *p++ = *t++); 82634624Sbostic } 82734624Sbostic else { 82834624Sbostic *p++ = '0'; 82946076Sbostic *p++ = to_char(exp); 83034624Sbostic } 83157154Sbostic return (p - p0); 83234242Sbostic } 83346076Sbostic #endif /* FLOATING_POINT */ 834