1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 /* 41 * _doprnt: common code for printf, fprintf, sprintf 42 */ 43 44 #include <sys/types.h> 45 #include "file64.h" 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <ctype.h> 49 #include <stdarg.h> 50 #include <values.h> 51 #include <nan.h> 52 #include <memory.h> 53 #include <string.h> 54 #include "print.h" /* parameters & macros for doprnt */ 55 #include "stdiom.h" 56 #include <locale.h> 57 #include <stddef.h> 58 #include "_locale.h" 59 #include "libc.h" 60 61 #define PUT(p, n) { unsigned char *newbufptr; \ 62 if ((newbufptr = bufptr + (n)) > bufferend) { \ 63 _dowrite((p), (n), iop, &bufptr); \ 64 } else { \ 65 (void) memcpy(bufptr, (p), (n)); \ 66 bufptr = newbufptr; \ 67 } \ 68 } 69 #define PAD(s, n) { int nn; \ 70 for (nn = (n); nn > 20; nn -= 20) \ 71 _dowrite((s), 20, iop, &bufptr); \ 72 PUT((s), nn); \ 73 } 74 75 #define SNLEN 5 /* Length of string used when printing a NaN */ 76 77 /* bit positions for flags used in doprnt */ 78 79 #define LENGTH 1 /* l */ 80 #define FPLUS 2 /* + */ 81 #define FMINUS 4 /* - */ 82 #define FBLANK 8 /* blank */ 83 #define FSHARP 16 /* # */ 84 #define PADZERO 32 /* padding zeroes requested via '0' */ 85 #define DOTSEEN 64 /* dot appeared in format specification */ 86 #define SUFFIX 128 /* a suffix is to appear in the output */ 87 #define RZERO 256 /* there will be trailing zeros in output */ 88 #define LZERO 512 /* there will be leading zeroes in output */ 89 #define SHORT 1024 /* h */ 90 91 /* 92 * Positional Parameter information 93 */ 94 #define MAXARGS 30 /* max. number of args for fast positional paramters */ 95 96 /* 97 * stva_list is used to subvert C's restriction that a variable with an 98 * array type can not appear on the left hand side of an assignment operator. 99 * By putting the array inside a structure, the functionality of assigning to 100 * the whole array through a simple assignment is achieved.. 101 */ 102 typedef struct stva_list { 103 va_list ap; 104 } stva_list; 105 106 static char _blanks[] = " "; 107 static char _zeroes[] = "00000000000000000000"; 108 static char uc_digs[] = "0123456789ABCDEF"; 109 static char lc_digs[] = "0123456789abcdef"; 110 static char lc_nan[] = "nan0x"; 111 static char uc_nan[] = "NAN0X"; 112 static char lc_inf[] = "inf"; 113 static char uc_inf[] = "INF"; 114 115 /* 116 * forward declarations 117 */ 118 void _mkarglst(char *, stva_list, stva_list []); 119 void _getarg(char *, stva_list *, int); 120 static int _lowdigit(long *); 121 static void _dowrite(char *, ssize_t, FILE *, unsigned char **); 122 123 static int 124 _lowdigit(long *valptr) 125 { /* This function computes the decimal low-order digit of the number */ 126 /* pointed to by valptr, and returns this digit after dividing */ 127 /* *valptr by ten. This function is called ONLY to compute the */ 128 /* low-order digit of a long whose high-order bit is set. */ 129 130 int lowbit = (int)(*valptr & 1); 131 long value = (*valptr >> 1) & ~HIBITL; 132 133 *valptr = value / 5; 134 return ((int)(value % 5 * 2 + lowbit + '0')); 135 } 136 137 /* The function _dowrite carries out buffer pointer bookkeeping surrounding */ 138 /* a call to fwrite. It is called only when the end of the file output */ 139 /* buffer is approached or in other unusual situations. */ 140 static void 141 _dowrite(char *p, ssize_t n, FILE *iop, unsigned char **ptrptr) 142 { 143 if (!(iop->_flag & _IOREAD)) { 144 iop->_cnt -= (*ptrptr - iop->_ptr); 145 iop->_ptr = *ptrptr; 146 _bufsync(iop, _bufend(iop)); 147 (void) fwrite(p, 1, n, iop); 148 *ptrptr = iop->_ptr; 149 } else 150 *ptrptr = (unsigned char *) memcpy(*ptrptr, p, n) + n; 151 } 152 153 int 154 _doprnt(char *format, va_list in_args, FILE *iop) 155 { 156 157 /* bufptr is used inside of doprnt instead of iop->_ptr; */ 158 /* bufferend is a copy of _bufend(iop), if it exists. For */ 159 /* dummy file descriptors (iop->_flag & _IOREAD), bufferend */ 160 /* may be meaningless. Dummy file descriptors are used so that */ 161 /* sprintf and vsprintf may share the _doprnt routine with the */ 162 /* rest of the printf family. */ 163 164 unsigned char *bufptr; 165 unsigned char *bufferend; 166 167 /* This variable counts output characters. */ 168 int count = 0; 169 170 /* Starting and ending points for value to be printed */ 171 char *bp; 172 char *p; 173 174 /* Field width and precision */ 175 int width, prec; 176 177 /* Format code */ 178 int fcode; 179 180 /* Number of padding zeroes required on the left and right */ 181 int lzero, rzero; 182 183 /* Flags - bit positions defined by LENGTH, FPLUS, FMINUS, FBLANK, */ 184 /* and FSHARP are set if corresponding character is in format */ 185 /* Bit position defined by PADZERO means extra space in the field */ 186 /* should be padded with leading zeroes rather than with blanks */ 187 int flagword; 188 189 /* Values are developed in this buffer */ 190 char buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))]; 191 192 /* Pointer to sign, "0x", "0X", or empty */ 193 char *prefix; 194 195 /* Exponent or empty */ 196 char *suffix; 197 198 /* Buffer to create exponent */ 199 char expbuf[MAXESIZ + 1]; 200 201 /* Length of prefix and of suffix */ 202 int prefixlength, suffixlength; 203 204 /* Combined length of leading zeroes, trailing zeroes, and suffix */ 205 int otherlength; 206 207 /* The value being converted, if integer */ 208 long val; 209 210 /* The value being converted, if real */ 211 double dval; 212 213 /* Output values from fcvt and ecvt */ 214 int decpt, sign; 215 216 /* Pointer to a translate table for digits of whatever radix */ 217 char *tab; 218 219 /* Work variables */ 220 int k, lradix, mradix; 221 222 /* Variables used to flag an infinities and nans, resp. */ 223 /* Nan_flg is used with two purposes: to flag a NaN and */ 224 /* as the length of the string ``NAN0X'' (``nan0x'') */ 225 int inf_nan = 0, NaN_flg = 0; 226 227 /* Pointer to string "NAN0X" or "nan0x" */ 228 char *SNAN; 229 230 /* Flag for negative infinity or NaN */ 231 int neg_in = 0; 232 233 /* variables for positional parameters */ 234 char *sformat = format; /* save the beginning of the format */ 235 int fpos = 1; /* 1 if first positional parameter */ 236 stva_list args; /* used to step through the argument list */ 237 stva_list sargs; 238 /* used to save the start of the argument list */ 239 stva_list bargs; 240 /* used to restore args if positional width or precision */ 241 stva_list arglst[MAXARGS]; 242 /* 243 * array giving the appropriate values for va_arg() to 244 * retrieve the corresponding argument: 245 * arglst[0] is the first argument, 246 * arglst[1] is the second argument, etc. 247 */ 248 int starflg = 0; /* set to 1 if * format specifier seen */ 249 /* 250 * Initialize args and sargs to the start of the argument list. 251 * Note that ANSI guarantees that the address of the first member of 252 * a structure will be the same as the address of the structure. 253 * See equivalent code in libc doprnt.c 254 */ 255 256 #if !(defined(__amd64) && defined(__GNUC__)) /* XX64 - fix me */ 257 va_copy(args.ap, in_args); 258 #endif 259 sargs = args; 260 261 /* if first I/O to the stream get a buffer */ 262 /* Note that iop->_base should not equal 0 for sprintf and vsprintf */ 263 if (iop->_base == 0 && _findbuf(iop) == 0) 264 return (EOF); 265 266 /* initialize buffer pointer and buffer end pointer */ 267 bufptr = iop->_ptr; 268 bufferend = (iop->_flag & _IOREAD) ? 269 (unsigned char *)((long)bufptr | (-1L & ~HIBITL)) 270 : _bufend(iop); 271 272 /* 273 * The main loop -- this loop goes through one iteration 274 * for each string of ordinary characters or format specification. 275 */ 276 for (;;) { 277 ptrdiff_t pdiff; 278 279 if ((fcode = *format) != '\0' && fcode != '%') { 280 bp = format; 281 do { 282 format++; 283 } while ((fcode = *format) != '\0' && fcode != '%'); 284 285 pdiff = format - bp; 286 /* pdiff = no. of non-% chars */ 287 count += pdiff; 288 PUT(bp, pdiff); 289 } 290 if (fcode == '\0') { /* end of format; return */ 291 ptrdiff_t d = bufptr - iop->_ptr; 292 iop->_cnt -= d; 293 iop->_ptr = bufptr; 294 if (bufptr + iop->_cnt > bufferend && 295 !(iop->_flag & _IOREAD)) 296 _bufsync(iop, bufferend); 297 /* 298 * in case of interrupt during last 299 * several lines 300 */ 301 if (iop->_flag & (_IONBF | _IOLBF) && 302 (iop->_flag & _IONBF || 303 memchr((char *)(bufptr-count), '\n', count) != 304 NULL)) 305 (void) _xflsbuf(iop); 306 return (ferror(iop) ? EOF : count); 307 } 308 309 /* 310 * % has been found. 311 * The following switch is used to parse the format 312 * specification and to perform the operation specified 313 * by the format letter. The program repeatedly goes 314 * back to this switch until the format letter is 315 * encountered. 316 */ 317 width = prefixlength = otherlength = flagword = 318 suffixlength = 0; 319 format++; 320 321 charswitch: 322 323 switch (fcode = *format++) { 324 325 case '+': 326 flagword |= FPLUS; 327 goto charswitch; 328 case '-': 329 flagword |= FMINUS; 330 flagword &= ~PADZERO; /* ignore 0 flag */ 331 goto charswitch; 332 case ' ': 333 flagword |= FBLANK; 334 goto charswitch; 335 case '#': 336 flagword |= FSHARP; 337 goto charswitch; 338 339 /* Scan the field width and precision */ 340 case '.': 341 flagword |= DOTSEEN; 342 prec = 0; 343 goto charswitch; 344 345 case '*': 346 if (isdigit(*format)) { 347 starflg = 1; 348 bargs = args; 349 goto charswitch; 350 } 351 if (!(flagword & DOTSEEN)) { 352 width = va_arg(args.ap, int); 353 if (width < 0) { 354 width = -width; 355 flagword ^= FMINUS; 356 } 357 } else { 358 prec = va_arg(args.ap, int); 359 if (prec < 0) 360 prec = 0; 361 } 362 goto charswitch; 363 364 case '$': 365 { 366 int position; 367 stva_list targs; 368 if (fpos) { 369 _mkarglst(sformat, sargs, arglst); 370 fpos = 0; 371 } 372 if (flagword & DOTSEEN) { 373 position = prec; 374 prec = 0; 375 } else { 376 position = width; 377 width = 0; 378 } 379 if (position <= 0) { 380 /* illegal position */ 381 format--; 382 continue; 383 } 384 if (position <= MAXARGS) { 385 targs = arglst[position - 1]; 386 } else { 387 targs = arglst[MAXARGS - 1]; 388 _getarg(sformat, &targs, position); 389 } 390 if (!starflg) 391 args = targs; 392 else { 393 starflg = 0; 394 args = bargs; 395 if (flagword & DOTSEEN) 396 prec = va_arg(targs.ap, int); 397 else 398 width = va_arg(targs.ap, int); 399 } 400 goto charswitch; 401 } 402 403 case '0': /* obsolescent spec: leading zero in width */ 404 /* means pad with leading zeros */ 405 if (!(flagword & (DOTSEEN | FMINUS))) 406 flagword |= PADZERO; 407 /* FALLTHROUGH */ 408 case '1': 409 case '2': 410 case '3': 411 case '4': 412 case '5': 413 case '6': 414 case '7': 415 case '8': 416 case '9': 417 { 418 int num = fcode - '0'; 419 while (isdigit(fcode = *format)) { 420 num = num * 10 + fcode - '0'; 421 format++; 422 } 423 if (flagword & DOTSEEN) 424 prec = num; 425 else 426 width = num; 427 goto charswitch; 428 } 429 430 /* Scan the length modifier */ 431 case 'l': 432 flagword |= LENGTH; 433 goto charswitch; 434 case 'h': 435 flagword |= SHORT; 436 goto charswitch; 437 case 'L': 438 goto charswitch; 439 440 /* 441 * The character addressed by format must be 442 * the format letter -- there is nothing 443 * left for it to be. 444 * 445 * The status of the +, -, #, and blank 446 * flags are reflected in the variable 447 * "flagword". "width" and "prec" contain 448 * numbers corresponding to the digit 449 * strings before and after the decimal 450 * point, respectively. If there was no 451 * decimal point, then flagword & DOTSEEN 452 * is false and the value of prec is meaningless. 453 * 454 * The following switch cases set things up 455 * for printing. What ultimately gets 456 * printed will be padding blanks, a 457 * prefix, left padding zeroes, a value, 458 * right padding zeroes, a suffix, and 459 * more padding blanks. Padding blanks 460 * will not appear simultaneously on both 461 * the left and the right. Each case in 462 * this switch will compute the value, and 463 * leave in several variables the informa- 464 * tion necessary to construct what is to 465 * be printed. 466 * 467 * The prefix is a sign, a blank, "0x", 468 * "0X", or null, and is addressed by 469 * "prefix". 470 * 471 * The suffix is either null or an 472 * exponent, and is addressed by "suffix". 473 * If there is a suffix, the flagword bit 474 * SUFFIX will be set. 475 * 476 * The value to be printed starts at "bp" 477 * and continues up to and not including 478 * "p". 479 * 480 * "lzero" and "rzero" will contain the 481 * number of padding zeroes required on 482 * the left and right, respectively. 483 * The flagword bits LZERO and RZERO tell 484 * whether padding zeros are required. 485 * 486 * The number of padding blanks, and 487 * whether they go on the left or the 488 * right, will be computed on exit from 489 * the switch. 490 */ 491 492 493 494 495 /* 496 * decimal fixed point representations 497 * 498 * HIBITL is 100...000 499 * binary, and is equal to the maximum 500 * negative number. 501 * We assume a 2's complement machine 502 */ 503 504 case 'i': 505 case 'd': 506 /* Fetch the argument to be printed */ 507 if (flagword & LENGTH) 508 val = va_arg(args.ap, long); 509 else 510 val = va_arg(args.ap, int); 511 512 if (flagword & SHORT) 513 val = (short)val; 514 515 /* Set buffer pointer to last digit */ 516 p = bp = buf + MAXDIGS; 517 518 /* If signed conversion, make sign */ 519 if (val < 0) { 520 prefix = "-"; 521 prefixlength = 1; 522 /* 523 * Negate, checking in 524 * advance for possible 525 * overflow. 526 */ 527 if (val != HIBITL) 528 val = -val; 529 else /* number is -HIBITL; convert last */ 530 /* digit now and get positive number */ 531 *--bp = _lowdigit(&val); 532 } else if (flagword & FPLUS) { 533 prefix = "+"; 534 prefixlength = 1; 535 } else if (flagword & FBLANK) { 536 prefix = " "; 537 prefixlength = 1; 538 } 539 540 decimal: 541 { 542 long qval = val; 543 long saveq; 544 545 if (qval <= 9) { 546 if (qval != 0 || !(flagword & DOTSEEN)) 547 *--bp = (char)(qval + '0'); 548 } else { 549 do { 550 saveq = qval; 551 qval /= 10; 552 *--bp = (char)(saveq - 553 qval * 10 + '0'); 554 } while (qval > 9); 555 *--bp = (char)(qval + '0'); 556 pdiff = (ptrdiff_t)saveq; 557 } 558 } 559 560 /* Calculate minimum padding zero requirement */ 561 if (flagword & DOTSEEN) { 562 int leadzeroes = prec - (int)(p - bp); 563 if (leadzeroes > 0) { 564 otherlength = lzero = leadzeroes; 565 flagword |= LZERO; 566 } 567 } 568 569 break; 570 571 case 'u': 572 /* Fetch the argument to be printed */ 573 if (flagword & LENGTH) 574 val = va_arg(args.ap, long); 575 else 576 val = va_arg(args.ap, unsigned); 577 578 if (flagword & SHORT) 579 val = (unsigned short)val; 580 581 p = bp = buf + MAXDIGS; 582 583 if (val & HIBITL) 584 *--bp = _lowdigit(&val); 585 586 goto decimal; 587 588 /* 589 * non-decimal fixed point representations 590 * for radix equal to a power of two 591 * 592 * "mradix" is one less than the radix for the conversion. 593 * "lradix" is one less than the base 2 log 594 * of the radix for the conversion. Conversion is unsigned. 595 * HIBITL is 100...000 596 * binary, and is equal to the maximum 597 * negative number. 598 * We assume a 2's complement machine 599 */ 600 601 case 'o': 602 mradix = 7; 603 lradix = 2; 604 goto fixed; 605 606 case 'X': 607 case 'x': 608 case 'p': 609 mradix = 15; 610 lradix = 3; 611 612 fixed: 613 /* Fetch the argument to be printed */ 614 if (flagword & LENGTH) 615 val = va_arg(args.ap, long); 616 else 617 val = va_arg(args.ap, unsigned); 618 619 if (flagword & SHORT) 620 val = (unsigned short)val; 621 622 /* Set translate table for digits */ 623 tab = (fcode == 'X') ? uc_digs : lc_digs; 624 625 /* Entry point when printing a double which is a NaN */ 626 put_pc: 627 /* Develop the digits of the value */ 628 p = bp = buf + MAXDIGS; 629 { 630 long qval = val; 631 if (qval == 0) { 632 if (!(flagword & DOTSEEN)) { 633 otherlength = lzero = 1; 634 flagword |= LZERO; 635 } 636 } else 637 do { 638 *--bp = tab[qval & mradix]; 639 qval = ((qval >> 1) & ~HIBITL) 640 >> lradix; 641 } while (qval != 0); 642 } 643 644 /* Calculate minimum padding zero requirement */ 645 if (flagword & DOTSEEN) { 646 int leadzeroes = prec - (int)(p - bp); 647 if (leadzeroes > 0) { 648 otherlength = lzero = leadzeroes; 649 flagword |= LZERO; 650 } 651 } 652 653 /* Handle the # flag */ 654 if (flagword & FSHARP && val != 0) 655 switch (fcode) { 656 case 'o': 657 if (!(flagword & LZERO)) { 658 otherlength = lzero = 1; 659 flagword |= LZERO; 660 } 661 break; 662 case 'x': 663 prefix = "0x"; 664 prefixlength = 2; 665 break; 666 case 'X': 667 prefix = "0X"; 668 prefixlength = 2; 669 break; 670 } 671 672 break; 673 674 case 'E': 675 case 'e': 676 /* 677 * E-format. The general strategy 678 * here is fairly easy: we take 679 * what ecvt gives us and re-format it. 680 */ 681 682 /* Establish default precision */ 683 if (!(flagword & DOTSEEN)) 684 prec = 6; 685 686 /* Fetch the value */ 687 dval = va_arg(args.ap, double); 688 689 /* Check for NaNs and Infinities */ 690 if (IsNANorINF(dval)) { 691 if (IsINF(dval)) { 692 if (IsNegNAN(dval)) 693 neg_in = 1; 694 inf_nan = 1; 695 bp = (fcode == 'E')? uc_inf: lc_inf; 696 p = bp + 3; 697 break; 698 } else { 699 if (IsNegNAN(dval)) 700 neg_in = 1; 701 inf_nan = 1; 702 val = GETNaNPC(dval); 703 NaN_flg = SNLEN; 704 mradix = 15; 705 lradix = 3; 706 if (fcode == 'E') { 707 SNAN = uc_nan; 708 tab = uc_digs; 709 } else { 710 SNAN = lc_nan; 711 tab = lc_digs; 712 } 713 goto put_pc; 714 } 715 } 716 /* Develop the mantissa */ 717 bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign); 718 719 /* Determine the prefix */ 720 e_merge: 721 if (sign) { 722 prefix = "-"; 723 prefixlength = 1; 724 } else if (flagword & FPLUS) { 725 prefix = "+"; 726 prefixlength = 1; 727 } else if (flagword & FBLANK) { 728 prefix = " "; 729 prefixlength = 1; 730 } 731 732 /* Place the first digit in the buffer */ 733 p = &buf[0]; 734 *p++ = (*bp != '\0') ? *bp++ : '0'; 735 736 /* Put in a decimal point if needed */ 737 if (prec != 0 || (flagword & FSHARP)) 738 *p++ = _numeric[0]; 739 740 /* Create the rest of the mantissa */ 741 { 742 int rz = prec; 743 for (; rz > 0 && *bp != '\0'; --rz) 744 *p++ = *bp++; 745 if (rz > 0) { 746 otherlength = rzero = rz; 747 flagword |= RZERO; 748 } 749 } 750 751 bp = &buf[0]; 752 753 /* Create the exponent */ 754 *(suffix = &expbuf[MAXESIZ]) = '\0'; 755 if (dval != 0) { 756 int nn = decpt - 1; 757 if (nn < 0) 758 nn = -nn; 759 for (; nn > 9; nn /= 10) 760 *--suffix = todigit(nn % 10); 761 *--suffix = todigit(nn); 762 } 763 764 /* Prepend leading zeroes to the exponent */ 765 while (suffix > &expbuf[MAXESIZ - 2]) 766 *--suffix = '0'; 767 768 /* Put in the exponent sign */ 769 *--suffix = (decpt > 0 || dval == 0) ? '+' : '-'; 770 771 /* Put in the e */ 772 *--suffix = isupper(fcode) ? 'E' : 'e'; 773 774 /* compute size of suffix */ 775 otherlength += (suffixlength = 776 (int)(&expbuf[MAXESIZ] - suffix)); 777 flagword |= SUFFIX; 778 779 break; 780 781 case 'f': 782 /* 783 * F-format floating point. This is a 784 * good deal less simple than E-format. 785 * The overall strategy will be to call 786 * fcvt, reformat its result into buf, 787 * and calculate how many trailing 788 * zeroes will be required. There will 789 * never be any leading zeroes needed. 790 */ 791 792 /* Establish default precision */ 793 if (!(flagword & DOTSEEN)) 794 prec = 6; 795 796 /* Fetch the value */ 797 dval = va_arg(args.ap, double); 798 799 /* Check for NaNs and Infinities */ 800 if (IsNANorINF(dval)) { 801 if (IsINF(dval)) { 802 if (IsNegNAN(dval)) 803 neg_in = 1; 804 inf_nan = 1; 805 bp = lc_inf; 806 p = bp + 3; 807 break; 808 } else { 809 if (IsNegNAN(dval)) 810 neg_in = 1; 811 inf_nan = 1; 812 val = GETNaNPC(dval); 813 NaN_flg = SNLEN; 814 mradix = 15; 815 lradix = 3; 816 tab = lc_digs; 817 SNAN = lc_nan; 818 goto put_pc; 819 } 820 } 821 /* Do the conversion */ 822 bp = fcvt(dval, min(prec, MAXFCVT), &decpt, &sign); 823 824 /* Determine the prefix */ 825 f_merge: 826 if (sign) { 827 prefix = "-"; 828 prefixlength = 1; 829 } else if (flagword & FPLUS) { 830 prefix = "+"; 831 prefixlength = 1; 832 } else if (flagword & FBLANK) { 833 prefix = " "; 834 prefixlength = 1; 835 } 836 837 /* Initialize buffer pointer */ 838 p = &buf[0]; 839 { 840 int nn = decpt; 841 842 /* Emit the digits before the decimal point */ 843 k = 0; 844 do { 845 *p++ = (nn <= 0 || *bp == '\0' || 846 k >= MAXFSIG) ? 847 '0' : (k++, *bp++); 848 } while (--nn > 0); 849 850 /* Decide whether we need a decimal point */ 851 if ((flagword & FSHARP) || prec > 0) 852 *p++ = _numeric[0]; 853 854 /* Digits (if any) after the decimal point */ 855 nn = min(prec, MAXFCVT); 856 if (prec > nn) { 857 flagword |= RZERO; 858 otherlength = rzero = prec - nn; 859 } 860 while (--nn >= 0) 861 *p++ = (++decpt <= 0 || *bp == '\0' || 862 k >= MAXFSIG) ? 863 '0' : (k++, *bp++); 864 } 865 866 bp = &buf[0]; 867 868 break; 869 870 case 'G': 871 case 'g': 872 /* 873 * g-format. We play around a bit 874 * and then jump into e or f, as needed. 875 */ 876 877 /* Establish default precision */ 878 if (!(flagword & DOTSEEN)) 879 prec = 6; 880 else if (prec == 0) 881 prec = 1; 882 883 /* Fetch the value */ 884 dval = va_arg(args.ap, double); 885 886 /* Check for NaN and Infinities */ 887 if (IsNANorINF(dval)) { 888 if (IsINF(dval)) { 889 if (IsNegNAN(dval)) 890 neg_in = 1; 891 bp = (fcode == 'G') ? uc_inf : lc_inf; 892 p = bp + 3; 893 inf_nan = 1; 894 break; 895 } else { 896 if (IsNegNAN(dval)) 897 neg_in = 1; 898 inf_nan = 1; 899 val = GETNaNPC(dval); 900 NaN_flg = SNLEN; 901 mradix = 15; 902 lradix = 3; 903 if (fcode == 'G') { 904 SNAN = uc_nan; 905 tab = uc_digs; 906 } else { 907 SNAN = lc_nan; 908 tab = lc_digs; 909 } 910 goto put_pc; 911 } 912 } 913 914 /* Do the conversion */ 915 bp = ecvt(dval, min(prec, MAXECVT), &decpt, &sign); 916 if (dval == 0) 917 decpt = 1; 918 { 919 int kk = prec; 920 size_t sz; 921 922 if (!(flagword & FSHARP)) { 923 sz = strlen(bp); 924 if (sz < kk) 925 kk = (int)sz; 926 while (kk >= 1 && bp[kk-1] == '0') 927 --kk; 928 } 929 930 if (decpt < -3 || decpt > prec) { 931 prec = kk - 1; 932 goto e_merge; 933 } 934 prec = kk - decpt; 935 goto f_merge; 936 } 937 938 case '%': 939 buf[0] = (char)fcode; 940 goto c_merge; 941 942 case 'c': 943 buf[0] = va_arg(args.ap, int); 944 c_merge: 945 p = (bp = &buf[0]) + 1; 946 break; 947 948 case 's': 949 bp = va_arg(args.ap, char *); 950 if (!(flagword & DOTSEEN)) 951 p = bp + strlen(bp); 952 else { /* a strnlen function would be useful here! */ 953 char *qp = bp; 954 while (*qp++ != '\0' && --prec >= 0) 955 ; 956 p = qp - 1; 957 } 958 break; 959 960 case 'n': 961 { 962 if (flagword & LENGTH) { 963 long *svcount; 964 svcount = va_arg(args.ap, long *); 965 *svcount = count; 966 } else if (flagword & SHORT) { 967 short *svcount; 968 svcount = va_arg(args.ap, short *); 969 *svcount = (short)count; 970 } else { 971 int *svcount; 972 svcount = va_arg(args.ap, int *); 973 *svcount = count; 974 } 975 continue; 976 } 977 978 default: /* this is technically an error; what we do is to */ 979 /* back up the format pointer to the offending char */ 980 /* and continue with the format scan */ 981 format--; 982 continue; 983 984 } 985 986 if (inf_nan) { 987 if (neg_in) { 988 prefix = "-"; 989 prefixlength = 1; 990 neg_in = 0; 991 } else if (flagword & FPLUS) { 992 prefix = "+"; 993 prefixlength = 1; 994 } else if (flagword & FBLANK) { 995 prefix = " "; 996 prefixlength = 1; 997 } 998 inf_nan = 0; 999 } 1000 1001 /* Calculate number of padding blanks */ 1002 k = (int)(pdiff = p - bp) + prefixlength + otherlength + 1003 NaN_flg; 1004 if (width <= k) 1005 count += k; 1006 else { 1007 count += width; 1008 1009 /* Set up for padding zeroes if requested */ 1010 /* Otherwise emit padding blanks unless output is */ 1011 /* to be left-justified. */ 1012 1013 if (flagword & PADZERO) { 1014 if (!(flagword & LZERO)) { 1015 flagword |= LZERO; 1016 lzero = width - k; 1017 } 1018 else 1019 lzero += width - k; 1020 k = width; /* cancel padding blanks */ 1021 } else 1022 /* Blanks on left if required */ 1023 if (!(flagword & FMINUS)) 1024 PAD(_blanks, width - k); 1025 } 1026 1027 /* Prefix, if any */ 1028 if (prefixlength != 0) 1029 PUT(prefix, prefixlength); 1030 1031 /* If value is NaN, put string NaN */ 1032 if (NaN_flg) { 1033 PUT(SNAN, SNLEN); 1034 NaN_flg = 0; 1035 } 1036 1037 /* Zeroes on the left */ 1038 if (flagword & LZERO) 1039 PAD(_zeroes, lzero); 1040 1041 /* The value itself */ 1042 if (pdiff > 0) 1043 PUT(bp, pdiff); 1044 1045 if (flagword & (RZERO | SUFFIX | FMINUS)) { 1046 /* Zeroes on the right */ 1047 if (flagword & RZERO) 1048 PAD(_zeroes, rzero); 1049 1050 /* The suffix */ 1051 if (flagword & SUFFIX) 1052 PUT(suffix, suffixlength); 1053 1054 /* Blanks on the right if required */ 1055 if (flagword & FMINUS && width > k) 1056 PAD(_blanks, width - k); 1057 } 1058 } 1059 } 1060 1061 /* 1062 * This function initializes arglst, to contain the appropriate va_list values 1063 * for the first MAXARGS arguments. 1064 */ 1065 void 1066 _mkarglst(char *fmt, stva_list args, stva_list arglst[]) 1067 { 1068 static char digits[] = "01234567890", skips[] = "# +-.0123456789hL$"; 1069 1070 enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR, 1071 LONG_PTR, INT_PTR}; 1072 enum types typelst[MAXARGS], curtype; 1073 int maxnum, n, curargno, flags; 1074 1075 /* 1076 * Algorithm 1. set all argument types to zero. 1077 * 2. walk through fmt putting arg types in typelst[]. 1078 * 3. walk through args using va_arg(args.ap, typelst[n]) 1079 * and set arglst[] to the appropriate values. 1080 * Assumptions: Cannot use %*$... to specify variable position. 1081 */ 1082 1083 (void) memset((void *)typelst, 0, sizeof (typelst)); 1084 maxnum = -1; 1085 curargno = 0; 1086 while ((fmt = strchr(fmt, '%')) != 0) { 1087 size_t sz; 1088 1089 fmt++; /* skip % */ 1090 if (fmt[sz = strspn(fmt, digits)] == '$') { 1091 curargno = atoi(fmt) - 1; 1092 /* convert to zero base */ 1093 if (curargno < 0) 1094 continue; 1095 fmt += sz + 1; 1096 } 1097 flags = 0; 1098 again:; 1099 fmt += strspn(fmt, skips); 1100 switch (*fmt++) { 1101 case '%': /* there is no argument! */ 1102 continue; 1103 case 'l': 1104 flags |= 0x1; 1105 goto again; 1106 case '*': /* int argument used for value */ 1107 /* check if there is a positional parameter */ 1108 if (isdigit(*fmt)) { 1109 int targno; 1110 targno = atoi(fmt) - 1; 1111 fmt += strspn(fmt, digits); 1112 if (*fmt == '$') 1113 fmt++; /* skip '$' */ 1114 if (targno >= 0 && targno < MAXARGS) { 1115 typelst[targno] = INT; 1116 if (maxnum < targno) 1117 maxnum = targno; 1118 } 1119 goto again; 1120 } 1121 flags |= 0x2; 1122 curtype = INT; 1123 break; 1124 case 'e': 1125 case 'E': 1126 case 'f': 1127 case 'g': 1128 case 'G': 1129 curtype = DOUBLE; 1130 break; 1131 case 's': 1132 curtype = CHAR_PTR; 1133 break; 1134 case 'p': 1135 curtype = VOID_PTR; 1136 break; 1137 case 'n': 1138 if (flags & 0x1) 1139 curtype = LONG_PTR; 1140 else 1141 curtype = INT_PTR; 1142 break; 1143 default: 1144 if (flags & 0x1) 1145 curtype = LONG; 1146 else 1147 curtype = INT; 1148 break; 1149 } 1150 if (curargno >= 0 && curargno < MAXARGS) { 1151 typelst[curargno] = curtype; 1152 if (maxnum < curargno) 1153 maxnum = curargno; 1154 } 1155 curargno++; /* default to next in list */ 1156 if (flags & 0x2) /* took care of *, keep going */ 1157 { 1158 flags ^= 0x2; 1159 goto again; 1160 } 1161 } 1162 for (n = 0; n <= maxnum; n++) { 1163 arglst[n] = args; 1164 if (typelst[n] == 0) 1165 typelst[n] = INT; 1166 1167 switch (typelst[n]) { 1168 case INT: 1169 (void) va_arg(args.ap, int); 1170 break; 1171 case LONG: 1172 (void) va_arg(args.ap, long); 1173 break; 1174 case CHAR_PTR: 1175 (void) va_arg(args.ap, char *); 1176 break; 1177 case DOUBLE: 1178 (void) va_arg(args.ap, double); 1179 break; 1180 case LONG_DOUBLE: 1181 (void) va_arg(args.ap, double); 1182 break; 1183 case VOID_PTR: 1184 (void) va_arg(args.ap, void *); 1185 break; 1186 case LONG_PTR: 1187 (void) va_arg(args.ap, long *); 1188 break; 1189 case INT_PTR: 1190 (void) va_arg(args.ap, int *); 1191 break; 1192 } 1193 } 1194 } 1195 1196 /* 1197 * This function is used to find the va_list value for arguments whose 1198 * position is greater than MAXARGS. This function is slow, so hopefully 1199 * MAXARGS will be big enough so that this function need only be called in 1200 * unusual circumstances. 1201 * pargs is assumed to contain the value of arglst[MAXARGS - 1]. 1202 */ 1203 void 1204 _getarg(char *fmt, stva_list *pargs, int argno) 1205 { 1206 static char digits[] = "01234567890", skips[] = "# +-.0123456789h$"; 1207 int i, curargno, flags; 1208 size_t n; 1209 char *sfmt = fmt; 1210 int found = 1; 1211 1212 i = MAXARGS; 1213 curargno = 1; 1214 while (found) { 1215 fmt = sfmt; 1216 found = 0; 1217 while ((i != argno) && (fmt = strchr(fmt, '%')) != 0) { 1218 fmt++; /* skip % */ 1219 if (fmt[n = strspn(fmt, digits)] == '$') { 1220 curargno = atoi(fmt); 1221 if (curargno <= 0) 1222 continue; 1223 fmt += n + 1; 1224 } 1225 1226 /* find conversion specifier for next argument */ 1227 if (i != curargno) { 1228 curargno++; 1229 continue; 1230 } else 1231 found = 1; 1232 flags = 0; 1233 again:; 1234 fmt += strspn(fmt, skips); 1235 switch (*fmt++) { 1236 case '%': /* there is no argument! */ 1237 continue; 1238 case 'l': 1239 flags |= 0x1; 1240 goto again; 1241 case '*': /* int argument used for value */ 1242 /* 1243 * check if there is a positional parameter; 1244 * if so, just skip it; its size will be 1245 * correctly determined by default 1246 */ 1247 if (isdigit(*fmt)) { 1248 fmt += strspn(fmt, digits); 1249 if (*fmt == '$') 1250 fmt++; /* skip '$' */ 1251 goto again; 1252 } 1253 flags |= 0x2; 1254 (void) va_arg((*pargs).ap, int); 1255 break; 1256 case 'e': 1257 case 'E': 1258 case 'f': 1259 case 'g': 1260 case 'G': 1261 if (flags & 0x1) 1262 (void) va_arg((*pargs).ap, double); 1263 else 1264 (void) va_arg((*pargs).ap, double); 1265 break; 1266 case 's': 1267 (void) va_arg((*pargs).ap, char *); 1268 break; 1269 case 'p': 1270 (void) va_arg((*pargs).ap, void *); 1271 break; 1272 case 'n': 1273 if (flags & 0x1) 1274 (void) va_arg((*pargs).ap, long *); 1275 else 1276 (void) va_arg((*pargs).ap, int *); 1277 break; 1278 default: 1279 if (flags & 0x1) 1280 (void) va_arg((*pargs).ap, long int); 1281 else 1282 (void) va_arg((*pargs).ap, int); 1283 break; 1284 } 1285 i++; 1286 curargno++; /* default to next in list */ 1287 if (flags & 0x2) /* took care of *, keep going */ 1288 { 1289 flags ^= 0x2; 1290 goto again; 1291 } 1292 } 1293 1294 /* 1295 * missing specifier for parameter, assume parameter is an int 1296 */ 1297 if (!found && i != argno) { 1298 (void) va_arg((*pargs).ap, int); 1299 i++; 1300 curargno = i; 1301 found = 1; 1302 } 1303 } 1304 } 1305