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.15 (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 case 's': 196 if (!(t = va_arg(argp, char *))) 197 t = "(null)"; 198 if ((size = strlen(t)) > prec && prec >= 0) 199 size = prec; 200 pforw: if (!(flags&LADJUST) && width) 201 for (n = size; n++ < width;) 202 PUTC(padc); 203 if (fp->_cnt - (n = size) >= 0) { 204 cnt += n; 205 fp->_cnt -= n; 206 bcopy(t, fp->_ptr, n); 207 fp->_ptr += n; 208 } 209 else for (; n--; ++t) 210 PUTC(*t); 211 if (flags&LADJUST) 212 while (width-- > size) 213 PUTC(padc); 214 break; 215 case 'u': 216 ARG(); 217 base = 10; 218 goto num; 219 case 'X': 220 digs = "0123456789ABCDEF"; 221 /*FALLTHROUGH*/ 222 case 'x': 223 ARG(); 224 base = 16; 225 /* alternate form for hex; leading 0x/X */ 226 if (flags&ALT && _ulong) { 227 PUTC('0'); 228 PUTC(*fmt); 229 } 230 num: t = buf + MAXDIGIT - 1; 231 do { 232 *t-- = digs[_ulong % base]; 233 _ulong /= base; 234 } while(_ulong); 235 digs = "0123456789abcdef"; 236 size = buf + MAXDIGIT - 1 - t; 237 if (size >= prec) { 238 /* alternate form for octal; leading 0 */ 239 if (t[1] != '0' && flags&ALT && *fmt == 'o') { 240 *t-- = '0'; 241 ++size; 242 } 243 } 244 else 245 for (; size < prec; ++size) 246 *t-- = '0'; 247 if (!(flags&LADJUST)) 248 while (size++ < width) 249 PUTC(padc); 250 while (++t < buf + MAXDIGIT) 251 PUTC(*t); 252 for (; width > size; --width) 253 PUTC(padc); 254 break; 255 case '\0': /* "%?" prints ?, unless ? is NULL */ 256 return(cnt); 257 default: 258 PUTC(*fmt); 259 } 260 } 261 /*NOTREACHED*/ 262 } 263 264 #define EFORMAT 0x01 265 #define FFORMAT 0x02 266 #define GFORMAT 0x04 267 #define DEFPREC 6 268 269 static 270 _cvt(number, prec, fmtch) 271 double number; 272 register int prec; 273 char fmtch; 274 { 275 register char *p; 276 register int expcnt, format; 277 static int maxprec = MAXPREC; 278 double fract, integer, tmp, modf(); 279 int decpt; 280 char *endp, *savep, *startp, *malloc(); 281 282 if (prec == -1) 283 prec = DEFPREC; 284 285 /* allocate space for large precision */ 286 if (prec > maxprec) 287 buf = malloc((u_int)((maxprec = prec) + MAXFRAC + 1)); 288 289 startp = buf; 290 if (number < 0) { 291 *startp++ = '-'; 292 number = -number; 293 } 294 else if (sign) 295 *startp++ = sign; 296 297 switch(fmtch) { 298 case 'e': 299 case 'E': 300 format = EFORMAT; 301 break; 302 case 'f': 303 format = FFORMAT; 304 break; 305 case 'g': 306 case 'G': 307 format = GFORMAT; 308 fmtch -= 2; 309 } 310 311 /* 312 * if the alternate flag is set, or, at least one digit of precision 313 * was requested, add a decimal point, unless it's the g/G format 314 * in which case we require two digits of precision, as it counts 315 * precision differently. 316 */ 317 decpt = flags&ALT || prec > (format&GFORMAT ? 1 : 0); 318 319 expcnt = 0; 320 p = buf + maxprec + MAXFRAC; 321 endp = p + 1; 322 fract = modf(number, &integer); 323 if (integer) { 324 register char *p2; 325 326 /* get integer part of number; count decimal places */ 327 for (; integer; ++expcnt) { 328 tmp = modf(integer / 10, &integer); 329 *p-- = (int)((tmp + .03) * 10) + '0'; 330 } 331 332 /* copy, in reverse order, to start of buffer */ 333 p2 = startp; 334 *p2++ = *++p; 335 336 /* 337 * if the format is g/G, and the resulting exponent will be 338 * greater than the precision, use e/E format. If e/E format, 339 * put in a decimal point as needed, and decrement precision 340 * count for each digit after the decimal point. 341 */ 342 if (format&GFORMAT && expcnt - 1 > prec || format&EFORMAT) { 343 if (format&GFORMAT) { 344 format |= EFORMAT; 345 346 /* first digit is precision for g/G format */ 347 if (prec) 348 --prec; 349 } 350 if (decpt) 351 *p2++ = '.'; 352 for (; ++p < endp && prec; --prec, *p2++ = *p); 353 354 /* precision ran out, round */ 355 if (p < endp) { 356 if (*p > '4') { 357 for (savep = p2--;; *p2-- = '0') { 358 if (*p2 == '.') 359 --p2; 360 if (++*p2 <= '9') 361 break; 362 } 363 p2 = savep; 364 } 365 fract = 0; 366 } 367 } 368 /* 369 * g/G in f format; if out of precision, replace digits with 370 * zeroes, note, have to round first. 371 */ 372 else if (format&GFORMAT) { 373 for (; ++p < endp && prec; --prec, *p2++ = *p); 374 /* precision ran out; round and then add zeroes */ 375 if (p < endp) { 376 if (*p > '4') { 377 for (savep = p2--; ++*p2 > '9'; 378 *p2-- = '0'); 379 p2 = savep; 380 } 381 do { 382 *p2++ = '0'; 383 } while (++p < endp); 384 fract = 0; 385 } 386 if (decpt) 387 *p2++ = '.'; 388 } 389 /* f format */ 390 else { 391 for (; ++p < endp; *p2++ = *p); 392 if (decpt) 393 *p2++ = '.'; 394 } 395 p = p2; 396 } 397 /* 398 * if no fraction, the number was zero, and if no precision, can't 399 * show anything after the decimal point. 400 */ 401 else if (!fract || !prec) { 402 *startp++ = '0'; 403 if (decpt && !(format&GFORMAT)) 404 *startp++ = '.'; 405 *startp = '\0'; 406 return(startp - buf); 407 } 408 /* 409 * if the format is g/G, and the resulting exponent will be less than 410 * -4 use e/E format. If e/E format, compute exponent value. 411 */ 412 else if (format&GFORMAT && fract < .0001 || format&EFORMAT) { 413 format |= EFORMAT; 414 if (fract) 415 for (p = startp; fract;) { 416 fract = modf(fract * 10, &tmp); 417 if (!tmp) { 418 --expcnt; 419 continue; 420 } 421 *p++ = (int)tmp + '0'; 422 break; 423 } 424 else 425 *p++ = '0'; 426 427 /* g/G format, decrement precision for first digit */ 428 if (format&GFORMAT && prec) 429 --prec; 430 431 /* add decimal after first non-zero digit */ 432 if (decpt) 433 *p++ = '.'; 434 } 435 /* 436 * f format or g/G printed as f format; don't worry about decimal 437 * point, if g/G format doesn't need it, will get stripped later. 438 */ 439 else { 440 p = startp; 441 *p++ = '0'; 442 *p++ = '.'; 443 } 444 445 /* finish out requested precision */ 446 while (fract && prec-- > 0) { 447 fract = modf(fract * 10, &tmp); 448 *p++ = (int)tmp + '0'; 449 } 450 while (prec-- > 0) 451 *p++ = '0'; 452 453 /* 454 * if any fractional value left, "round" it back up to the beginning 455 * of the number, fixing the exponent as necessary, and avoiding the 456 * decimal point. 457 */ 458 if (fract) { 459 (void)modf(fract * 10, &tmp); 460 if (tmp > 4) { 461 for (savep = p--;; *p-- = '0') { 462 if (*p == '.') 463 --p; 464 if (p == startp) { 465 *p = '1'; 466 ++expcnt; 467 break; 468 } 469 if (++*p <= '9') 470 break; 471 } 472 p = savep; 473 } 474 } 475 476 /* 477 * if a g/G format and not alternate flag, lose trailing zeroes, 478 * if e/E or g/G format, and last char is decimal point, lose it. 479 */ 480 if (!(flags&ALT)) { 481 if (format&GFORMAT) 482 for (; p[-1] == '0'; --p); 483 if (format&(GFORMAT|EFORMAT) && p[-1] == '.') 484 --p; 485 } 486 487 /* if an e/E format, add exponent */ 488 if (format&EFORMAT) { 489 *p++ = fmtch; 490 if (--expcnt < 0) { 491 expcnt = -expcnt; 492 *p++ = '-'; 493 } 494 else 495 *p++ = '+'; 496 *p++ = expcnt / 10 + '0'; 497 *p++ = expcnt % 10 + '0'; 498 } 499 return(p - buf); 500 } 501