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.5 (Berkeley) 05/09/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 MAXBUF 120 /* should hold any number */ 23 #define DEFPREC 6 /* default precision */ 24 25 #define PUTC(ch, fd) {++cnt; putc(ch, fd);} 26 27 #define LONGINT 0x01 28 #define LONGDBL 0x02 29 #define SHORTINT 0x04 30 #define GETARG(r) \ 31 r = argsize&LONGINT ? va_arg(argp, long) : \ 32 argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 33 34 x_doprnt(fmt, argp, fp) 35 register char *fmt; 36 va_list argp; 37 register FILE *fp; 38 { 39 register u_long reg_ulong; 40 register long reg_long; 41 register int base; 42 register char *digs, *bp, *t, padc; 43 double _double; 44 char argsize, printsign, buf[MAXBUF], *ecvt(), *fcvt(); 45 int alternate, cnt, decpt, n, ladjust, width, prec, sign, size; 46 47 for (cnt = 0; *fmt; ++fmt) { 48 if (*fmt != '%') { 49 PUTC(*fmt, fp); 50 continue; 51 } 52 53 alternate = ladjust = width = 0; 54 prec = -1; 55 padc = ' '; 56 argsize = printsign = '\0'; 57 58 flags: switch (*++fmt) { 59 case '#': 60 alternate = 1; 61 goto flags; 62 case '%': /* "%#%" prints as "%" */ 63 PUTC('%', fp); 64 continue; 65 case '*': 66 /* 67 * ``A negative field width argument is taken as a 68 * - flag followed by a positive field width.'' 69 * -- ANSI X3J11 70 * They don't exclude field widths read from args. 71 */ 72 if ((width = va_arg(argp, int)) >= 0) 73 goto flags; 74 width = -width; 75 /*FALLTHROUGH*/ 76 case '-': 77 ladjust = 1; 78 goto flags; 79 case '+': 80 printsign = '+'; 81 goto flags; 82 case '.': 83 if (*++fmt == '*') 84 prec = va_arg(argp, int); 85 else if (isdigit(*fmt)) { 86 prec = 0; 87 do { 88 prec = 10 * prec + *fmt - '0'; 89 } while isdigit(*++fmt); 90 --fmt; 91 } 92 else { 93 prec = 0; 94 --fmt; 95 goto flags; 96 } 97 if (prec < 0) 98 prec = -1; 99 goto flags; 100 case '0': 101 padc = '0'; 102 /*FALLTHROUGH*/ 103 case '1': case '2': case '3': case '4': 104 case '5': case '6': case '7': case '8': case '9': 105 do { 106 width = 10 * width + *fmt - '0'; 107 } while isdigit(*++fmt); 108 --fmt; 109 case 'L': 110 argsize |= LONGDBL; 111 goto flags; 112 case 'h': 113 argsize |= SHORTINT; 114 goto flags; 115 case 'l': 116 argsize |= LONGINT; 117 goto flags; 118 } 119 120 digs = "0123456789abcdef"; 121 122 switch (*fmt) { 123 case 'c': 124 PUTC(va_arg(argp, int), fp); 125 break; 126 case 'd': 127 case 'i': 128 GETARG(reg_long); 129 if (reg_long < 0) { 130 reg_ulong = -reg_long; 131 printsign = '-'; 132 } 133 else { 134 reg_ulong = reg_long; 135 } 136 if (printsign) 137 PUTC(printsign, fp); 138 base = 10; 139 goto num1; 140 case 'E': 141 case 'e': 142 if (prec == -1) 143 prec = DEFPREC; 144 _double = va_arg(argp, double); 145 t = fcvt(_double, prec + 1, &decpt, &sign); 146 gise: bp = buf; 147 *bp++ = *t ? *t++ : '0'; 148 if (alternate || prec > 0) 149 *bp++ = '.'; 150 while (prec--) 151 *bp++ = *t ? *t++ : '0'; 152 *bp++ = *fmt; 153 if (decpt > 0 || !_double) { 154 *bp++ = '+'; 155 --decpt; 156 } 157 else { 158 *bp++ = '-'; 159 decpt = -decpt + 1; 160 } 161 /* exponents <= 99 in ANSI X3J11 */ 162 *bp++ = (int)(decpt / 10) + '0'; 163 *bp++ = (int)(decpt % 10) + '0'; 164 goto pbuf; 165 case 'f': 166 if (prec == -1) 167 prec = DEFPREC; 168 _double = va_arg(argp, double); 169 t = fcvt(_double, prec + 1, &decpt, &sign); 170 gisf: bp = buf; 171 if (decpt >= 0) 172 for (;;) { 173 *bp++ = *t ? *t++ : '0'; 174 if (!--decpt) 175 break; 176 } 177 if (alternate || prec > 0) { 178 if (decpt < 0) 179 *bp++ = '0'; 180 *bp++ = '.'; 181 } 182 while (decpt++) { 183 *bp++ = '0'; 184 --prec; 185 } 186 while (prec--) 187 *bp++ = *t ? *t++ : '0'; 188 pbuf: size = bp - buf; 189 if (sign || printsign) 190 PUTC(sign ? '-' : printsign, fp); 191 if (size < width && !ladjust) 192 do { 193 PUTC(padc, fp); 194 } while (--width > size); 195 for (t = buf; t < bp; ++t) 196 PUTC(*t, fp); 197 for (; width > size; --width) 198 PUTC(padc, fp); 199 break; 200 case 'G': 201 case 'g': { 202 int gotoe; 203 204 if (prec == -1) 205 prec = DEFPREC; 206 _double = va_arg(argp, double); 207 t = fcvt(_double, prec + 1, &decpt, &sign); 208 gotoe = decpt > prec; 209 if (!alternate) { 210 for (bp = t + prec + decpt; prec && 211 *--bp == '0'; --prec); 212 } 213 if (gotoe || decpt < -3) { 214 *fmt -= 2; 215 goto gise; 216 } 217 --*fmt; 218 goto gisf; 219 } 220 case 'n': 221 *(va_arg(argp, int *)) = cnt; 222 break; 223 case 'o': 224 GETARG(reg_ulong); 225 base = 8; 226 if (!reg_ulong || !alternate) 227 goto num1; 228 bp = buf + sizeof(buf) - 1; 229 do { 230 *bp-- = digs[reg_ulong % base]; 231 reg_ulong /= base; 232 } while(reg_ulong); 233 size = &buf[sizeof(buf) - 1] - bp; 234 if (size < --width && !ladjust) 235 do { 236 PUTC(padc, fp); 237 } while (--width > size); 238 PUTC('0', fp); 239 goto num2; 240 break; 241 case 'p': 242 case 's': 243 if (!(bp = va_arg(argp, char *))) 244 bp = "(null)"; 245 if (width > 0 && !ladjust) { 246 char *savep; 247 248 savep = bp; 249 for (n = 0; *bp && (prec < 0 || n < prec); 250 n++, bp++); 251 bp = savep; 252 while (n++ < width) 253 PUTC(' ', fp); 254 } 255 for (n = 0; *bp; ++bp) { 256 if (++n > prec && prec >= 0) 257 break; 258 PUTC(*bp, fp); 259 } 260 if (n < width && ladjust) 261 do { 262 PUTC(' ', fp); 263 } while (++n < width); 264 break; 265 case 'u': 266 GETARG(reg_ulong); 267 base = 10; 268 goto num1; 269 case 'X': 270 digs = "0123456789ABCDEF"; 271 /*FALLTHROUGH*/ 272 case 'x': 273 GETARG(reg_ulong); 274 if (alternate && reg_ulong) { 275 PUTC('0', fp); 276 PUTC(*fmt, fp); 277 } 278 base = 16; 279 num1: bp = buf + sizeof(buf) - 1; 280 do { 281 *bp-- = digs[reg_ulong % base]; 282 reg_ulong /= base; 283 } while(reg_ulong); 284 size = &buf[sizeof(buf) - 1] - bp; 285 for (; size < prec; *bp-- = '0', ++size); 286 if (size < width && !ladjust) 287 do { 288 PUTC(padc, fp); 289 } while (--width > size); 290 num2: while (++bp != &buf[MAXBUF]) 291 PUTC(*bp, fp); 292 for (; width > size; --width) 293 PUTC(padc, fp); 294 break; 295 case '\0': /* "%?" prints ?, unless ? is NULL */ 296 return(ferror(fp) ? -1 : cnt); 297 default: 298 PUTC(*fmt, fp); 299 } 300 } 301 return(ferror(fp) ? -1 : cnt); 302 } 303