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