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