1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #if defined(LIBC_SCCS) && !defined(lint) 14 static char sccsid[] = "@(#)vfprintf.c 5.4 (Berkeley) 05/08/88"; 15 #endif /* LIBC_SCCS and not lint */ 16 17 #include <sys/param.h> 18 #include <varargs.h> 19 #include <stdio.h> 20 #include <ctype.h> 21 22 #define GETARG(r) \ 23 r = argsize&LONGINT ? va_arg(argp, long) : \ 24 argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 25 26 #define MAXBUF 1024 /* should hold any number */ 27 #define MAXEXP 10 /* should hold any exponent */ 28 29 #define DEFPREC 6 /* default precision */ 30 31 #define PUTC(ch, fd) {++cnt; putc(ch, fd);} 32 33 #define LONGINT 0x01 34 #define LONGDBL 0x02 35 #define SHORTINT 0x04 36 37 x_doprnt(fmt, argp, fp) 38 register char *fmt; 39 va_list argp; 40 register FILE *fp; 41 { 42 register u_long reg_ulong; 43 register long reg_long; 44 register int base; 45 register char *digs, *bp, *t, padc; 46 double _double; 47 char argsize, printsign, buf[MAXBUF], *ecvt(), *fcvt(); 48 int alternate, cnt, decpt, n, ladjust, width, prec, sign, size; 49 50 for (cnt = 0; *fmt; ++fmt) { 51 if (*fmt != '%') { 52 PUTC(*fmt, fp); 53 continue; 54 } 55 56 alternate = ladjust = width = 0; 57 prec = -1; 58 padc = ' '; 59 argsize = printsign = '\0'; 60 61 flags: switch (*++fmt) { 62 case '#': 63 alternate = 1; 64 goto flags; 65 case '%': /* "%#%" prints as "%" */ 66 PUTC('%', fp); 67 continue; 68 case '*': 69 /* 70 * ``A negative field width argument is taken as a 71 * - flag followed by a positive field width.'' 72 * -- ANSI X3J11 73 * They don't exclude field widths read from args. 74 */ 75 if ((width = va_arg(argp, int)) >= 0) 76 goto flags; 77 width = -width; 78 /*FALLTHROUGH*/ 79 case '-': 80 ladjust = 1; 81 goto flags; 82 case '+': 83 printsign = '+'; 84 goto flags; 85 case '.': 86 if (*++fmt == '*') 87 prec = va_arg(argp, int); 88 else if (isdigit(*fmt)) { 89 prec = 0; 90 do { 91 prec = 10 * prec + *fmt - '0'; 92 } while isdigit(*++fmt); 93 --fmt; 94 } 95 else { 96 prec = 0; 97 --fmt; 98 goto flags; 99 } 100 if (prec < 0) 101 prec = -1; 102 goto flags; 103 case '0': 104 padc = '0'; 105 /*FALLTHROUGH*/ 106 case '1': case '2': case '3': case '4': 107 case '5': case '6': case '7': case '8': case '9': 108 do { 109 width = 10 * width + *fmt - '0'; 110 } while isdigit(*++fmt); 111 --fmt; 112 case 'L': 113 argsize |= LONGDBL; 114 goto flags; 115 case 'h': 116 argsize |= SHORTINT; 117 goto flags; 118 case 'l': 119 argsize |= LONGINT; 120 goto flags; 121 } 122 123 digs = "0123456789abcdef"; 124 125 switch (*fmt) { 126 case 'c': 127 PUTC(va_arg(argp, int), fp); 128 break; 129 case 'E': 130 case 'e': 131 if (prec == -1) 132 prec = DEFPREC; 133 _double = va_arg(argp, double); 134 t = ecvt(_double, prec + 1, &decpt, &sign); 135 bp = buf; 136 *bp++ = *t ? *t++ : '0'; 137 if (alternate || prec > 0) 138 *bp++ = '.'; 139 while (prec--) 140 *bp++ = *t ? *t++ : '0'; 141 *bp++ = *fmt; 142 *bp++ = (decpt > 0 || !_double) ? '+' : '-'; 143 /* we know exponents <= 99 */ 144 --decpt; 145 *bp++ = (int)decpt / 10 + '0'; 146 *bp++ = (int)decpt % 10 + '0'; 147 goto pbuf; 148 case 'f': 149 if (prec == -1) 150 prec = DEFPREC; 151 _double = va_arg(argp, double); 152 t = fcvt(_double, prec + 1, &decpt, &sign); 153 bp = buf; 154 if (decpt >= 0) 155 for (;;) { 156 *bp++ = *t ? *t++ : '0'; 157 if (!--decpt) 158 break; 159 } 160 if (alternate || prec > 0) 161 *bp++ = '.'; 162 while (decpt++) { 163 *bp++ = *t ? *t++ : '0'; 164 --prec; 165 } 166 while (prec--) 167 *bp++ = *t ? *t++ : '0'; 168 pbuf: size = bp - buf; 169 if (sign || printsign) 170 PUTC(sign ? '-' : printsign, fp); 171 if (size < width && !ladjust) 172 do { 173 PUTC(padc, fp); 174 } while (--width > size); 175 for (t = buf; t < bp; ++t) 176 PUTC(*t, fp); 177 for (; width > size; --width) 178 PUTC(padc, fp); 179 break; 180 case 'd': 181 case 'i': 182 GETARG(reg_long); 183 if (reg_long < 0) { 184 reg_ulong = -reg_long; 185 printsign = '-'; 186 } 187 else { 188 reg_ulong = reg_long; 189 } 190 if (printsign) 191 PUTC(printsign, fp); 192 base = 10; 193 goto num1; 194 case 'n': 195 *(va_arg(argp, int *)) = cnt; 196 break; 197 case 'o': 198 GETARG(reg_ulong); 199 base = 8; 200 if (!reg_ulong || !alternate) 201 goto num1; 202 bp = buf + sizeof(buf) - 1; 203 do { 204 *bp-- = digs[reg_ulong % base]; 205 reg_ulong /= base; 206 } while(reg_ulong); 207 size = &buf[sizeof(buf) - 1] - bp; 208 if (size < --width && !ladjust) 209 do { 210 PUTC(padc, fp); 211 } while (--width > size); 212 PUTC('0', fp); 213 goto num2; 214 break; 215 case 'p': 216 case 's': 217 if (!(bp = va_arg(argp, char *))) 218 bp = "(null)"; 219 if (width > 0 && !ladjust) { 220 char *savep; 221 222 savep = bp; 223 for (n = 0; *bp && (prec < 0 || n < prec); 224 n++, bp++); 225 bp = savep; 226 while (n++ < width) 227 PUTC(' ', fp); 228 } 229 for (n = 0; *bp; ++bp) { 230 if (++n > prec && prec >= 0) 231 break; 232 PUTC(*bp, fp); 233 } 234 if (n < width && ladjust) 235 do { 236 PUTC(' ', fp); 237 } while (++n < width); 238 break; 239 case 'u': 240 GETARG(reg_ulong); 241 base = 10; 242 goto num1; 243 case 'X': 244 digs = "0123456789ABCDEF"; 245 /*FALLTHROUGH*/ 246 case 'x': 247 GETARG(reg_ulong); 248 if (alternate && reg_ulong) { 249 PUTC('0', fp); 250 PUTC(*fmt, fp); 251 } 252 base = 16; 253 num1: bp = buf + sizeof(buf) - 1; 254 do { 255 *bp-- = digs[reg_ulong % base]; 256 reg_ulong /= base; 257 } while(reg_ulong); 258 size = &buf[sizeof(buf) - 1] - bp; 259 for (; size < prec; *bp-- = '0', ++size); 260 if (size < width && !ladjust) 261 do { 262 PUTC(padc, fp); 263 } while (--width > size); 264 num2: while (++bp != &buf[MAXBUF]) 265 PUTC(*bp, fp); 266 for (; width > size; --width) 267 PUTC(padc, fp); 268 break; 269 case '\0': /* "%?" prints ?, unless ? is NULL */ 270 return(ferror(fp) ? -1 : cnt); 271 default: 272 PUTC(*fmt, fp); 273 } 274 } 275 return(ferror(fp) ? -1 : cnt); 276 } 277