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.6 (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 for (cnt = 0; *fmt; ++fmt) { 52 if (*fmt != '%') { 53 PUTC(*fmt, fp); 54 continue; 55 } 56 57 alternate = ladjust = width = 0; 58 prec = -1; 59 padc = ' '; 60 argsize = printsign = '\0'; 61 62 flags: switch (*++fmt) { 63 case '#': 64 alternate = 1; 65 goto flags; 66 case '%': /* "%#%" prints as "%" */ 67 PUTC('%', fp); 68 continue; 69 case '*': 70 /* 71 * ``A negative field width argument is taken as a 72 * - flag followed by a positive field width.'' 73 * -- ANSI X3J11 74 * They don't exclude field widths read from args. 75 */ 76 if ((width = va_arg(argp, int)) >= 0) 77 goto flags; 78 width = -width; 79 /*FALLTHROUGH*/ 80 case '-': 81 ladjust = 1; 82 goto flags; 83 case '+': 84 printsign = '+'; 85 goto flags; 86 case '.': 87 if (*++fmt == '*') 88 prec = va_arg(argp, int); 89 else if (isdigit(*fmt)) { 90 prec = 0; 91 do { 92 prec = 10 * prec + *fmt - '0'; 93 } while isdigit(*++fmt); 94 --fmt; 95 } 96 else { 97 prec = 0; 98 --fmt; 99 goto flags; 100 } 101 if (prec < 0) 102 prec = -1; 103 goto flags; 104 case '0': 105 padc = '0'; 106 /*FALLTHROUGH*/ 107 case '1': case '2': case '3': case '4': 108 case '5': case '6': case '7': case '8': case '9': 109 do { 110 width = 10 * width + *fmt - '0'; 111 } while isdigit(*++fmt); 112 --fmt; 113 case 'L': 114 argsize |= LONGDBL; 115 goto flags; 116 case 'h': 117 argsize |= SHORTINT; 118 goto flags; 119 case 'l': 120 argsize |= LONGINT; 121 goto flags; 122 } 123 124 digs = "0123456789abcdef"; 125 126 switch (*fmt) { 127 case 'c': 128 PUTC(va_arg(argp, int), fp); 129 break; 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); 149 goto pbuf; 150 case 'f': 151 _double = va_arg(argp, double); 152 bp = _cvt(_double, prec, buf, FFORMAT, 'f', 153 printsign); 154 pbuf: size = bp - buf; 155 if (size < width && !ladjust) 156 do { 157 PUTC(padc, fp); 158 } while (--width > size); 159 for (t = buf; t < bp; ++t) 160 PUTC(*t, fp); 161 for (; width > size; --width) 162 PUTC(padc, fp); 163 break; 164 case 'G': 165 case 'g': 166 _double = va_arg(argp, double); 167 bp = _cvt(_double, prec, buf, GFORMAT, *fmt - 2, 168 printsign); 169 goto pbuf; 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 break; 244 case '\0': /* "%?" prints ?, unless ? is NULL */ 245 return(ferror(fp) ? -1 : cnt); 246 default: 247 PUTC(*fmt, fp); 248 } 249 } 250 return(ferror(fp) ? -1 : cnt); 251 } 252 253 char * 254 _cvt(number, prec, bp, format, fmtch, printsign) 255 double number; 256 int prec, format; 257 register char *bp; 258 char fmtch, printsign; 259 { 260 int sign, decpt; 261 register char *t; 262 register int n; 263 double fabs(); 264 char *ecvt(), *fcvt(); 265 266 if (prec == -1) 267 prec = DEFPREC; 268 t = fabs(number) < 1 ? ecvt(number, prec + 1, &decpt, &sign) : 269 fcvt(number, prec + 1, &decpt, &sign); 270 271 if (sign) 272 *bp++ = '-'; 273 else if (printsign) 274 *bp++ = printsign; 275 276 /* E format */ 277 /* use 'e' format if exponent > precision or less than -4 */ 278 if (format == EFORMAT || 279 format == GFORMAT && (decpt > prec || decpt < -3)) { 280 *bp++ = *t ? *t++ : '0'; 281 if (format != GFORMAT && prec || prec > 1) { 282 *bp++ = '.'; 283 while(prec--) 284 *bp++ = *t ? *t++ : '0'; 285 } 286 if (*t && *t > '4') 287 ++bp[-1]; 288 if (format == 2) { 289 for (; bp[-1] == '0'; --bp); 290 if (*bp == '.') 291 --bp; 292 } 293 *bp++ = fmtch; 294 if (--decpt < 0) { 295 decpt = -decpt; 296 *bp++ = '-'; 297 } 298 else 299 *bp++ = '+'; 300 *bp++ = decpt / 10 + '0'; 301 *bp++ = decpt % 10 + '0'; 302 } 303 /* F format */ 304 else { 305 if (decpt <= 0) { 306 *bp++ = '0'; 307 if (prec) { 308 *bp++ = '.'; 309 if (format == FFORMAT) 310 while (decpt++ < 0 && prec--) 311 *bp++ = '0'; 312 else while (decpt++ < 0) 313 *bp++ = '0'; 314 } 315 } 316 else { 317 for (n = 1; n <= decpt; n++) 318 *bp++ = *t++; 319 if (prec) 320 *bp++ = '.'; 321 } 322 for (n = 1; n <= prec; n++) 323 *bp++ = *t ? *t++ : '0'; 324 if (format == GFORMAT) { 325 for (; bp[-1] == '0'; --bp); 326 if (bp[-1] == '.') 327 --bp; 328 } 329 } 330 return(bp); 331 } 332