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.16 (Berkeley) 05/17/88"; 15 #endif /* LIBC_SCCS and not lint */ 16 17 #include <sys/types.h> 18 #include <varargs.h> 19 #include <stdio.h> 20 #include <ctype.h> 21 22 /* 23 * To handle arbitrary floating point precision, the buffer has to hold the 24 * number, a decimal point, and N precision digits. We can't just truncate 25 * at some point is that the lower-level math routines may very well be 26 * repeatedly returning some small fraction. A 128 bit fraction can be 27 * represented in 39 decimal digits. Guess a max of 40 digits of precision, 28 * and add one for the decimal point. 29 */ 30 #define MAXFRAC 39 31 #define MAXPREC 40 32 #define MAXDIGIT (MAXFRAC + MAXPREC + 1) 33 34 #define PUTC(ch) {++cnt; putc(ch, fp);} 35 36 #define ARG() \ 37 _ulong = flags&LONGINT ? va_arg(argp, long) : \ 38 flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 39 40 /* have to deal with the negative buffer count kludge */ 41 #define NEGATIVE_COUNT_KLUDGE 42 43 #define LONGINT 0x01 /* long integer */ 44 #define LONGDBL 0x02 /* long double; unimplemented */ 45 #define SHORTINT 0x04 /* short integer */ 46 #define ALT 0x08 /* alternate form */ 47 #define LADJUST 0x10 /* left adjustment */ 48 static int flags; 49 50 static char sign, *buf; 51 52 x_doprnt(fmt, argp, fp) 53 register char *fmt; 54 va_list argp; 55 register FILE *fp; 56 { 57 register int cnt, n; 58 register char ch, *t; 59 double _double; 60 u_long _ulong; 61 int base, width, prec, size; 62 char padc, *digs, sbuf[MAXDIGIT]; 63 64 digs = "0123456789abcdef"; 65 for (buf = sbuf, cnt = 0;; ++fmt) { 66 n = fp->_cnt; 67 for (t = fp->_ptr; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) 68 if (--n < 0 69 #ifdef NEGATIVE_COUNT_KLUDGE 70 && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) 71 #endif 72 || ch == '\n' && fp->_flag&_IOLBF) { 73 fp->_cnt = n; 74 fp->_ptr = t; 75 (void)_flsbuf(ch, fp); 76 n = fp->_cnt; 77 t = fp->_ptr; 78 } 79 else 80 *t++ = ch; 81 fp->_cnt = n; 82 fp->_ptr = t; 83 if (!ch) 84 return(cnt); 85 86 flags = width = 0; 87 prec = -1; 88 padc = ' '; 89 sign = '\0'; 90 91 rflag: switch (*++fmt) { 92 case ' ': 93 sign = ' '; 94 goto rflag; 95 case '#': 96 flags |= ALT; 97 goto rflag; 98 case '*': 99 /* 100 * ``A negative field width argument is taken as a 101 * - flag followed by a positive field width.'' 102 * -- ANSI X3J11 103 * They don't exclude field widths read from args. 104 */ 105 if ((width = va_arg(argp, int)) >= 0) 106 goto rflag; 107 width = -width; 108 /*FALLTHROUGH*/ 109 case '-': 110 flags |= LADJUST; 111 goto rflag; 112 case '+': 113 sign = '+'; 114 goto rflag; 115 case '.': 116 if (*++fmt == '*') 117 n = va_arg(argp, int); 118 else if (isascii(*fmt) && isdigit(*fmt)) { 119 n = 0; 120 do { 121 n = 10 * n + *fmt - '0'; 122 } while (isascii(*++fmt) && isdigit(*fmt)); 123 --fmt; 124 } 125 else { 126 --fmt; 127 prec = 0; 128 goto rflag; 129 } 130 prec = n < 0 ? -1 : n; 131 goto rflag; 132 case '0': 133 padc = '0'; 134 /*FALLTHROUGH*/ 135 case '1': case '2': case '3': case '4': 136 case '5': case '6': case '7': case '8': case '9': 137 n = 0; 138 do { 139 n = 10 * n + *fmt - '0'; 140 } while (isascii(*++fmt) && isdigit(*fmt)); 141 width = n; 142 --fmt; 143 goto rflag; 144 case 'L': 145 /* 146 * C doesn't have a long double; use long for now. 147 * flags |= LONGDBL; 148 */ 149 flags |= LONGINT; 150 goto rflag; 151 case 'h': 152 flags |= SHORTINT; 153 goto rflag; 154 case 'l': 155 flags |= LONGINT; 156 goto rflag; 157 case 'c': 158 buf[0] = va_arg(argp, int); 159 size = 1; 160 t = buf; 161 goto pforw; 162 case 'd': 163 case 'i': 164 ARG(); 165 if ((long)_ulong < 0) { 166 _ulong = -_ulong; 167 sign = '-'; 168 } 169 if (sign) 170 PUTC(sign); 171 base = 10; 172 goto num; 173 case 'e': 174 case 'E': 175 case 'f': 176 case 'g': 177 case 'G': 178 _double = va_arg(argp, double); 179 size = _cvt(_double, prec, *fmt); 180 t = buf; 181 goto pforw; 182 case 'n': 183 if (flags&LONGDBL || flags&LONGINT) 184 *va_arg(argp, long *) = cnt; 185 else if (flags&SHORTINT) 186 *va_arg(argp, short *) = cnt; 187 else 188 *va_arg(argp, int *) = cnt; 189 break; 190 case 'o': 191 ARG(); 192 base = 8; 193 goto num; 194 case 'p': 195 /* 196 * the argument shall be a pointer to void. The value 197 * of the pointer is converted to a sequence of 198 * printable characters, in an implementation-defined 199 * manner. 200 */ 201 _ulong = (u_long)va_arg(argp, void *); 202 base = 16; 203 goto num; 204 case 's': 205 if (!(t = va_arg(argp, char *))) 206 t = "(null)"; 207 if ((size = strlen(t)) > prec && prec >= 0) 208 size = prec; 209 pforw: if (!(flags&LADJUST) && width) 210 for (n = size; n++ < width;) 211 PUTC(padc); 212 if (fp->_cnt - (n = size) >= 0) { 213 cnt += n; 214 fp->_cnt -= n; 215 bcopy(t, fp->_ptr, n); 216 fp->_ptr += n; 217 } 218 else for (; n--; ++t) 219 PUTC(*t); 220 if (flags&LADJUST) 221 while (width-- > size) 222 PUTC(padc); 223 break; 224 case 'u': 225 ARG(); 226 base = 10; 227 goto num; 228 case 'X': 229 digs = "0123456789ABCDEF"; 230 /*FALLTHROUGH*/ 231 case 'x': 232 ARG(); 233 base = 16; 234 /* alternate form for hex; leading 0x/X */ 235 if (flags&ALT && _ulong) { 236 PUTC('0'); 237 PUTC(*fmt); 238 } 239 num: t = buf + MAXDIGIT - 1; 240 do { 241 *t-- = digs[_ulong % base]; 242 _ulong /= base; 243 } while(_ulong); 244 digs = "0123456789abcdef"; 245 size = buf + MAXDIGIT - 1 - t; 246 if (size >= prec) { 247 /* alternate form for octal; leading 0 */ 248 if (t[1] != '0' && flags&ALT && *fmt == 'o') { 249 *t-- = '0'; 250 ++size; 251 } 252 } 253 else 254 for (; size < prec; ++size) 255 *t-- = '0'; 256 if (!(flags&LADJUST)) 257 while (size++ < width) 258 PUTC(padc); 259 while (++t < buf + MAXDIGIT) 260 PUTC(*t); 261 for (; width > size; --width) 262 PUTC(padc); 263 break; 264 case '\0': /* "%?" prints ?, unless ? is NULL */ 265 return(cnt); 266 default: 267 PUTC(*fmt); 268 } 269 } 270 /*NOTREACHED*/ 271 } 272 273 #define EFORMAT 0x01 274 #define FFORMAT 0x02 275 #define GFORMAT 0x04 276 #define DEFPREC 6 277 278 static 279 _cvt(number, prec, fmtch) 280 double number; 281 register int prec; 282 char fmtch; 283 { 284 register char *p; 285 register int expcnt, format; 286 static int maxprec = MAXPREC; 287 double fract, integer, tmp, modf(); 288 int decpt; 289 char *endp, *savep, *startp, *malloc(); 290 291 if (prec == -1) 292 prec = DEFPREC; 293 294 /* allocate space for large precision */ 295 if (prec > maxprec) 296 buf = malloc((u_int)((maxprec = prec) + MAXFRAC + 1)); 297 298 startp = buf; 299 if (number < 0) { 300 *startp++ = '-'; 301 number = -number; 302 } 303 else if (sign) 304 *startp++ = sign; 305 306 switch(fmtch) { 307 case 'e': 308 case 'E': 309 format = EFORMAT; 310 break; 311 case 'f': 312 format = FFORMAT; 313 break; 314 case 'g': 315 case 'G': 316 format = GFORMAT; 317 fmtch -= 2; 318 } 319 320 /* 321 * if the alternate flag is set, or, at least one digit of precision 322 * was requested, add a decimal point, unless it's the g/G format 323 * in which case we require two digits of precision, as it counts 324 * precision differently. 325 */ 326 decpt = flags&ALT || prec > (format&GFORMAT ? 1 : 0); 327 328 expcnt = 0; 329 p = buf + maxprec + MAXFRAC; 330 endp = p + 1; 331 fract = modf(number, &integer); 332 if (integer) { 333 register char *p2; 334 335 /* get integer part of number; count decimal places */ 336 for (; integer; ++expcnt) { 337 tmp = modf(integer / 10, &integer); 338 *p-- = (int)((tmp + .03) * 10) + '0'; 339 } 340 341 /* copy, in reverse order, to start of buffer */ 342 p2 = startp; 343 *p2++ = *++p; 344 345 /* 346 * if the format is g/G, and the resulting exponent will be 347 * greater than the precision, use e/E format. If e/E format, 348 * put in a decimal point as needed, and decrement precision 349 * count for each digit after the decimal point. 350 */ 351 if (format&GFORMAT && expcnt - 1 > prec || format&EFORMAT) { 352 if (format&GFORMAT) { 353 format |= EFORMAT; 354 355 /* first digit is precision for g/G format */ 356 if (prec) 357 --prec; 358 } 359 if (decpt) 360 *p2++ = '.'; 361 for (; ++p < endp && prec; --prec, *p2++ = *p); 362 363 /* precision ran out, round */ 364 if (p < endp) { 365 if (*p > '4') { 366 for (savep = p2--;; *p2-- = '0') { 367 if (*p2 == '.') 368 --p2; 369 if (++*p2 <= '9') 370 break; 371 } 372 p2 = savep; 373 } 374 fract = 0; 375 } 376 } 377 /* 378 * g/G in f format; if out of precision, replace digits with 379 * zeroes, note, have to round first. 380 */ 381 else if (format&GFORMAT) { 382 for (; ++p < endp && prec; --prec, *p2++ = *p); 383 /* precision ran out; round and then add zeroes */ 384 if (p < endp) { 385 if (*p > '4') { 386 for (savep = p2--; ++*p2 > '9'; 387 *p2-- = '0'); 388 p2 = savep; 389 } 390 do { 391 *p2++ = '0'; 392 } while (++p < endp); 393 fract = 0; 394 } 395 if (decpt) 396 *p2++ = '.'; 397 } 398 /* f format */ 399 else { 400 for (; ++p < endp; *p2++ = *p); 401 if (decpt) 402 *p2++ = '.'; 403 } 404 p = p2; 405 } 406 /* 407 * if no fraction, the number was zero, and if no precision, can't 408 * show anything after the decimal point. 409 */ 410 else if (!fract || !prec) { 411 *startp++ = '0'; 412 if (decpt && !(format&GFORMAT)) 413 *startp++ = '.'; 414 *startp = '\0'; 415 return(startp - buf); 416 } 417 /* 418 * if the format is g/G, and the resulting exponent will be less than 419 * -4 use e/E format. If e/E format, compute exponent value. 420 */ 421 else if (format&GFORMAT && fract < .0001 || format&EFORMAT) { 422 format |= EFORMAT; 423 if (fract) 424 for (p = startp; fract;) { 425 fract = modf(fract * 10, &tmp); 426 if (!tmp) { 427 --expcnt; 428 continue; 429 } 430 *p++ = (int)tmp + '0'; 431 break; 432 } 433 else 434 *p++ = '0'; 435 436 /* g/G format, decrement precision for first digit */ 437 if (format&GFORMAT && prec) 438 --prec; 439 440 /* add decimal after first non-zero digit */ 441 if (decpt) 442 *p++ = '.'; 443 } 444 /* 445 * f format or g/G printed as f format; don't worry about decimal 446 * point, if g/G format doesn't need it, will get stripped later. 447 */ 448 else { 449 p = startp; 450 *p++ = '0'; 451 *p++ = '.'; 452 } 453 454 /* finish out requested precision */ 455 while (fract && prec-- > 0) { 456 fract = modf(fract * 10, &tmp); 457 *p++ = (int)tmp + '0'; 458 } 459 while (prec-- > 0) 460 *p++ = '0'; 461 462 /* 463 * if any fractional value left, "round" it back up to the beginning 464 * of the number, fixing the exponent as necessary, and avoiding the 465 * decimal point. 466 */ 467 if (fract) { 468 (void)modf(fract * 10, &tmp); 469 if (tmp > 4) { 470 for (savep = p--;; *p-- = '0') { 471 if (*p == '.') 472 --p; 473 if (p == startp) { 474 *p = '1'; 475 ++expcnt; 476 break; 477 } 478 if (++*p <= '9') 479 break; 480 } 481 p = savep; 482 } 483 } 484 485 /* 486 * if a g/G format and not alternate flag, lose trailing zeroes, 487 * if e/E or g/G format, and last char is decimal point, lose it. 488 */ 489 if (!(flags&ALT)) { 490 if (format&GFORMAT) 491 for (; p[-1] == '0'; --p); 492 if (format&(GFORMAT|EFORMAT) && p[-1] == '.') 493 --p; 494 } 495 496 /* if an e/E format, add exponent */ 497 if (format&EFORMAT) { 498 *p++ = fmtch; 499 if (--expcnt < 0) { 500 expcnt = -expcnt; 501 *p++ = '-'; 502 } 503 else 504 *p++ = '+'; 505 *p++ = expcnt / 10 + '0'; 506 *p++ = expcnt % 10 + '0'; 507 } 508 return(p - buf); 509 } 510