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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * University Copyright- Copyright (c) 1982, 1986, 1988 33 * The Regents of the University of California 34 * All Rights Reserved 35 * 36 * University Acknowledgment- Portions of this document are derived from 37 * software developed by the University of California, Berkeley, and its 38 * contributors. 39 */ 40 41 #pragma ident "%Z%%M% %I% %E% SMI" 42 43 /*LINTLIBRARY*/ 44 45 /* 46 * _doprnt: common code for printf, fprintf, sprintf 47 */ 48 49 #include "../../../lib/common/inc/c_synonyms.h" 50 #include <sys/types.h> 51 #include "file64.h" 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <ctype.h> 55 #include <stdarg.h> 56 #include <values.h> 57 #include <nan.h> 58 #include <memory.h> 59 #include <string.h> 60 #include "print.h" /* parameters & macros for doprnt */ 61 #include "stdiom.h" 62 #include <locale.h> 63 #include <stddef.h> 64 #include "_locale.h" 65 #include "libc.h" 66 67 #define PUT(p, n) { unsigned char *newbufptr; \ 68 if ((newbufptr = bufptr + (n)) > bufferend) { \ 69 _dowrite((p), (n), iop, &bufptr); \ 70 } else { \ 71 (void) memcpy(bufptr, (p), (n)); \ 72 bufptr = newbufptr; \ 73 } \ 74 } 75 #define PAD(s, n) { int nn; \ 76 for (nn = (n); nn > 20; nn -= 20) \ 77 _dowrite((s), 20, iop, &bufptr); \ 78 PUT((s), nn); \ 79 } 80 81 #define SNLEN 5 /* Length of string used when printing a NaN */ 82 83 /* bit positions for flags used in doprnt */ 84 85 #define LENGTH 1 /* l */ 86 #define FPLUS 2 /* + */ 87 #define FMINUS 4 /* - */ 88 #define FBLANK 8 /* blank */ 89 #define FSHARP 16 /* # */ 90 #define PADZERO 32 /* padding zeroes requested via '0' */ 91 #define DOTSEEN 64 /* dot appeared in format specification */ 92 #define SUFFIX 128 /* a suffix is to appear in the output */ 93 #define RZERO 256 /* there will be trailing zeros in output */ 94 #define LZERO 512 /* there will be leading zeroes in output */ 95 #define SHORT 1024 /* h */ 96 97 /* 98 * Positional Parameter information 99 */ 100 #define MAXARGS 30 /* max. number of args for fast positional paramters */ 101 102 /* 103 * stva_list is used to subvert C's restriction that a variable with an 104 * array type can not appear on the left hand side of an assignment operator. 105 * By putting the array inside a structure, the functionality of assigning to 106 * the whole array through a simple assignment is achieved.. 107 */ 108 typedef struct stva_list { 109 va_list ap; 110 } stva_list; 111 112 static char _blanks[] = " "; 113 static char _zeroes[] = "00000000000000000000"; 114 static char uc_digs[] = "0123456789ABCDEF"; 115 static char lc_digs[] = "0123456789abcdef"; 116 static char lc_nan[] = "nan0x"; 117 static char uc_nan[] = "NAN0X"; 118 static char lc_inf[] = "inf"; 119 static char uc_inf[] = "INF"; 120 121 /* 122 * forward declarations 123 */ 124 void _mkarglst(char *, stva_list, stva_list []); 125 void _getarg(char *, stva_list *, int); 126 static int _lowdigit(long *); 127 static void _dowrite(char *, ssize_t, FILE *, unsigned char **); 128 129 static int 130 _lowdigit(long *valptr) 131 { /* This function computes the decimal low-order digit of the number */ 132 /* pointed to by valptr, and returns this digit after dividing */ 133 /* *valptr by ten. This function is called ONLY to compute the */ 134 /* low-order digit of a long whose high-order bit is set. */ 135 136 int lowbit = (int)(*valptr & 1); 137 long value = (*valptr >> 1) & ~HIBITL; 138 139 *valptr = value / 5; 140 return ((int)(value % 5 * 2 + lowbit + '0')); 141 } 142 143 /* The function _dowrite carries out buffer pointer bookkeeping surrounding */ 144 /* a call to fwrite. It is called only when the end of the file output */ 145 /* buffer is approached or in other unusual situations. */ 146 static void 147 _dowrite(char *p, ssize_t n, FILE *iop, unsigned char **ptrptr) 148 { 149 if (!(iop->_flag & _IOREAD)) { 150 iop->_cnt -= (*ptrptr - iop->_ptr); 151 iop->_ptr = *ptrptr; 152 _bufsync(iop, _bufend(iop)); 153 (void) fwrite(p, 1, n, iop); 154 *ptrptr = iop->_ptr; 155 } else 156 *ptrptr = (unsigned char *) memcpy(*ptrptr, p, n) + n; 157 } 158 159 int 160 _doprnt(char *format, va_list in_args, FILE *iop) 161 { 162 163 /* bufptr is used inside of doprnt instead of iop->_ptr; */ 164 /* bufferend is a copy of _bufend(iop), if it exists. For */ 165 /* dummy file descriptors (iop->_flag & _IOREAD), bufferend */ 166 /* may be meaningless. Dummy file descriptors are used so that */ 167 /* sprintf and vsprintf may share the _doprnt routine with the */ 168 /* rest of the printf family. */ 169 170 unsigned char *bufptr; 171 unsigned char *bufferend; 172 173 /* This variable counts output characters. */ 174 int count = 0; 175 176 /* Starting and ending points for value to be printed */ 177 char *bp; 178 char *p; 179 180 /* Field width and precision */ 181 int width, prec; 182 183 /* Format code */ 184 int fcode; 185 186 /* Number of padding zeroes required on the left and right */ 187 int lzero, rzero; 188 189 /* Flags - bit positions defined by LENGTH, FPLUS, FMINUS, FBLANK, */ 190 /* and FSHARP are set if corresponding character is in format */ 191 /* Bit position defined by PADZERO means extra space in the field */ 192 /* should be padded with leading zeroes rather than with blanks */ 193 int flagword; 194 195 /* Values are developed in this buffer */ 196 char buf[max(MAXDIGS, 1+max(MAXFCVT+MAXEXP, MAXECVT))]; 197 198 /* Pointer to sign, "0x", "0X", or empty */ 199 char *prefix; 200 201 /* Exponent or empty */ 202 char *suffix; 203 204 /* Buffer to create exponent */ 205 char expbuf[MAXESIZ + 1]; 206 207 /* Length of prefix and of suffix */ 208 int prefixlength, suffixlength; 209 210 /* Combined length of leading zeroes, trailing zeroes, and suffix */ 211 int otherlength; 212 213 /* The value being converted, if integer */ 214 long val; 215 216 /* The value being converted, if real */ 217 double dval; 218 219 /* Output values from fcvt and ecvt */ 220 int decpt, sign; 221 222 /* Pointer to a translate table for digits of whatever radix */ 223 char *tab; 224 225 /* Work variables */ 226 int k, lradix, mradix; 227 228 /* Variables used to flag an infinities and nans, resp. */ 229 /* Nan_flg is used with two purposes: to flag a NaN and */ 230 /* as the length of the string ``NAN0X'' (``nan0x'') */ 231 int inf_nan = 0, NaN_flg = 0; 232 233 /* Pointer to string "NAN0X" or "nan0x" */ 234 char *SNAN; 235 236 /* Flag for negative infinity or NaN */ 237 int neg_in = 0; 238 239 /* variables for positional parameters */ 240 char *sformat = format; /* save the beginning of the format */ 241 int fpos = 1; /* 1 if first positional parameter */ 242 stva_list args; /* used to step through the argument list */ 243 stva_list sargs; 244 /* used to save the start of the argument list */ 245 stva_list bargs; 246 /* used to restore args if positional width or precision */ 247 stva_list arglst[MAXARGS]; 248 /* 249 * array giving the appropriate values for va_arg() to 250 * retrieve the corresponding argument: 251 * arglst[0] is the first argument, 252 * arglst[1] is the second argument, etc. 253 */ 254 int starflg = 0; /* set to 1 if * format specifier seen */ 255 /* 256 * Initialize args and sargs to the start of the argument list. 257 * Note that ANSI guarantees that the address of the first member of 258 * a structure will be the same as the address of the structure. 259 * See equivalent code in libc doprnt.c 260 */ 261 262 #if !(defined(__amd64) && defined(__GNUC__)) /* XX64 - fix me */ 263 va_copy(args.ap, in_args); 264 #endif 265 sargs = args; 266 267 /* if first I/O to the stream get a buffer */ 268 /* Note that iop->_base should not equal 0 for sprintf and vsprintf */ 269 if (iop->_base == 0 && _findbuf(iop) == 0) 270 return (EOF); 271 272 /* initialize buffer pointer and buffer end pointer */ 273 bufptr = iop->_ptr; 274 bufferend = (iop->_flag & _IOREAD) ? 275 (unsigned char *)((long)bufptr | (-1L & ~HIBITL)) 276 : _bufend(iop); 277 278 /* 279 * The main loop -- this loop goes through one iteration 280 * for each string of ordinary characters or format specification. 281 */ 282 for (;;) { 283 ptrdiff_t pdiff; 284 285 if ((fcode = *format) != '\0' && fcode != '%') { 286 bp = format; 287 do { 288 format++; 289 } while ((fcode = *format) != '\0' && fcode != '%'); 290 291 pdiff = format - bp; 292 /* pdiff = no. of non-% chars */ 293 count += pdiff; 294 PUT(bp, pdiff); 295 } 296 if (fcode == '\0') { /* end of format; return */ 297 ptrdiff_t d = bufptr - iop->_ptr; 298 iop->_cnt -= d; 299 iop->_ptr = bufptr; 300 if (bufptr + iop->_cnt > bufferend && 301 !(iop->_flag & _IOREAD)) 302 _bufsync(iop, bufferend); 303 /* 304 * in case of interrupt during last 305 * several lines 306 */ 307 if (iop->_flag & (_IONBF | _IOLBF) && 308 (iop->_flag & _IONBF || 309 memchr((char *)(bufptr-count), '\n', count) != 310 NULL)) 311 (void) _xflsbuf(iop); 312 return (ferror(iop) ? EOF : count); 313 } 314 315 /* 316 * % has been found. 317 * The following switch is used to parse the format 318 * specification and to perform the operation specified 319 * by the format letter. The program repeatedly goes 320 * back to this switch until the format letter is 321 * encountered. 322 */ 323 width = prefixlength = otherlength = flagword = 324 suffixlength = 0; 325 format++; 326 327 charswitch: 328 329 switch (fcode = *format++) { 330 331 case '+': 332 flagword |= FPLUS; 333 goto charswitch; 334 case '-': 335 flagword |= FMINUS; 336 flagword &= ~PADZERO; /* ignore 0 flag */ 337 goto charswitch; 338 case ' ': 339 flagword |= FBLANK; 340 goto charswitch; 341 case '#': 342 flagword |= FSHARP; 343 goto charswitch; 344 345 /* Scan the field width and precision */ 346 case '.': 347 flagword |= DOTSEEN; 348 prec = 0; 349 goto charswitch; 350 351 case '*': 352 if (isdigit(*format)) { 353 starflg = 1; 354 bargs = args; 355 goto charswitch; 356 } 357 if (!(flagword & DOTSEEN)) { 358 width = va_arg(args.ap, int); 359 if (width < 0) { 360 width = -width; 361 flagword ^= FMINUS; 362 } 363 } else { 364 prec = va_arg(args.ap, int); 365 if (prec < 0) 366 prec = 0; 367 } 368 goto charswitch; 369 370 case '$': 371 { 372 int position; 373 stva_list targs; 374 if (fpos) { 375 _mkarglst(sformat, sargs, arglst); 376 fpos = 0; 377 } 378 if (flagword & DOTSEEN) { 379 position = prec; 380 prec = 0; 381 } else { 382 position = width; 383 width = 0; 384 } 385 if (position <= 0) { 386 /* illegal position */ 387 format--; 388 continue; 389 } 390 if (position <= MAXARGS) { 391 targs = arglst[position - 1]; 392 } else { 393 targs = arglst[MAXARGS - 1]; 394 _getarg(sformat, &targs, position); 395 } 396 if (!starflg) 397 args = targs; 398 else { 399 starflg = 0; 400 args = bargs; 401 if (flagword & DOTSEEN) 402 prec = va_arg(targs.ap, int); 403 else 404 width = va_arg(targs.ap, int); 405 } 406 goto charswitch; 407 } 408 409 case '0': /* obsolescent spec: leading zero in width */ 410 /* means pad with leading zeros */ 411 if (!(flagword & (DOTSEEN | FMINUS))) 412 flagword |= PADZERO; 413 /* FALLTHROUGH */ 414 case '1': 415 case '2': 416 case '3': 417 case '4': 418 case '5': 419 case '6': 420 case '7': 421 case '8': 422 case '9': 423 { int num = fcode - '0'; 424 while (isdigit(fcode = *format)) { 425 num = num * 10 + fcode - '0'; 426 format++; 427 } 428 if (flagword & DOTSEEN) 429 prec = num; 430 else 431 width = num; 432 goto charswitch; 433 } 434 435 /* Scan the length modifier */ 436 case 'l': 437 flagword |= LENGTH; 438 goto charswitch; 439 case 'h': 440 flagword |= SHORT; 441 goto charswitch; 442 case 'L': 443 goto charswitch; 444 445 /* 446 * The character addressed by format must be 447 * the format letter -- there is nothing 448 * left for it to be. 449 * 450 * The status of the +, -, #, and blank 451 * flags are reflected in the variable 452 * "flagword". "width" and "prec" contain 453 * numbers corresponding to the digit 454 * strings before and after the decimal 455 * point, respectively. If there was no 456 * decimal point, then flagword & DOTSEEN 457 * is false and the value of prec is meaningless. 458 * 459 * The following switch cases set things up 460 * for printing. What ultimately gets 461 * printed will be padding blanks, a 462 * prefix, left padding zeroes, a value, 463 * right padding zeroes, a suffix, and 464 * more padding blanks. Padding blanks 465 * will not appear simultaneously on both 466 * the left and the right. Each case in 467 * this switch will compute the value, and 468 * leave in several variables the informa- 469 * tion necessary to construct what is to 470 * be printed. 471 * 472 * The prefix is a sign, a blank, "0x", 473 * "0X", or null, and is addressed by 474 * "prefix". 475 * 476 * The suffix is either null or an 477 * exponent, and is addressed by "suffix". 478 * If there is a suffix, the flagword bit 479 * SUFFIX will be set. 480 * 481 * The value to be printed starts at "bp" 482 * and continues up to and not including 483 * "p". 484 * 485 * "lzero" and "rzero" will contain the 486 * number of padding zeroes required on 487 * the left and right, respectively. 488 * The flagword bits LZERO and RZERO tell 489 * whether padding zeros are required. 490 * 491 * The number of padding blanks, and 492 * whether they go on the left or the 493 * right, will be computed on exit from 494 * the switch. 495 */ 496 497 498 499 500 /* 501 * decimal fixed point representations 502 * 503 * HIBITL is 100...000 504 * binary, and is equal to the maximum 505 * negative number. 506 * We assume a 2's complement machine 507 */ 508 509 case 'i': 510 case 'd': 511 /* Fetch the argument to be printed */ 512 if (flagword & LENGTH) 513 val = va_arg(args.ap, long); 514 else 515 val = va_arg(args.ap, int); 516 517 if (flagword & SHORT) 518 val = (short)val; 519 520 /* Set buffer pointer to last digit */ 521 p = bp = buf + MAXDIGS; 522 523 /* If signed conversion, make sign */ 524 if (val < 0) { 525 prefix = "-"; 526 prefixlength = 1; 527 /* 528 * Negate, checking in 529 * advance for possible 530 * overflow. 531 */ 532 if (val != HIBITL) 533 val = -val; 534 else /* number is -HIBITL; convert last */ 535 /* digit now and get positive number */ 536 *--bp = _lowdigit(&val); 537 } else if (flagword & FPLUS) { 538 prefix = "+"; 539 prefixlength = 1; 540 } else if (flagword & FBLANK) { 541 prefix = " "; 542 prefixlength = 1; 543 } 544 545 decimal: 546 { long qval = val; 547 long saveq; 548 549 if (qval <= 9) { 550 if (qval != 0 || !(flagword & DOTSEEN)) 551 *--bp = (char)(qval + '0'); 552 } else { 553 do { 554 saveq = qval; 555 qval /= 10; 556 *--bp = (char)(saveq - 557 qval * 10 + '0'); 558 } while (qval > 9); 559 *--bp = (char)(qval + '0'); 560 pdiff = (ptrdiff_t)saveq; 561 } 562 } 563 564 /* Calculate minimum padding zero requirement */ 565 if (flagword & DOTSEEN) { 566 int leadzeroes = prec - (int)(p - bp); 567 if (leadzeroes > 0) { 568 otherlength = lzero = leadzeroes; 569 flagword |= LZERO; 570 } 571 } 572 573 break; 574 575 case 'u': 576 /* Fetch the argument to be printed */ 577 if (flagword & LENGTH) 578 val = va_arg(args.ap, long); 579 else 580 val = va_arg(args.ap, unsigned); 581 582 if (flagword & SHORT) 583 val = (unsigned short)val; 584 585 p = bp = buf + MAXDIGS; 586 587 if (val & HIBITL) 588 *--bp = _lowdigit(&val); 589 590 goto decimal; 591 592 /* 593 * non-decimal fixed point representations 594 * for radix equal to a power of two 595 * 596 * "mradix" is one less than the radix for the conversion. 597 * "lradix" is one less than the base 2 log 598 * of the radix for the conversion. Conversion is unsigned. 599 * HIBITL is 100...000 600 * binary, and is equal to the maximum 601 * negative number. 602 * We assume a 2's complement machine 603 */ 604 605 case 'o': 606 mradix = 7; 607 lradix = 2; 608 goto fixed; 609 610 case 'X': 611 case 'x': 612 case 'p': 613 mradix = 15; 614 lradix = 3; 615 616 fixed: 617 /* Fetch the argument to be printed */ 618 if (flagword & LENGTH) 619 val = va_arg(args.ap, long); 620 else 621 val = va_arg(args.ap, unsigned); 622 623 if (flagword & SHORT) 624 val = (unsigned short)val; 625 626 /* Set translate table for digits */ 627 tab = (fcode == 'X') ? uc_digs : lc_digs; 628 629 /* Entry point when printing a double which is a NaN */ 630 put_pc: 631 /* Develop the digits of the value */ 632 p = bp = buf + MAXDIGS; 633 { long qval = val; 634 if (qval == 0) { 635 if (!(flagword & DOTSEEN)) { 636 otherlength = lzero = 1; 637 flagword |= LZERO; 638 } 639 } else 640 do { 641 *--bp = tab[qval & mradix]; 642 qval = ((qval >> 1) & ~HIBITL) 643 >> lradix; 644 } while (qval != 0); 645 } 646 647 /* Calculate minimum padding zero requirement */ 648 if (flagword & DOTSEEN) { 649 int leadzeroes = prec - (int)(p - bp); 650 if (leadzeroes > 0) { 651 otherlength = lzero = leadzeroes; 652 flagword |= LZERO; 653 } 654 } 655 656 /* Handle the # flag */ 657 if (flagword & FSHARP && val != 0) 658 switch (fcode) { 659 case 'o': 660 if (!(flagword & LZERO)) { 661 otherlength = lzero = 1; 662 flagword |= LZERO; 663 } 664 break; 665 case 'x': 666 prefix = "0x"; 667 prefixlength = 2; 668 break; 669 case 'X': 670 prefix = "0X"; 671 prefixlength = 2; 672 break; 673 } 674 675 break; 676 677 case 'E': 678 case 'e': 679 /* 680 * E-format. The general strategy 681 * here is fairly easy: we take 682 * what ecvt gives us and re-format it. 683 */ 684 685 /* Establish default precision */ 686 if (!(flagword & DOTSEEN)) 687 prec = 6; 688 689 /* Fetch the value */ 690 dval = va_arg(args.ap, double); 691 692 /* Check for NaNs and Infinities */ 693 if (IsNANorINF(dval)) { 694 if (IsINF(dval)) { 695 if (IsNegNAN(dval)) 696 neg_in = 1; 697 inf_nan = 1; 698 bp = (fcode == 'E')? uc_inf: lc_inf; 699 p = bp + 3; 700 break; 701 } else { 702 if (IsNegNAN(dval)) 703 neg_in = 1; 704 inf_nan = 1; 705 val = GETNaNPC(dval); 706 NaN_flg = SNLEN; 707 mradix = 15; 708 lradix = 3; 709 if (fcode == 'E') { 710 SNAN = uc_nan; 711 tab = uc_digs; 712 } else { 713 SNAN = lc_nan; 714 tab = lc_digs; 715 } 716 goto put_pc; 717 } 718 } 719 /* Develop the mantissa */ 720 bp = ecvt(dval, min(prec + 1, MAXECVT), &decpt, &sign); 721 722 /* Determine the prefix */ 723 e_merge: 724 if (sign) { 725 prefix = "-"; 726 prefixlength = 1; 727 } else if (flagword & FPLUS) { 728 prefix = "+"; 729 prefixlength = 1; 730 } else if (flagword & FBLANK) { 731 prefix = " "; 732 prefixlength = 1; 733 } 734 735 /* Place the first digit in the buffer */ 736 p = &buf[0]; 737 *p++ = (*bp != '\0') ? *bp++ : '0'; 738 739 /* Put in a decimal point if needed */ 740 if (prec != 0 || (flagword & FSHARP)) 741 *p++ = _numeric[0]; 742 743 /* Create the rest of the mantissa */ 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