github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/lib9/fmt/fltfmt.c (about) 1 /* 2 * The authors of this software are Rob Pike and Ken Thompson, 3 * with contributions from Mike Burrows and Sean Dorward. 4 * 5 * Copyright (c) 2002-2006 by Lucent Technologies. 6 * Portions Copyright (c) 2004 Google Inc. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose without fee is hereby granted, provided that this entire notice 10 * is included in all copies of any software which is or includes a copy 11 * or modification of this software and in all copies of the supporting 12 * documentation for such software. 13 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 14 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES 15 * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 16 * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 17 */ 18 19 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ 20 #include <u.h> 21 #include <errno.h> 22 #include <libc.h> 23 #include "fmtdef.h" 24 25 enum 26 { 27 FDIGIT = 30, 28 FDEFLT = 6, 29 NSIGNIF = 17 30 }; 31 32 /* 33 * first few powers of 10, enough for about 1/2 of the 34 * total space for doubles. 35 */ 36 static double pows10[] = 37 { 38 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 39 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 40 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, 41 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39, 42 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 43 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59, 44 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69, 45 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79, 46 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89, 47 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99, 48 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, 49 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 50 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 51 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 52 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 53 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 54 }; 55 56 #undef pow10 57 #define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0]))) 58 #define pow10(x) fmtpow10(x) 59 60 static double 61 pow10(int n) 62 { 63 double d; 64 int neg; 65 66 neg = 0; 67 if(n < 0){ 68 neg = 1; 69 n = -n; 70 } 71 72 if(n < npows10) 73 d = pows10[n]; 74 else{ 75 d = pows10[npows10-1]; 76 for(;;){ 77 n -= npows10 - 1; 78 if(n < npows10){ 79 d *= pows10[n]; 80 break; 81 } 82 d *= pows10[npows10 - 1]; 83 } 84 } 85 if(neg) 86 return 1./d; 87 return d; 88 } 89 90 /* 91 * add 1 to the decimal integer string a of length n. 92 * if 99999 overflows into 10000, return 1 to tell caller 93 * to move the virtual decimal point. 94 */ 95 static int 96 xadd1(char *a, int n) 97 { 98 char *b; 99 int c; 100 101 if(n < 0 || n > NSIGNIF) 102 return 0; 103 for(b = a+n-1; b >= a; b--) { 104 c = *b + 1; 105 if(c <= '9') { 106 *b = (char)c; 107 return 0; 108 } 109 *b = '0'; 110 } 111 /* 112 * need to overflow adding digit. 113 * shift number down and insert 1 at beginning. 114 * decimal is known to be 0s or we wouldn't 115 * have gotten this far. (e.g., 99999+1 => 00000) 116 */ 117 a[0] = '1'; 118 return 1; 119 } 120 121 /* 122 * subtract 1 from the decimal integer string a. 123 * if 10000 underflows into 09999, make it 99999 124 * and return 1 to tell caller to move the virtual 125 * decimal point. this way, xsub1 is inverse of xadd1. 126 */ 127 static int 128 xsub1(char *a, int n) 129 { 130 char *b; 131 int c; 132 133 if(n < 0 || n > NSIGNIF) 134 return 0; 135 for(b = a+n-1; b >= a; b--) { 136 c = *b - 1; 137 if(c >= '0') { 138 if(c == '0' && b == a) { 139 /* 140 * just zeroed the top digit; shift everyone up. 141 * decimal is known to be 9s or we wouldn't 142 * have gotten this far. (e.g., 10000-1 => 09999) 143 */ 144 *b = '9'; 145 return 1; 146 } 147 *b = (char)c; 148 return 0; 149 } 150 *b = '9'; 151 } 152 /* 153 * can't get here. the number a is always normalized 154 * so that it has a nonzero first digit. 155 */ 156 abort(); 157 } 158 159 /* 160 * format exponent like sprintf(p, "e%+02d", e) 161 */ 162 static void 163 xfmtexp(char *p, int e, int ucase) 164 { 165 char se[9]; 166 int i; 167 168 *p++ = ucase ? 'E' : 'e'; 169 if(e < 0) { 170 *p++ = '-'; 171 e = -e; 172 } else 173 *p++ = '+'; 174 i = 0; 175 while(e) { 176 se[i++] = (char)(e % 10 + '0'); 177 e /= 10; 178 } 179 while(i < 2) 180 se[i++] = '0'; 181 while(i > 0) 182 *p++ = se[--i]; 183 *p++ = '\0'; 184 } 185 186 /* 187 * compute decimal integer m, exp such that: 188 * f = m*10^exp 189 * m is as short as possible with losing exactness 190 * assumes special cases (NaN, +Inf, -Inf) have been handled. 191 */ 192 static void 193 xdtoa(double f, char *s, int *exp, int *neg, int *ns) 194 { 195 int d, e2, e, ee, i, ndigit, oerrno; 196 char c; 197 char tmp[NSIGNIF+10]; 198 double g; 199 200 oerrno = errno; /* in case strtod smashes errno */ 201 202 /* 203 * make f non-negative. 204 */ 205 *neg = 0; 206 if(f < 0) { 207 f = -f; 208 *neg = 1; 209 } 210 211 /* 212 * must handle zero specially. 213 */ 214 if(f == 0){ 215 *exp = 0; 216 s[0] = '0'; 217 s[1] = '\0'; 218 *ns = 1; 219 return; 220 } 221 222 /* 223 * find g,e such that f = g*10^e. 224 * guess 10-exponent using 2-exponent, then fine tune. 225 */ 226 frexp(f, &e2); 227 e = (int)(e2 * .301029995664); 228 g = f * pow10(-e); 229 while(g < 1) { 230 e--; 231 g = f * pow10(-e); 232 } 233 while(g >= 10) { 234 e++; 235 g = f * pow10(-e); 236 } 237 238 /* 239 * convert NSIGNIF digits as a first approximation. 240 */ 241 for(i=0; i<NSIGNIF; i++) { 242 d = (int)g; 243 s[i] = (char)(d+'0'); 244 g = (g-d) * 10; 245 } 246 s[i] = 0; 247 248 /* 249 * adjust e because s is 314159... not 3.14159... 250 */ 251 e -= NSIGNIF-1; 252 xfmtexp(s+NSIGNIF, e, 0); 253 254 /* 255 * adjust conversion until strtod(s) == f exactly. 256 */ 257 for(i=0; i<10; i++) { 258 g = strtod(s, nil); 259 if(f > g) { 260 if(xadd1(s, NSIGNIF)) { 261 /* gained a digit */ 262 e--; 263 xfmtexp(s+NSIGNIF, e, 0); 264 } 265 continue; 266 } 267 if(f < g) { 268 if(xsub1(s, NSIGNIF)) { 269 /* lost a digit */ 270 e++; 271 xfmtexp(s+NSIGNIF, e, 0); 272 } 273 continue; 274 } 275 break; 276 } 277 278 /* 279 * play with the decimal to try to simplify. 280 */ 281 282 /* 283 * bump last few digits up to 9 if we can 284 */ 285 for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) { 286 c = s[i]; 287 if(c != '9') { 288 s[i] = '9'; 289 g = strtod(s, nil); 290 if(g != f) { 291 s[i] = c; 292 break; 293 } 294 } 295 } 296 297 /* 298 * add 1 in hopes of turning 9s to 0s 299 */ 300 if(s[NSIGNIF-1] == '9') { 301 strcpy(tmp, s); 302 ee = e; 303 if(xadd1(tmp, NSIGNIF)) { 304 ee--; 305 xfmtexp(tmp+NSIGNIF, ee, 0); 306 } 307 g = strtod(tmp, nil); 308 if(g == f) { 309 strcpy(s, tmp); 310 e = ee; 311 } 312 } 313 314 /* 315 * bump last few digits down to 0 as we can. 316 */ 317 for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) { 318 c = s[i]; 319 if(c != '0') { 320 s[i] = '0'; 321 g = strtod(s, nil); 322 if(g != f) { 323 s[i] = c; 324 break; 325 } 326 } 327 } 328 329 /* 330 * remove trailing zeros. 331 */ 332 ndigit = NSIGNIF; 333 while(ndigit > 1 && s[ndigit-1] == '0'){ 334 e++; 335 --ndigit; 336 } 337 s[ndigit] = 0; 338 *exp = e; 339 *ns = ndigit; 340 errno = oerrno; 341 } 342 343 #ifdef PLAN9PORT 344 static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" }; 345 #else 346 static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" }; 347 #endif 348 349 int 350 __efgfmt(Fmt *fmt) 351 { 352 char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t; 353 double f; 354 int c, chr, dotwid, e, exp, ndigits, neg, newndigits; 355 int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2; 356 ulong fl; 357 Rune r, *rs, *rt; 358 359 if(fmt->flags&FmtLong) 360 f = (double)va_arg(fmt->args, long double); 361 else 362 f = va_arg(fmt->args, double); 363 364 /* 365 * extract formatting flags 366 */ 367 fl = fmt->flags; 368 fmt->flags = 0; 369 prec = FDEFLT; 370 if(fl & FmtPrec) 371 prec = fmt->prec; 372 chr = (int)fmt->r; 373 ucase = 0; 374 switch(chr) { 375 case 'A': 376 case 'E': 377 case 'F': 378 case 'G': 379 chr += 'a'-'A'; 380 ucase = 1; 381 break; 382 } 383 384 /* 385 * pick off special numbers. 386 */ 387 if(__isNaN(f)) { 388 s = special[0+ucase]; 389 special: 390 fmt->flags = fl & (FmtWidth|FmtLeft); 391 return __fmtcpy(fmt, s, (int)strlen(s), (int)strlen(s)); 392 } 393 if(__isInf(f, 1)) { 394 s = special[2+ucase]; 395 goto special; 396 } 397 if(__isInf(f, -1)) { 398 s = special[4+ucase]; 399 goto special; 400 } 401 402 /* 403 * get exact representation. 404 */ 405 digits = buf; 406 xdtoa(f, digits, &exp, &neg, &ndigits); 407 408 /* 409 * get locale's decimal point. 410 */ 411 dot = fmt->decimal; 412 if(dot == nil) 413 dot = "."; 414 dotwid = utflen(dot); 415 416 /* 417 * now the formatting fun begins. 418 * compute parameters for actual fmt: 419 * 420 * pad: number of spaces to insert before/after field. 421 * z1: number of zeros to insert before digits 422 * z2: number of zeros to insert after digits 423 * point: number of digits to print before decimal point 424 * ndigits: number of digits to use from digits[] 425 * suf: trailing suffix, like "e-5" 426 */ 427 realchr = chr; 428 switch(chr){ 429 case 'g': 430 /* 431 * convert to at most prec significant digits. (prec=0 means 1) 432 */ 433 if(prec == 0) 434 prec = 1; 435 if(ndigits > prec) { 436 if(digits[prec] >= '5' && xadd1(digits, prec)) 437 exp++; 438 exp += ndigits-prec; 439 ndigits = prec; 440 } 441 442 /* 443 * extra rules for %g (implemented below): 444 * trailing zeros removed after decimal unless FmtSharp. 445 * decimal point only if digit follows. 446 */ 447 448 /* fall through to %e */ 449 default: 450 case 'e': 451 /* 452 * one significant digit before decimal, no leading zeros. 453 */ 454 point = 1; 455 z1 = 0; 456 457 /* 458 * decimal point is after ndigits digits right now. 459 * slide to be after first. 460 */ 461 e = exp + (ndigits-1); 462 463 /* 464 * if this is %g, check exponent and convert prec 465 */ 466 if(realchr == 'g') { 467 if(-4 <= e && e < prec) 468 goto casef; 469 prec--; /* one digit before decimal; rest after */ 470 } 471 472 /* 473 * compute trailing zero padding or truncate digits. 474 */ 475 if(1+prec >= ndigits) 476 z2 = 1+prec - ndigits; 477 else { 478 /* 479 * truncate digits 480 */ 481 assert(realchr != 'g'); 482 newndigits = 1+prec; 483 if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) { 484 /* 485 * had 999e4, now have 100e5 486 */ 487 e++; 488 } 489 ndigits = newndigits; 490 z2 = 0; 491 } 492 xfmtexp(suf, e, ucase); 493 sufwid = (int)strlen(suf); 494 break; 495 496 casef: 497 case 'f': 498 /* 499 * determine where digits go with respect to decimal point 500 */ 501 if(ndigits+exp > 0) { 502 point = ndigits+exp; 503 z1 = 0; 504 } else { 505 point = 1; 506 z1 = 1 + -(ndigits+exp); 507 } 508 509 /* 510 * %g specifies prec = number of significant digits 511 * convert to number of digits after decimal point 512 */ 513 if(realchr == 'g') 514 prec += z1 - point; 515 516 /* 517 * compute trailing zero padding or truncate digits. 518 */ 519 if(point+prec >= z1+ndigits) 520 z2 = point+prec - (z1+ndigits); 521 else { 522 /* 523 * truncate digits 524 */ 525 assert(realchr != 'g'); 526 newndigits = point+prec - z1; 527 if(newndigits < 0) { 528 z1 += newndigits; 529 newndigits = 0; 530 } else if(newndigits == 0) { 531 /* perhaps round up */ 532 if(digits[0] >= '5'){ 533 digits[0] = '1'; 534 newndigits = 1; 535 goto newdigit; 536 } 537 } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) { 538 /* 539 * digits was 999, is now 100; make it 1000 540 */ 541 digits[newndigits++] = '0'; 542 newdigit: 543 /* 544 * account for new digit 545 */ 546 if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/ 547 z1--; 548 else /* 9.99 => 10.00 */ 549 point++; 550 } 551 z2 = 0; 552 ndigits = newndigits; 553 } 554 sufwid = 0; 555 break; 556 } 557 558 /* 559 * if %g is given without FmtSharp, remove trailing zeros. 560 * must do after truncation, so that e.g. print %.3g 1.001 561 * produces 1, not 1.00. sorry, but them's the rules. 562 */ 563 if(realchr == 'g' && !(fl & FmtSharp)) { 564 if(z1+ndigits+z2 >= point) { 565 if(z1+ndigits < point) 566 z2 = point - (z1+ndigits); 567 else{ 568 z2 = 0; 569 while(z1+ndigits > point && digits[ndigits-1] == '0') 570 ndigits--; 571 } 572 } 573 } 574 575 /* 576 * compute width of all digits and decimal point and suffix if any 577 */ 578 wid = z1+ndigits+z2; 579 if(wid > point) 580 wid += dotwid; 581 else if(wid == point){ 582 if(fl & FmtSharp) 583 wid += dotwid; 584 else 585 point++; /* do not print any decimal point */ 586 } 587 wid += sufwid; 588 589 /* 590 * determine sign 591 */ 592 sign = 0; 593 if(neg) 594 sign = '-'; 595 else if(fl & FmtSign) 596 sign = '+'; 597 else if(fl & FmtSpace) 598 sign = ' '; 599 if(sign) 600 wid++; 601 602 /* 603 * compute padding 604 */ 605 pad = 0; 606 if((fl & FmtWidth) && fmt->width > wid) 607 pad = fmt->width - wid; 608 if(pad && !(fl & FmtLeft) && (fl & FmtZero)){ 609 z1 += pad; 610 point += pad; 611 pad = 0; 612 } 613 614 /* 615 * format the actual field. too bad about doing this twice. 616 */ 617 if(fmt->runes){ 618 if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0) 619 return -1; 620 rt = (Rune*)fmt->to; 621 rs = (Rune*)fmt->stop; 622 if(sign) 623 FMTRCHAR(fmt, rt, rs, sign); 624 while(z1>0 || ndigits>0 || z2>0) { 625 if(z1 > 0){ 626 z1--; 627 c = '0'; 628 }else if(ndigits > 0){ 629 ndigits--; 630 c = *digits++; 631 }else{ 632 z2--; 633 c = '0'; 634 } 635 FMTRCHAR(fmt, rt, rs, c); 636 if(--point == 0) { 637 for(p = dot; *p; ){ 638 p += chartorune(&r, p); 639 FMTRCHAR(fmt, rt, rs, r); 640 } 641 } 642 } 643 fmt->nfmt += (int)(rt - (Rune*)fmt->to); 644 fmt->to = rt; 645 if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0) 646 return -1; 647 if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0) 648 return -1; 649 }else{ 650 if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0) 651 return -1; 652 t = (char*)fmt->to; 653 s = (char*)fmt->stop; 654 if(sign) 655 FMTCHAR(fmt, t, s, sign); 656 while(z1>0 || ndigits>0 || z2>0) { 657 if(z1 > 0){ 658 z1--; 659 c = '0'; 660 }else if(ndigits > 0){ 661 ndigits--; 662 c = *digits++; 663 }else{ 664 z2--; 665 c = '0'; 666 } 667 FMTCHAR(fmt, t, s, c); 668 if(--point == 0) 669 for(p=dot; *p; p++) 670 FMTCHAR(fmt, t, s, *p); 671 } 672 fmt->nfmt += (int)(t - (char*)fmt->to); 673 fmt->to = t; 674 if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0) 675 return -1; 676 if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0) 677 return -1; 678 } 679 return 0; 680 } 681