FreeCalypso > hg > freecalypso-citrine
comparison sprintf/old/doprnt.c.43tahoe @ 0:75a11d740a02
initial import of gsm-fw from freecalypso-sw rev 1033:5ab737ac3ad7
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Thu, 09 Jun 2016 00:02:41 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:75a11d740a02 |
|---|---|
| 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 the above copyright notice and this paragraph are | |
| 7 * duplicated in all such forms and that any documentation, | |
| 8 * advertising materials, and other materials related to such | |
| 9 * distribution and use acknowledge that the software was developed | |
| 10 * by the University of California, Berkeley. The name of the | |
| 11 * University may not be used to endorse or promote products derived | |
| 12 * from this software without specific prior written permission. | |
| 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
| 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
| 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
| 16 */ | |
| 17 | |
| 18 #if defined(LIBC_SCCS) && !defined(lint) | |
| 19 static char sccsid[] = "@(#)doprnt.c 5.35 (Berkeley) 6/27/88"; | |
| 20 #endif /* LIBC_SCCS and not lint */ | |
| 21 | |
| 22 #include <sys/types.h> | |
| 23 #include <varargs.h> | |
| 24 #include <stdio.h> | |
| 25 #include <ctype.h> | |
| 26 | |
| 27 /* 11-bit exponent (VAX G floating point) is 308 decimal digits */ | |
| 28 #define MAXEXP 308 | |
| 29 /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ | |
| 30 #define MAXFRACT 39 | |
| 31 | |
| 32 #define DEFPREC 6 | |
| 33 | |
| 34 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ | |
| 35 | |
| 36 #define PUTC(ch) (void) putc(ch, fp) | |
| 37 | |
| 38 #define ARG() \ | |
| 39 _ulong = flags&LONGINT ? va_arg(argp, long) : \ | |
| 40 flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); | |
| 41 | |
| 42 #define todigit(c) ((c) - '0') | |
| 43 #define tochar(n) ((n) + '0') | |
| 44 | |
| 45 /* have to deal with the negative buffer count kludge */ | |
| 46 #define NEGATIVE_COUNT_KLUDGE | |
| 47 | |
| 48 #define LONGINT 0x01 /* long integer */ | |
| 49 #define LONGDBL 0x02 /* long double; unimplemented */ | |
| 50 #define SHORTINT 0x04 /* short integer */ | |
| 51 #define ALT 0x08 /* alternate form */ | |
| 52 #define LADJUST 0x10 /* left adjustment */ | |
| 53 #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ | |
| 54 #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ | |
| 55 | |
| 56 _doprnt(fmt0, argp, fp) | |
| 57 u_char *fmt0; | |
| 58 va_list argp; | |
| 59 register FILE *fp; | |
| 60 { | |
| 61 register u_char *fmt; /* format string */ | |
| 62 register int ch; /* character from fmt */ | |
| 63 register int cnt; /* return value accumulator */ | |
| 64 register int n; /* random handy integer */ | |
| 65 register char *t; /* buffer pointer */ | |
| 66 double _double; /* double precision arguments %[eEfgG] */ | |
| 67 u_long _ulong; /* integer arguments %[diouxX] */ | |
| 68 int base; /* base for [diouxX] conversion */ | |
| 69 int dprec; /* decimal precision in [diouxX] */ | |
| 70 int fieldsz; /* field size expanded by sign, etc */ | |
| 71 int flags; /* flags as above */ | |
| 72 int fpprec; /* `extra' floating precision in [eEfgG] */ | |
| 73 int prec; /* precision from format (%.3d), or -1 */ | |
| 74 int realsz; /* field size expanded by decimal precision */ | |
| 75 int size; /* size of converted field or string */ | |
| 76 int width; /* width from format (%8d), or 0 */ | |
| 77 char sign; /* sign prefix (' ', '+', '-', or \0) */ | |
| 78 char softsign; /* temporary negative sign for floats */ | |
| 79 char *digs; /* digits for [diouxX] conversion */ | |
| 80 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ | |
| 81 | |
| 82 if (fp->_flag & _IORW) { | |
| 83 fp->_flag |= _IOWRT; | |
| 84 fp->_flag &= ~(_IOEOF|_IOREAD); | |
| 85 } | |
| 86 if ((fp->_flag & _IOWRT) == 0) | |
| 87 return (EOF); | |
| 88 | |
| 89 fmt = fmt0; | |
| 90 digs = "0123456789abcdef"; | |
| 91 for (cnt = 0;; ++fmt) { | |
| 92 n = fp->_cnt; | |
| 93 for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%'; | |
| 94 ++cnt, ++fmt) | |
| 95 if (--n < 0 | |
| 96 #ifdef NEGATIVE_COUNT_KLUDGE | |
| 97 && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz) | |
| 98 #endif | |
| 99 || ch == '\n' && fp->_flag & _IOLBF) { | |
| 100 fp->_cnt = n; | |
| 101 fp->_ptr = t; | |
| 102 (void) _flsbuf((u_char)ch, fp); | |
| 103 n = fp->_cnt; | |
| 104 t = (char *)fp->_ptr; | |
| 105 } else | |
| 106 *t++ = ch; | |
| 107 fp->_cnt = n; | |
| 108 fp->_ptr = t; | |
| 109 if (!ch) | |
| 110 return (cnt); | |
| 111 | |
| 112 flags = 0; dprec = 0; fpprec = 0; width = 0; | |
| 113 prec = -1; | |
| 114 sign = '\0'; | |
| 115 | |
| 116 rflag: switch (*++fmt) { | |
| 117 case ' ': | |
| 118 /* | |
| 119 * ``If the space and + flags both appear, the space | |
| 120 * flag will be ignored.'' | |
| 121 * -- ANSI X3J11 | |
| 122 */ | |
| 123 if (!sign) | |
| 124 sign = ' '; | |
| 125 goto rflag; | |
| 126 case '#': | |
| 127 flags |= ALT; | |
| 128 goto rflag; | |
| 129 case '*': | |
| 130 /* | |
| 131 * ``A negative field width argument is taken as a | |
| 132 * - flag followed by a positive field width.'' | |
| 133 * -- ANSI X3J11 | |
| 134 * They don't exclude field widths read from args. | |
| 135 */ | |
| 136 if ((width = va_arg(argp, int)) >= 0) | |
| 137 goto rflag; | |
| 138 width = -width; | |
| 139 /* FALLTHROUGH */ | |
| 140 case '-': | |
| 141 flags |= LADJUST; | |
| 142 goto rflag; | |
| 143 case '+': | |
| 144 sign = '+'; | |
| 145 goto rflag; | |
| 146 case '.': | |
| 147 if (*++fmt == '*') | |
| 148 n = va_arg(argp, int); | |
| 149 else { | |
| 150 n = 0; | |
| 151 while (isascii(*fmt) && isdigit(*fmt)) | |
| 152 n = 10 * n + todigit(*fmt++); | |
| 153 --fmt; | |
| 154 } | |
| 155 prec = n < 0 ? -1 : n; | |
| 156 goto rflag; | |
| 157 case '0': | |
| 158 /* | |
| 159 * ``Note that 0 is taken as a flag, not as the | |
| 160 * beginning of a field width.'' | |
| 161 * -- ANSI X3J11 | |
| 162 */ | |
| 163 flags |= ZEROPAD; | |
| 164 goto rflag; | |
| 165 case '1': case '2': case '3': case '4': | |
| 166 case '5': case '6': case '7': case '8': case '9': | |
| 167 n = 0; | |
| 168 do { | |
| 169 n = 10 * n + todigit(*fmt); | |
| 170 } while (isascii(*++fmt) && isdigit(*fmt)); | |
| 171 width = n; | |
| 172 --fmt; | |
| 173 goto rflag; | |
| 174 case 'L': | |
| 175 flags |= LONGDBL; | |
| 176 goto rflag; | |
| 177 case 'h': | |
| 178 flags |= SHORTINT; | |
| 179 goto rflag; | |
| 180 case 'l': | |
| 181 flags |= LONGINT; | |
| 182 goto rflag; | |
| 183 case 'c': | |
| 184 *(t = buf) = va_arg(argp, int); | |
| 185 size = 1; | |
| 186 sign = '\0'; | |
| 187 goto pforw; | |
| 188 case 'D': | |
| 189 flags |= LONGINT; | |
| 190 /*FALLTHROUGH*/ | |
| 191 case 'd': | |
| 192 case 'i': | |
| 193 ARG(); | |
| 194 if ((long)_ulong < 0) { | |
| 195 _ulong = -_ulong; | |
| 196 sign = '-'; | |
| 197 } | |
| 198 base = 10; | |
| 199 goto number; | |
| 200 case 'e': | |
| 201 case 'E': | |
| 202 case 'f': | |
| 203 case 'g': | |
| 204 case 'G': | |
| 205 _double = va_arg(argp, double); | |
| 206 /* | |
| 207 * don't do unrealistic precision; just pad it with | |
| 208 * zeroes later, so buffer size stays rational. | |
| 209 */ | |
| 210 if (prec > MAXFRACT) { | |
| 211 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT)) | |
| 212 fpprec = prec - MAXFRACT; | |
| 213 prec = MAXFRACT; | |
| 214 } | |
| 215 else if (prec == -1) | |
| 216 prec = DEFPREC; | |
| 217 /* | |
| 218 * softsign avoids negative 0 if _double is < 0 and | |
| 219 * no significant digits will be shown | |
| 220 */ | |
| 221 if (_double < 0) { | |
| 222 softsign = '-'; | |
| 223 _double = -_double; | |
| 224 } | |
| 225 else | |
| 226 softsign = 0; | |
| 227 /* | |
| 228 * cvt may have to round up past the "start" of the | |
| 229 * buffer, i.e. ``intf("%.2f", (double)9.999);''; | |
| 230 * if the first char isn't NULL, it did. | |
| 231 */ | |
| 232 *buf = NULL; | |
| 233 size = cvt(_double, prec, flags, &softsign, *fmt, buf, | |
| 234 buf + sizeof(buf)); | |
| 235 if (softsign) | |
| 236 sign = '-'; | |
| 237 t = *buf ? buf : buf + 1; | |
| 238 goto pforw; | |
| 239 case 'n': | |
| 240 if (flags & LONGINT) | |
| 241 *va_arg(argp, long *) = cnt; | |
| 242 else if (flags & SHORTINT) | |
| 243 *va_arg(argp, short *) = cnt; | |
| 244 else | |
| 245 *va_arg(argp, int *) = cnt; | |
| 246 break; | |
| 247 case 'O': | |
| 248 flags |= LONGINT; | |
| 249 /*FALLTHROUGH*/ | |
| 250 case 'o': | |
| 251 ARG(); | |
| 252 base = 8; | |
| 253 goto nosign; | |
| 254 case 'p': | |
| 255 /* | |
| 256 * ``The argument shall be a pointer to void. The | |
| 257 * value of the pointer is converted to a sequence | |
| 258 * of printable characters, in an implementation- | |
| 259 * defined manner.'' | |
| 260 * -- ANSI X3J11 | |
| 261 */ | |
| 262 /* NOSTRICT */ | |
| 263 _ulong = (u_long)va_arg(argp, void *); | |
| 264 base = 16; | |
| 265 goto nosign; | |
| 266 case 's': | |
| 267 if (!(t = va_arg(argp, char *))) | |
| 268 t = "(null)"; | |
| 269 if (prec >= 0) { | |
| 270 /* | |
| 271 * can't use strlen; can only look for the | |
| 272 * NUL in the first `prec' characters, and | |
| 273 * strlen() will go further. | |
| 274 */ | |
| 275 char *p, *memchr(); | |
| 276 | |
| 277 if (p = memchr(t, 0, prec)) { | |
| 278 size = p - t; | |
| 279 if (size > prec) | |
| 280 size = prec; | |
| 281 } else | |
| 282 size = prec; | |
| 283 } else | |
| 284 size = strlen(t); | |
| 285 sign = '\0'; | |
| 286 goto pforw; | |
| 287 case 'U': | |
| 288 flags |= LONGINT; | |
| 289 /*FALLTHROUGH*/ | |
| 290 case 'u': | |
| 291 ARG(); | |
| 292 base = 10; | |
| 293 goto nosign; | |
| 294 case 'X': | |
| 295 digs = "0123456789ABCDEF"; | |
| 296 /* FALLTHROUGH */ | |
| 297 case 'x': | |
| 298 ARG(); | |
| 299 base = 16; | |
| 300 /* leading 0x/X only if non-zero */ | |
| 301 if (flags & ALT && _ulong != 0) | |
| 302 flags |= HEXPREFIX; | |
| 303 | |
| 304 /* unsigned conversions */ | |
| 305 nosign: sign = '\0'; | |
| 306 /* | |
| 307 * ``... diouXx conversions ... if a precision is | |
| 308 * specified, the 0 flag will be ignored.'' | |
| 309 * -- ANSI X3J11 | |
| 310 */ | |
| 311 number: if ((dprec = prec) >= 0) | |
| 312 flags &= ~ZEROPAD; | |
| 313 | |
| 314 /* | |
| 315 * ``The result of converting a zero value with an | |
| 316 * explicit precision of zero is no characters.'' | |
| 317 * -- ANSI X3J11 | |
| 318 */ | |
| 319 t = buf + BUF; | |
| 320 if (_ulong != 0 || prec != 0) { | |
| 321 do { | |
| 322 *--t = digs[_ulong % base]; | |
| 323 _ulong /= base; | |
| 324 } while (_ulong); | |
| 325 digs = "0123456789abcdef"; | |
| 326 if (flags & ALT && base == 8 && *t != '0') | |
| 327 *--t = '0'; /* octal leading 0 */ | |
| 328 } | |
| 329 size = buf + BUF - t; | |
| 330 | |
| 331 pforw: | |
| 332 /* | |
| 333 * All reasonable formats wind up here. At this point, | |
| 334 * `t' points to a string which (if not flags&LADJUST) | |
| 335 * should be padded out to `width' places. If | |
| 336 * flags&ZEROPAD, it should first be prefixed by any | |
| 337 * sign or other prefix; otherwise, it should be blank | |
| 338 * padded before the prefix is emitted. After any | |
| 339 * left-hand padding and prefixing, emit zeroes | |
| 340 * required by a decimal [diouxX] precision, then print | |
| 341 * the string proper, then emit zeroes required by any | |
| 342 * leftover floating precision; finally, if LADJUST, | |
| 343 * pad with blanks. | |
| 344 */ | |
| 345 | |
| 346 /* | |
| 347 * compute actual size, so we know how much to pad | |
| 348 * fieldsz excludes decimal prec; realsz includes it | |
| 349 */ | |
| 350 fieldsz = size + fpprec; | |
| 351 if (sign) | |
| 352 fieldsz++; | |
| 353 if (flags & HEXPREFIX) | |
| 354 fieldsz += 2; | |
| 355 realsz = dprec > fieldsz ? dprec : fieldsz; | |
| 356 | |
| 357 /* right-adjusting blank padding */ | |
| 358 if ((flags & (LADJUST|ZEROPAD)) == 0 && width) | |
| 359 for (n = realsz; n < width; n++) | |
| 360 PUTC(' '); | |
| 361 /* prefix */ | |
| 362 if (sign) | |
| 363 PUTC(sign); | |
| 364 if (flags & HEXPREFIX) { | |
| 365 PUTC('0'); | |
| 366 PUTC((char)*fmt); | |
| 367 } | |
| 368 /* right-adjusting zero padding */ | |
| 369 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) | |
| 370 for (n = realsz; n < width; n++) | |
| 371 PUTC('0'); | |
| 372 /* leading zeroes from decimal precision */ | |
| 373 for (n = fieldsz; n < dprec; n++) | |
| 374 PUTC('0'); | |
| 375 | |
| 376 /* the string or number proper */ | |
| 377 if (fp->_cnt - (n = size) >= 0 && | |
| 378 (fp->_flag & _IOLBF) == 0) { | |
| 379 fp->_cnt -= n; | |
| 380 bcopy(t, (char *)fp->_ptr, n); | |
| 381 fp->_ptr += n; | |
| 382 } else | |
| 383 while (--n >= 0) | |
| 384 PUTC(*t++); | |
| 385 /* trailing f.p. zeroes */ | |
| 386 while (--fpprec >= 0) | |
| 387 PUTC('0'); | |
| 388 /* left-adjusting padding (always blank) */ | |
| 389 if (flags & LADJUST) | |
| 390 for (n = realsz; n < width; n++) | |
| 391 PUTC(' '); | |
| 392 /* finally, adjust cnt */ | |
| 393 cnt += width > realsz ? width : realsz; | |
| 394 break; | |
| 395 case '\0': /* "%?" prints ?, unless ? is NULL */ | |
| 396 return (cnt); | |
| 397 default: | |
| 398 PUTC((char)*fmt); | |
| 399 cnt++; | |
| 400 } | |
| 401 } | |
| 402 /* NOTREACHED */ | |
| 403 } | |
| 404 | |
| 405 static | |
| 406 cvt(number, prec, flags, signp, fmtch, startp, endp) | |
| 407 double number; | |
| 408 register int prec; | |
| 409 int flags; | |
| 410 u_char fmtch; | |
| 411 char *signp, *startp, *endp; | |
| 412 { | |
| 413 register char *p, *t; | |
| 414 register double fract; | |
| 415 int dotrim, expcnt, gformat; | |
| 416 double integer, tmp, modf(); | |
| 417 char *exponent(), *round(); | |
| 418 | |
| 419 dotrim = expcnt = gformat = 0; | |
| 420 fract = modf(number, &integer); | |
| 421 | |
| 422 /* get an extra slot for rounding. */ | |
| 423 t = ++startp; | |
| 424 | |
| 425 /* | |
| 426 * get integer portion of number; put into the end of the buffer; the | |
| 427 * .01 is added for modf(356.0 / 10, &integer) returning .59999999... | |
| 428 */ | |
| 429 for (p = endp - 1; integer; ++expcnt) { | |
| 430 tmp = modf(integer / 10, &integer); | |
| 431 *p-- = tochar((int)((tmp + .01) * 10)); | |
| 432 } | |
| 433 switch(fmtch) { | |
| 434 case 'f': | |
| 435 /* reverse integer into beginning of buffer */ | |
| 436 if (expcnt) | |
| 437 for (; ++p < endp; *t++ = *p); | |
| 438 else | |
| 439 *t++ = '0'; | |
| 440 /* | |
| 441 * if precision required or alternate flag set, add in a | |
| 442 * decimal point. | |
| 443 */ | |
| 444 if (prec || flags&ALT) | |
| 445 *t++ = '.'; | |
| 446 /* if requires more precision and some fraction left */ | |
| 447 if (fract) { | |
| 448 if (prec) | |
| 449 do { | |
| 450 fract = modf(fract * 10, &tmp); | |
| 451 *t++ = tochar((int)tmp); | |
| 452 } while (--prec && fract); | |
| 453 if (fract) | |
| 454 startp = round(fract, (int *)NULL, startp, | |
| 455 t - 1, (char)0, signp); | |
| 456 } | |
| 457 for (; prec--; *t++ = '0'); | |
| 458 break; | |
| 459 case 'e': | |
| 460 case 'E': | |
| 461 eformat: if (expcnt) { | |
| 462 *t++ = *++p; | |
| 463 if (prec || flags&ALT) | |
| 464 *t++ = '.'; | |
| 465 /* if requires more precision and some integer left */ | |
| 466 for (; prec && ++p < endp; --prec) | |
| 467 *t++ = *p; | |
| 468 /* | |
| 469 * if done precision and more of the integer component, | |
| 470 * round using it; adjust fract so we don't re-round | |
| 471 * later. | |
| 472 */ | |
| 473 if (!prec && ++p < endp) { | |
| 474 fract = 0; | |
| 475 startp = round((double)0, &expcnt, startp, | |
| 476 t - 1, *p, signp); | |
| 477 } | |
| 478 /* adjust expcnt for digit in front of decimal */ | |
| 479 --expcnt; | |
| 480 } | |
| 481 /* until first fractional digit, decrement exponent */ | |
| 482 else if (fract) { | |
| 483 /* adjust expcnt for digit in front of decimal */ | |
| 484 for (expcnt = -1;; --expcnt) { | |
| 485 fract = modf(fract * 10, &tmp); | |
| 486 if (tmp) | |
| 487 break; | |
| 488 } | |
| 489 *t++ = tochar((int)tmp); | |
| 490 if (prec || flags&ALT) | |
| 491 *t++ = '.'; | |
| 492 } | |
| 493 else { | |
| 494 *t++ = '0'; | |
| 495 if (prec || flags&ALT) | |
| 496 *t++ = '.'; | |
| 497 } | |
| 498 /* if requires more precision and some fraction left */ | |
| 499 if (fract) { | |
| 500 if (prec) | |
| 501 do { | |
| 502 fract = modf(fract * 10, &tmp); | |
| 503 *t++ = tochar((int)tmp); | |
| 504 } while (--prec && fract); | |
| 505 if (fract) | |
| 506 startp = round(fract, &expcnt, startp, | |
| 507 t - 1, (char)0, signp); | |
| 508 } | |
| 509 /* if requires more precision */ | |
| 510 for (; prec--; *t++ = '0'); | |
| 511 | |
| 512 /* unless alternate flag, trim any g/G format trailing 0's */ | |
| 513 if (gformat && !(flags&ALT)) { | |
| 514 while (t > startp && *--t == '0'); | |
| 515 if (*t == '.') | |
| 516 --t; | |
| 517 ++t; | |
| 518 } | |
| 519 t = exponent(t, expcnt, fmtch); | |
| 520 break; | |
| 521 case 'g': | |
| 522 case 'G': | |
| 523 /* a precision of 0 is treated as a precision of 1. */ | |
| 524 if (!prec) | |
| 525 ++prec; | |
| 526 /* | |
| 527 * ``The style used depends on the value converted; style e | |
| 528 * will be used only if the exponent resulting from the | |
| 529 * conversion is less than -4 or greater than the precision.'' | |
| 530 * -- ANSI X3J11 | |
| 531 */ | |
| 532 if (expcnt > prec || !expcnt && fract && fract < .0001) { | |
| 533 /* | |
| 534 * g/G format counts "significant digits, not digits of | |
| 535 * precision; for the e/E format, this just causes an | |
| 536 * off-by-one problem, i.e. g/G considers the digit | |
| 537 * before the decimal point significant and e/E doesn't | |
| 538 * count it as precision. | |
| 539 */ | |
| 540 --prec; | |
| 541 fmtch -= 2; /* G->E, g->e */ | |
| 542 gformat = 1; | |
| 543 goto eformat; | |
| 544 } | |
| 545 /* | |
| 546 * reverse integer into beginning of buffer, | |
| 547 * note, decrement precision | |
| 548 */ | |
| 549 if (expcnt) | |
| 550 for (; ++p < endp; *t++ = *p, --prec); | |
| 551 else | |
| 552 *t++ = '0'; | |
| 553 /* | |
| 554 * if precision required or alternate flag set, add in a | |
| 555 * decimal point. If no digits yet, add in leading 0. | |
| 556 */ | |
| 557 if (prec || flags&ALT) { | |
| 558 dotrim = 1; | |
| 559 *t++ = '.'; | |
| 560 } | |
| 561 else | |
| 562 dotrim = 0; | |
| 563 /* if requires more precision and some fraction left */ | |
| 564 if (fract) { | |
| 565 if (prec) { | |
| 566 do { | |
| 567 fract = modf(fract * 10, &tmp); | |
| 568 *t++ = tochar((int)tmp); | |
| 569 } while(!tmp); | |
| 570 while (--prec && fract) { | |
| 571 fract = modf(fract * 10, &tmp); | |
| 572 *t++ = tochar((int)tmp); | |
| 573 } | |
| 574 } | |
| 575 if (fract) | |
| 576 startp = round(fract, (int *)NULL, startp, | |
| 577 t - 1, (char)0, signp); | |
| 578 } | |
| 579 /* alternate format, adds 0's for precision, else trim 0's */ | |
| 580 if (flags&ALT) | |
| 581 for (; prec--; *t++ = '0'); | |
| 582 else if (dotrim) { | |
| 583 while (t > startp && *--t == '0'); | |
| 584 if (*t != '.') | |
| 585 ++t; | |
| 586 } | |
| 587 } | |
| 588 return(t - startp); | |
| 589 } | |
| 590 | |
| 591 static char * | |
| 592 round(fract, exp, start, end, ch, signp) | |
| 593 double fract; | |
| 594 int *exp; | |
| 595 register char *start, *end; | |
| 596 char ch, *signp; | |
| 597 { | |
| 598 double tmp; | |
| 599 | |
| 600 if (fract) | |
| 601 (void)modf(fract * 10, &tmp); | |
| 602 else | |
| 603 tmp = todigit(ch); | |
| 604 if (tmp > 4) | |
| 605 for (;; --end) { | |
| 606 if (*end == '.') | |
| 607 --end; | |
| 608 if (++*end <= '9') | |
| 609 break; | |
| 610 *end = '0'; | |
| 611 if (end == start) { | |
| 612 if (exp) { /* e/E; increment exponent */ | |
| 613 *end = '1'; | |
| 614 ++*exp; | |
| 615 } | |
| 616 else { /* f; add extra digit */ | |
| 617 *--end = '1'; | |
| 618 --start; | |
| 619 } | |
| 620 break; | |
| 621 } | |
| 622 } | |
| 623 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ | |
| 624 else if (*signp == '-') | |
| 625 for (;; --end) { | |
| 626 if (*end == '.') | |
| 627 --end; | |
| 628 if (*end != '0') | |
| 629 break; | |
| 630 if (end == start) | |
| 631 *signp = 0; | |
| 632 } | |
| 633 return(start); | |
| 634 } | |
| 635 | |
| 636 static char * | |
| 637 exponent(p, exp, fmtch) | |
| 638 register char *p; | |
| 639 register int exp; | |
| 640 u_char fmtch; | |
| 641 { | |
| 642 register char *t; | |
| 643 char expbuf[MAXEXP]; | |
| 644 | |
| 645 *p++ = fmtch; | |
| 646 if (exp < 0) { | |
| 647 exp = -exp; | |
| 648 *p++ = '-'; | |
| 649 } | |
| 650 else | |
| 651 *p++ = '+'; | |
| 652 t = expbuf + MAXEXP; | |
| 653 if (exp > 9) { | |
| 654 do { | |
| 655 *--t = tochar(exp % 10); | |
| 656 } while ((exp /= 10) > 9); | |
| 657 *--t = tochar(exp); | |
| 658 for (; t < expbuf + MAXEXP; *p++ = *t++); | |
| 659 } | |
| 660 else { | |
| 661 *p++ = '0'; | |
| 662 *p++ = tochar(exp); | |
| 663 } | |
| 664 return(p); | |
| 665 } |
