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