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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * _doprnt: common code for printf, fprintf, sprintf 34 * Floating-point code is included or not, depending 35 * on whether the preprocessor variable FLOAT is 1 or 0. 36 */ 37 #define MAXARGS 50 38 #ifndef FLOAT 39 #define FLOAT 1 /* YES! we want floating */ 40 #endif 41 42 #include <stdio.h> 43 #include <ctype.h> 44 #include <stdarg.h> 45 #include <values.h> 46 #include <locale.h> 47 #include "doprnt.h" 48 #include "stdiom.h" 49 #include <string.h> /* strchr, strlen, strspn */ 50 51 #define max(a,b) ((a) > (b) ? (a) : (b)) 52 #define min(a,b) ((a) < (b) ? (a) : (b)) 53 54 /* If this symbol is nonzero, allow '0' as a flag */ 55 /* If this symbol is nonzero, allow '0' as a flag */ 56 #define FZERO 1 57 58 #if FLOAT 59 /* 60 * libc/gen/common functions for floating-point conversion 61 */ 62 #include <floatingpoint.h> 63 extern void _fourdigitsquick(); 64 #endif 65 66 #define emitchar(c) { if (--filecnt < 0) { \ 67 FILE *iop = file; \ 68 if (((iop->_flag & (_IOLBF|_IONBF)) == 0 \ 69 || -filecnt >= iop->_bufsiz)) { \ 70 iop->_ptr = fileptr; \ 71 if (iop->_flag & _IOSTRG) \ 72 return iop->_ptr - iop->_base; \ 73 else \ 74 (void) _xflsbuf(iop); \ 75 fileptr = iop->_ptr; \ 76 filecnt = iop->_cnt; \ 77 filecnt--; \ 78 } \ 79 } \ 80 *fileptr++ = (unsigned)(c); \ 81 count++; \ 82 } 83 84 static char *nullstr = "(null)"; 85 static char *lowerhex = "0123456789abcdef"; 86 static char *upperhex = "0123456789ABCDEF"; 87 88 /* stva_list is used to subvert C's restriction that a variable with an 89 * array type can not appear on the left hand side of an assignment operator. 90 * By putting the array inside a structure, the functionality of assigning to 91 * the whole array through a simple assignment is achieved.. 92 */ 93 typedef struct stva_list { 94 va_list ap; 95 } stva_list; 96 97 void _mkarglst(char *, stva_list, stva_list []); 98 void _getarg(char *, stva_list *, int); 99 static char *_check_dol(char *, int *); 100 101 int 102 _doprnt(char *format, va_list in_args, FILE *file) 103 { 104 char convertbuffer[1024] ; 105 106 /* Current position in format */ 107 char *cp; 108 109 /* Starting and ending points for value to be printed */ 110 char *bp; 111 char *p; 112 113 /* Pointer and count for I/O buffer */ 114 unsigned char *fileptr; 115 int filecnt; 116 117 /* Field width and precision */ 118 int width; 119 int prec; 120 121 /* Format code */ 122 char fcode; 123 124 /* Number of padding zeroes required on the left */ 125 int lzero; 126 127 /* Flags - nonzero if corresponding character appears in format */ 128 bool fplus; /* + */ 129 bool fminus; /* - */ 130 bool fblank; /* blank */ 131 bool fsharp; /* # */ 132 #if FZERO 133 bool ansi_fzero; /* 0 for ansi-dictated formats */ 134 bool compat_fzero; /* 0 for backward compatibility */ 135 #endif 136 bool Lsize; /* Capital L for size = long double = quadruple */ 137 138 /* Pointer to sign, "0x", "0X", or empty */ 139 char *prefix; 140 141 /* Scratch */ 142 int nblank; 143 144 #if FLOAT 145 /* Exponent or empty */ 146 char *suffix; 147 148 /* Buffer to create exponent */ 149 char expbuf[7]; /* "e+xxxx\0" */ 150 151 /* Number of padding zeroes required on the right */ 152 int rzero; 153 154 /* Length of exponent suffix. */ 155 int suffixlength; 156 157 /* The value being converted, if real or quadruple */ 158 double dval; 159 quadruple qval; 160 161 /* Output values from fconvert and econvert */ 162 int decpt, sign; 163 164 /* Values are developed in this buffer */ 165 char buf[1034]; /* Size of convertbuffer, plus some for exponent and sign. */ 166 167 /* Current locale's decimal point */ 168 char decpt_char = *(localeconv()->decimal_point); 169 170 #else 171 /* Values are developed in this buffer */ 172 char buf[MAXDIGS]; 173 #endif 174 175 176 /* The value being converted, if integer */ 177 unsigned long val; 178 179 /* Work variables */ 180 int n; 181 char c; 182 char radix; 183 int svswitch = 0; 184 /* count of output characters */ 185 int count; 186 187 /* variables for positional parameters */ 188 char *sformat = format; /* save the beginning of the format */ 189 int fpos = 1; /* 1 if first positional parameter */ 190 stva_list args, /* used to step through the argument list */ 191 args_width, /* for width */ 192 args_prec, /* for prec */ 193 sargs; /* used to save the start of the argument list */ 194 stva_list arglst[MAXARGS];/* array giving the approriate values 195 * for va_arg() to retrieve the 196 * corresponding argument: 197 * arglst[0] is the first argument 198 * arglst[1] is the second argument, etc. 199 */ 200 int index = 0; /* argument placeolder */ 201 /* Initialize args and sargs to the start of the argument list. 202 * Note that ANSI guarantees that the address of the first member of 203 * a structure will be the same as the address of the structure. */ 204 args_width = args_prec = args = sargs = *(struct stva_list *)&in_args; 205 206 207 /* initialize p an bp (starting and ending points) bugid 1141781 */ 208 209 p = bp = NULL; 210 211 cp = format; 212 if ((c = *cp++) != '\0') { 213 /* 214 * We know we're going to write something; make sure 215 * we can write and set up buffers, etc.. 216 */ 217 if (_WRTCHK(file)) 218 return(EOF); 219 } else 220 return(0); /* no fault, no error */ 221 222 count = 0; 223 fileptr = file->_ptr; 224 filecnt = file->_cnt; 225 226 /* 227 * The main loop -- this loop goes through one iteration 228 * for each ordinary character or format specification. 229 */ 230 do { 231 if (c != '%') { 232 /* Ordinary (non-%) character */ 233 emitchar(c); 234 } else { 235 /* 236 * % has been spotted! 237 * 238 * First, try the 99% cases. 239 * then parse the format specification. 240 * 241 * Note that this code assumes the Sun 242 * Workstation environment (all params 243 * passed as int == long, no interrupts 244 * for fixed point overflow from negating 245 * the most negative number). 246 */ 247 skipit: 248 switch(c = *cp++) { 249 250 case 'l': 251 case 'h': 252 /* Quickly ignore long & short specifiers */ 253 goto skipit; 254 255 case 's': 256 bp = va_arg(args.ap, char *); 257 if (bp == NULL) 258 bp = nullstr; 259 while (c = *bp++) 260 emitchar(c); 261 p = bp; 262 continue; 263 264 case 'c': 265 c = va_arg(args.ap, int); 266 emitc: 267 emitchar(c); 268 continue; 269 270 case 'i': 271 case 'd': 272 case 'D': 273 val = va_arg(args.ap, int); 274 if ((long) val < 0) { 275 emitchar('-'); 276 val = -val; 277 } 278 goto udcommon; 279 280 case 'U': 281 case 'u': 282 val = va_arg(args.ap, unsigned); 283 udcommon: 284 { 285 char *stringp = lowerhex; 286 bp = buf+MAXDIGS; 287 stringp = lowerhex; 288 do { 289 *--bp = stringp[val%10]; 290 val /= 10; 291 } while (val); 292 } 293 goto intout; 294 295 case 'X': 296 { 297 char *stringp = upperhex; 298 val = va_arg(args.ap, unsigned); 299 bp = buf + MAXDIGS; 300 if (val == 0) 301 goto zero; 302 while (val) { 303 *--bp = stringp[val%16]; 304 val /= 16; 305 } 306 } 307 goto intout; 308 309 case 'x': 310 case 'p': 311 { 312 char *stringp = lowerhex; 313 val = va_arg(args.ap, unsigned); 314 bp = buf + MAXDIGS; 315 if (val == 0) 316 goto zero; 317 while (val) { 318 *--bp = stringp[val%16]; 319 val /= 16; 320 } 321 } 322 goto intout; 323 324 case 'O': 325 case 'o': 326 { 327 char *stringp = lowerhex; 328 val = va_arg(args.ap, unsigned); 329 bp = buf + MAXDIGS; 330 if (val == 0) 331 goto zero; 332 while (val) { 333 *--bp = stringp[val%8]; 334 val /= 8; 335 } 336 } 337 /* Common code to output integers */ 338 intout: 339 p = buf + MAXDIGS; 340 while (bp < p) { 341 c = *bp++; 342 emitchar(c); 343 } 344 continue; 345 346 zero: 347 c = '0'; 348 goto emitc; 349 350 default: 351 /* 352 * let AT&T deal with it 353 */ 354 cp-= 2; 355 } 356 357 Lsize = 0; /* Not long double unless we say so. */ 358 /* Scan the <flags> */ 359 fplus = 0; 360 fminus = 0; 361 fblank = 0; 362 fsharp = 0; 363 #if FZERO 364 ansi_fzero = 0; 365 compat_fzero = 0; 366 #endif 367 scan: switch (*++cp) { 368 case '+': 369 fplus = 1; 370 goto scan; 371 case '-': 372 fminus = 1; 373 goto scan; 374 case ' ': 375 fblank = 1; 376 goto scan; 377 case '#': 378 fsharp = 1; 379 goto scan; 380 #if FZERO 381 case '0': 382 ansi_fzero = 1; 383 compat_fzero = 1; 384 goto scan; 385 #endif 386 } 387 388 /* Scan the field width */ 389 if (*cp == '*') { 390 char *p; 391 int val; 392 393 p = _check_dol(cp+1, &val); 394 if (p != (char *)NULL) { 395 /* 396 * argument re-order 397 */ 398 if (fpos) { 399 _mkarglst(sformat, sargs, arglst); 400 fpos = 0; 401 } 402 if (val <= MAXARGS) { 403 args_width = arglst[val - 1]; 404 } else { 405 args_width = arglst[MAXARGS - 1]; 406 _getarg(sformat, &args_width, val); 407 } 408 width = va_arg(args_width.ap, int); 409 if (width < 0) { 410 width = -width; 411 fminus = 1; 412 } 413 cp = p; 414 } 415 else { 416 width = va_arg(args.ap, int); 417 if (width < 0) { 418 width = -width; 419 fminus = 1; 420 } 421 cp++; 422 } 423 } else { 424 index = width = 0; 425 while (isdigit(*cp)) { 426 n = tonumber(*cp++); 427 index = width = width * 10 + n; 428 } 429 } 430 431 /* Scan the precision */ 432 if (*cp == '.') { 433 434 /* '*' instead of digits? */ 435 if (*++cp == '*') { 436 char *p; 437 int val; 438 439 p = _check_dol(cp+1, &val); 440 if (p != (char *)NULL) { 441 /* 442 * argument re-order 443 */ 444 if (fpos) { 445 _mkarglst(sformat, sargs, arglst); 446 fpos = 0; 447 } 448 if (val <= MAXARGS) { 449 args_prec = arglst[val - 1]; 450 } else { 451 args_prec = arglst[MAXARGS - 1]; 452 _getarg(sformat, &args_prec, val); 453 } 454 prec = va_arg(args_prec.ap, int); 455 cp = p; 456 } 457 else { 458 prec = va_arg(args.ap, int); 459 cp++; 460 } 461 } else { 462 prec = 0; 463 while (isdigit(*cp)) { 464 n = tonumber(*cp++); 465 prec = prec * 10 + n; 466 } 467 } 468 } else 469 prec = -1; 470 471 if (*cp == '$') { 472 if (fpos) { 473 _mkarglst(sformat, sargs, arglst); 474 fpos = 0; 475 } 476 if (index <= MAXARGS) { 477 args = arglst[index - 1]; 478 } else { 479 args = arglst[MAXARGS - 1]; 480 _getarg(sformat, &args, index); 481 } 482 goto scan; 483 } 484 /* 485 * The character addressed by cp must be the 486 * format letter -- there is nothing left for 487 * it to be. 488 * 489 * The status of the +, -, #, blank, and 0 490 * flags are reflected in the variables 491 * "fplus", "fminus", "fsharp", "fblank", 492 * and "ansi_fzero"/"compat_fzero", respectively. 493 * "width" and "prec" contain numbers 494 * corresponding to the digit strings 495 * before and after the decimal point, 496 * respectively. If there was no decimal 497 * point, "prec" is -1. 498 * 499 * The following switch sets things up 500 * for printing. What ultimately gets 501 * printed will be padding blanks, a prefix, 502 * left padding zeroes, a value, right padding 503 * zeroes, a suffix, and more padding 504 * blanks. Padding blanks will not appear 505 * simultaneously on both the left and the 506 * right. Each case in this switch will 507 * compute the value, and leave in several 508 * variables the information necessary to 509 * construct what is to be printed. 510 * 511 * The prefix is a sign, a blank, "0x", "0X", 512 * or null, and is addressed by "prefix". 513 * 514 * The suffix is either null or an exponent, 515 * and is addressed by "suffix". 516 * 517 * The value to be printed starts at "bp" 518 * and continues up to and not including "p". 519 * 520 * "lzero" and "rzero" will contain the number 521 * of padding zeroes required on the left 522 * and right, respectively. If either of 523 * these variables is negative, it will be 524 * treated as if it were zero. 525 * 526 * The number of padding blanks, and whether 527 * they go on the left or the right, will be 528 * computed on exit from the switch. 529 */ 530 531 lzero = 0; 532 prefix = ""; 533 #if FLOAT 534 rzero = 0; 535 suffix = prefix; 536 #endif 537 538 #if FZERO 539 /* if both zero-padding and left-justify flags 540 * are used, ignore zero-padding, per ansi c 541 */ 542 if (ansi_fzero & fminus) { 543 ansi_fzero = 0; 544 compat_fzero = 0; 545 } 546 547 /* if zero-padding and precision are specified, 548 * ignore zero-padding for ansi-dictated formats, 549 * per ansi c 550 */ 551 if (ansi_fzero & (prec != -1)) ansi_fzero = 0; 552 #endif 553 554 next: 555 switch (fcode = *cp++) { 556 557 /* toss the length modifier, if any */ 558 case 'l': 559 case 'h': 560 goto next; 561 562 case 'L': 563 Lsize = 1; /* Remember long double size. */ 564 goto next; 565 566 /* 567 * fixed point representations 568 * 569 * "radix" is the radix for the conversion. 570 * Conversion is unsigned unless fcode is 'd'. 571 * We assume a 2's complement machine and 572 * that fixed point overflow (from negating 573 * the largest negative int) is ignored. 574 */ 575 576 case 'i': 577 case 'D': 578 case 'U': 579 case 'd': 580 case 'u': 581 radix = 10; 582 goto fixed; 583 584 case 'O': 585 case 'o': 586 radix = 8; 587 goto fixed; 588 589 case 'X': 590 case 'x': 591 radix = 16; 592 593 fixed: 594 /* Establish default precision */ 595 if (prec < 0) 596 prec = 1; 597 598 /* Fetch the argument to be printed */ 599 val = va_arg(args.ap, unsigned); 600 601 /* If signed conversion, establish sign */ 602 if (fcode == 'd' || fcode == 'D' || fcode == 'i') { 603 if ((long) val < 0) { 604 prefix = "-"; 605 val = -val; 606 } else if (fplus) 607 prefix = "+"; 608 else if (fblank) 609 prefix = " "; 610 } 611 /* Set translate table for digits */ 612 { 613 char *stringp; 614 if (fcode == 'X') 615 stringp = upperhex; 616 else 617 stringp = lowerhex; 618 619 /* Develop the digits of the value */ 620 bp = buf + MAXDIGS; 621 switch(radix) { 622 case 8: /*octal*/ 623 while (val) { 624 *--bp = stringp[val%8]; 625 val /= 8; 626 } 627 break; 628 case 16:/*hex*/ 629 while (val) { 630 *--bp = stringp[val%16]; 631 val /= 16; 632 } 633 break; 634 default: 635 while (val) { 636 *--bp = stringp[val%10]; 637 val /= 10; 638 } 639 break; 640 } /* switch */ 641 } 642 643 /* Calculate padding zero requirement */ 644 p = buf + MAXDIGS; 645 646 /* Handle the # flag */ 647 if (fsharp && bp != p) { 648 switch (fcode) { 649 case 'x': 650 prefix = "0x"; 651 break; 652 case 'X': 653 prefix = "0X"; 654 break; 655 } 656 } 657 #if FZERO 658 if (ansi_fzero) { 659 n = width - strlen(prefix); 660 if (n > prec) 661 prec = n; 662 } 663 #endif 664 lzero = bp - p + prec; 665 666 /* Handle the # flag for 'o' */ 667 if (fsharp && bp != p && fcode == 'o' && 668 lzero < 1) { 669 lzero = 1; 670 } 671 break; 672 #if FLOAT 673 674 #if defined(__sparc) 675 #define GETQVAL /* Sun-4 macro to get a quad q from the argument list, passed as a pointer. */ \ 676 { qval = *(va_arg(args.ap, quadruple*)) ; } 677 #else 678 #define GETQVAL /* Sun-3 macro to get a quad q from the argument list, passed as a value. */ \ 679 { int iq ; unsigned long * pl = (unsigned long *) (&qval) ; for(iq=0;iq<4;iq++) pl[iq] = (unsigned long) va_arg(args.ap, unsigned long) ; } 680 #endif 681 682 case 'E': 683 case 'e': 684 /* 685 * E-format. The general strategy 686 * here is fairly easy: we take 687 * what econvert gives us and re-format it. 688 */ 689 690 /* Establish default precision */ 691 if (prec < 0) 692 prec = 6; 693 694 /* Fetch the value */ 695 if (Lsize == 0) { /* Double */ 696 dval = va_arg(args.ap, double); 697 bp = econvert(dval, prec + 1, &decpt, &sign, convertbuffer); 698 } else { /* Long Double = quadruple */ 699 GETQVAL; 700 bp = qeconvert(&qval, prec + 1, &decpt, &sign, convertbuffer); 701 } 702 703 /* Determine the prefix */ 704 if (sign) 705 prefix = "-"; 706 else if (fplus) 707 prefix = "+"; 708 else if (fblank) 709 prefix = " "; 710 if (convertbuffer[0] > '9') 711 { /* handle infinity, nan */ 712 bp = &convertbuffer[0]; 713 for (p = bp+1 ; *p != 0 ; p++) ; 714 goto ebreak ; 715 } 716 { 717 char *stringp; 718 /* Place the first digit in the buffer */ 719 stringp = &buf[0]; 720 *stringp++ = *bp != '\0'? *bp++: '0'; 721 722 /* Put in a decimal point if needed */ 723 if (prec != 0 || fsharp) 724 *stringp++ = decpt_char; 725 726 /* Create the rest of the mantissa */ 727 rzero = prec; 728 while (rzero > 0 && *bp!= '\0') { 729 --rzero; 730 *stringp++ = *bp++; 731 } 732 p = stringp; 733 } 734 735 bp = &buf[0]; 736 737 /* Create the exponent */ 738 if (convertbuffer[0] != '0') 739 n = decpt - 1; 740 else 741 n = 0 ; 742 if (n < 0) 743 n = -n; 744 _fourdigitsquick( (short unsigned) n, &(expbuf[2]) ) ; 745 expbuf[6] = 0 ; 746 if (n < 100) 747 /* 748 * Normally two digit exponent field, 749 * three or four if required. 750 */ 751 { suffix = &(expbuf[4]) ; suffixlength = 4 ; } 752 else if (n < 1000) 753 { suffix = &(expbuf[3]) ; suffixlength = 5 ; } 754 else 755 { suffix = &(expbuf[2]) ; suffixlength = 6 ; } 756 /* Put in the exponent sign */ 757 *--suffix = (decpt > 0 || convertbuffer[0] == '0' )? '+': '-'; 758 759 /* Put in the e; note kludge in 'g' format */ 760 *--suffix = fcode; 761 ebreak: 762 #if FZERO 763 if (compat_fzero &! fminus) 764 /* Calculate padding zero requirement */ 765 lzero = width - (strlen(prefix) 766 + (p - buf) + rzero + suffixlength); 767 #endif 768 break; 769 770 case 'f': 771 /* 772 * F-format floating point. This is 773 * a good deal less simple than E-format. 774 * The overall strategy will be to call 775 * fconvert, reformat its result into buf, 776 * and calculate how many trailing 777 * zeroes will be required. There will 778 * never be any leading zeroes needed. 779 */ 780 781 /* Establish default precision */ 782 if (prec < 0) 783 prec = 6; 784 785 if (Lsize == 0) { 786 dval = va_arg(args.ap, double); 787 bp = fconvert(dval, prec, &decpt, &sign, convertbuffer); 788 } else { 789 GETQVAL ; 790 bp = qfconvert(&qval, prec, &decpt, &sign, convertbuffer); 791 } 792 793 /* Determine the prefix */ 794 if (sign) 795 prefix = "-"; 796 else if (fplus) 797 prefix = "+"; 798 else if (fblank) 799 prefix = " "; 800 if (convertbuffer[0] > '9') 801 { /* handle infinity, nan */ 802 bp = &convertbuffer[0]; 803 for (p = bp+1 ; *p != 0 ; p++) ; 804 goto fbreak ; 805 } 806 { 807 char *stringp; 808 /* Initialize buffer pointer */ 809 stringp = &buf[0]; 810 811 /* Emit the digits before the decimal point */ 812 n = decpt; 813 if (n <= 0) 814 *stringp++ = '0'; 815 else 816 do 817 if (*bp == '\0' ) 818 *stringp++ = '0'; 819 else { 820 *stringp++ = *bp++; 821 } 822 while (--n != 0); 823 824 /* Decide whether we need a decimal point */ 825 if (fsharp || prec > 0) 826 *stringp++ = decpt_char; 827 828 /* Digits(if any) after the decimal point */ 829 n = prec; 830 rzero = prec - n; 831 while (--n >= 0) { 832 if (++decpt <= 0 || *bp == '\0') 833 *stringp++ = '0'; 834 else { 835 *stringp++ = *bp++; 836 } 837 } 838 #if FZERO 839 if (compat_fzero &! fminus) 840 /* Calculate padding zero requirement */ 841 lzero = width - (strlen(prefix) 842 + (stringp - buf) + rzero); 843 #endif 844 p = stringp; 845 } 846 847 bp = &buf[0]; 848 fbreak: 849 break; 850 851 case 'G': 852 case 'g': 853 /* 854 * g-format. We play around a bit 855 * and then jump into e or f, as needed. 856 */ 857 858 /* Establish default precision */ 859 if (prec < 0) 860 prec = 6; 861 else if (prec == 0) 862 prec = 1; 863 864 if (Lsize == 0) { 865 dval = va_arg(args.ap, double); 866 bp = gconvert(dval, prec, fsharp, convertbuffer); 867 } else { 868 GETQVAL; 869 bp = qgconvert(&qval, prec, fsharp, convertbuffer); 870 } 871 bp = convertbuffer ; 872 if (convertbuffer[0] == '-') { 873 prefix = "-" ; 874 bp++; 875 } 876 else if (fplus) 877 prefix = "+"; 878 else if (fblank) 879 prefix = " "; 880 if (isupper(fcode)) 881 { /* Put in a big E for small minds. */ 882 for (p = bp ; (*p != NULL) && (*p != 'e') ; p++) ; 883 if (*p == 'e') *p = 'E' ; 884 for (; (*p != NULL) ; p++) ; 885 /* Find end of string. */ 886 } 887 else 888 for (p = bp ; *p != NULL ; p++) ; 889 /* Find end of string. */ 890 rzero = 0; 891 #if FZERO 892 if (compat_fzero & !fminus) 893 /* Calculate padding zero requirement */ 894 lzero = width - (strlen(prefix) 895 + (p - bp) + rzero); 896 #endif 897 break ; 898 899 #endif 900 case 'c': 901 buf[0] = va_arg(args.ap, int); 902 bp = &buf[0]; 903 p = bp + 1; 904 break; 905 906 case 's': 907 bp = va_arg(args.ap, char *); 908 if (prec < 0) 909 prec = MAXINT; 910 /* avoid *(0) */ 911 if (bp == NULL) 912 bp = nullstr; 913 for (n=0; *bp++ != '\0' && n < prec; n++) 914 ; 915 #if FZERO 916 if (compat_fzero &! fminus) 917 lzero = width - n; 918 #endif 919 p = --bp; 920 bp -= n; 921 break; 922 923 case '\0': 924 /* well, what's the punch line? */ 925 goto out; 926 927 case 'n': 928 svswitch = 1; 929 break; 930 default: 931 p = bp = &fcode; 932 p++; 933 break; 934 935 } 936 /* Calculate number of padding blanks */ 937 nblank = width 938 #if FLOAT 939 - (rzero < 0? 0: rzero) 940 - strlen(suffix) 941 #endif 942 - (p - bp) 943 - (lzero < 0? 0: lzero) 944 - strlen(prefix); 945 946 /* Blanks on left if required */ 947 if (!fminus) 948 while (--nblank >= 0) 949 emitchar(' '); 950 951 /* Prefix, if any */ 952 while (*prefix != '\0') { 953 emitchar(*prefix); 954 prefix++; 955 } 956 957 /* Zeroes on the left */ 958 while (--lzero >= 0) 959 emitchar('0'); 960 961 /* The value itself */ 962 while (bp < p) { 963 emitchar(*bp); 964 bp++; 965 } 966 #if FLOAT 967 /* Zeroes on the right */ 968 while (--rzero >= 0) 969 emitchar('0'); 970 971 /* The suffix */ 972 while (*suffix != '\0') { 973 emitchar(*suffix); 974 suffix++; 975 } 976 #endif 977 /* Blanks on the right if required */ 978 if (fminus) 979 while (--nblank >= 0) 980 emitchar(' '); 981 /* If %n is seen, save count in argument */ 982 if (svswitch == 1) { 983 long *svcount; 984 svcount = va_arg (args.ap, long *); 985 *svcount = count; 986 svswitch = 0; 987 } 988 } /* else */ 989 } while ((c = *cp++) != '\0'); /* do */ 990 out: 991 file->_ptr = fileptr; 992 file->_cnt = filecnt; 993 if (file->_flag & (_IONBF | _IOLBF) && 994 (file->_flag & _IONBF || 995 memchr((char *)file->_base, '\n', fileptr - file->_base) != NULL)) 996 (void) _xflsbuf(file); 997 return (ferror(file)? EOF: count); 998 } 999 1000 #if defined(__sparc) 1001 /* 1002 * We use "double *" instead of "quadruple *" to skip over the pointer to 1003 * long double on the argument list since a pointer is a pointer after all. 1004 */ 1005 #define SKIPQVAL { \ 1006 (void) va_arg(args.ap, double *); \ 1007 } 1008 #else /* Sun-3 */ 1009 #define SKIPQVAL { \ 1010 int iq; \ 1011 for (iq = 0; iq < 4; iq++) \ 1012 (void) va_arg(args.ap, unsigned long); \ 1013 } 1014 #endif 1015 /* 1016 * This function initializes arglst, to contain the appropriate va_list values 1017 * for the first MAXARGS arguments. 1018 */ 1019 void 1020 _mkarglst(char *fmt, stva_list args, stva_list arglst[]) 1021 { 1022 static char *digits = "01234567890", *skips = "# +-.0123456789h$"; 1023 1024 enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR, 1025 LONG_PTR, INT_PTR}; 1026 enum types typelst[MAXARGS], curtype; 1027 int maxnum, n, curargno, flags; 1028 1029 /* 1030 * Algorithm 1. set all argument types to zero. 1031 * 2. walk through fmt putting arg types in typelst[]. 1032 * 3. walk through args using va_arg(args.ap, typelst[n]) 1033 * and set arglst[] to the appropriate values. 1034 * Assumptions: Cannot use %*$... to specify variable position. 1035 */ 1036 1037 (void)memset((void *)typelst, 0, sizeof(typelst)); 1038 maxnum = -1; 1039 curargno = 0; 1040 while ((fmt = strchr(fmt, '%')) != 0) 1041 { 1042 fmt++; /* skip % */ 1043 if (fmt[n = strspn(fmt, digits)] == '$') 1044 { 1045 curargno = atoi(fmt) - 1; /* convert to zero base */ 1046 fmt += n + 1; 1047 } 1048 flags = 0; 1049 again:; 1050 fmt += strspn(fmt, skips); 1051 switch (*fmt++) 1052 { 1053 case '%': /*there is no argument! */ 1054 continue; 1055 case 'l': 1056 flags |= 0x1; 1057 goto again; 1058 case 'L': 1059 flags |= 0x8; 1060 goto again; 1061 case '*': /* int argument used for value */ 1062 flags |= 0x2; 1063 curtype = INT; 1064 break; 1065 case 'e': 1066 case 'E': 1067 case 'f': 1068 case 'g': 1069 case 'G': 1070 if (flags & 0x8) 1071 curtype = LONG_DOUBLE; 1072 else 1073 curtype = DOUBLE; 1074 break; 1075 case 's': 1076 curtype = CHAR_PTR; 1077 break; 1078 case 'p': 1079 curtype = VOID_PTR; 1080 break; 1081 case 'n': 1082 if (flags & 0x1) 1083 curtype = LONG_PTR; 1084 else 1085 curtype = INT_PTR; 1086 break; 1087 default: 1088 if (flags & 0x1) 1089 curtype = LONG; 1090 else 1091 curtype = INT; 1092 break; 1093 } 1094 if (curargno >= 0 && curargno < MAXARGS) 1095 { 1096 typelst[curargno] = curtype; 1097 if (maxnum < curargno) 1098 maxnum = curargno; 1099 } 1100 curargno++; /* default to next in list */ 1101 if (flags & 0x2) /* took care of *, keep going */ 1102 { 1103 flags ^= 0x2; 1104 goto again; 1105 } 1106 } 1107 for (n = 0 ; n <= maxnum; n++) 1108 { 1109 arglst[n] = args; 1110 if (typelst[n] == 0) 1111 typelst[n] = INT; 1112 1113 switch (typelst[n]) 1114 { 1115 case INT: 1116 va_arg(args.ap, int); 1117 break; 1118 case LONG: 1119 va_arg(args.ap, long); 1120 break; 1121 case CHAR_PTR: 1122 va_arg(args.ap, char *); 1123 break; 1124 case DOUBLE: 1125 va_arg(args.ap, double); 1126 break; 1127 case LONG_DOUBLE: 1128 SKIPQVAL 1129 break; 1130 case VOID_PTR: 1131 va_arg(args.ap, void *); 1132 break; 1133 case LONG_PTR: 1134 va_arg(args.ap, long *); 1135 break; 1136 case INT_PTR: 1137 va_arg(args.ap, int *); 1138 break; 1139 } 1140 } 1141 } 1142 1143 /* 1144 * This function is used to find the va_list value for arguments whose 1145 * position is greater than MAXARGS. This function is slow, so hopefully 1146 * MAXARGS will be big enough so that this function need only be called in 1147 * unusual circumstances. 1148 * pargs is assumed to contain the value of arglst[MAXARGS - 1]. 1149 */ 1150 void 1151 _getarg(char *fmt, stva_list *pargs, int argno) 1152 { 1153 static char *digits = "01234567890", *skips = "# +-.0123456789h$"; 1154 int i, n, curargno, flags; 1155 char *sfmt = fmt; 1156 int found = 1; 1157 1158 curargno = i = MAXARGS; 1159 while (found) 1160 { 1161 fmt = sfmt; 1162 found = 0; 1163 while ((i != argno) && (fmt = strchr(fmt, '%')) != 0) 1164 { 1165 fmt++; /* skip % */ 1166 if (fmt[n = strspn(fmt, digits)] == '$') 1167 { 1168 curargno = atoi(fmt); 1169 fmt += n + 1; 1170 } 1171 1172 /* find conversion specifier for next argument */ 1173 if (i != curargno) 1174 { 1175 curargno++; 1176 continue; 1177 } else 1178 found = 1; 1179 flags = 0; 1180 again:; 1181 fmt += strspn(fmt, skips); 1182 switch (*fmt++) 1183 { 1184 case '%': /*there is no argument! */ 1185 continue; 1186 case 'l': 1187 flags |= 0x1; 1188 goto again; 1189 case 'L': 1190 flags |= 0x8; 1191 goto again; 1192 case '*': /* int argument used for value */ 1193 flags |= 0x2; 1194 (void)va_arg((*pargs).ap, int); 1195 break; 1196 case 'e': 1197 case 'E': 1198 case 'f': 1199 case 'g': 1200 case 'G': 1201 if (flags & 0x8) { 1202 #define args (*pargs) 1203 SKIPQVAL 1204 #undef args 1205 } 1206 else 1207 (void)va_arg((*pargs).ap, double); 1208 break; 1209 case 's': 1210 (void)va_arg((*pargs).ap, char *); 1211 break; 1212 case 'p': 1213 (void)va_arg((*pargs).ap, void *); 1214 break; 1215 case 'n': 1216 if (flags & 0x1) 1217 (void)va_arg((*pargs).ap, long *); 1218 else 1219 (void)va_arg((*pargs).ap, int *); 1220 break; 1221 default: 1222 if (flags & 0x1) 1223 (void)va_arg((*pargs).ap, long int); 1224 else 1225 (void)va_arg((*pargs).ap, int); 1226 break; 1227 } 1228 i++; 1229 curargno++; /* default to next in list */ 1230 if (flags & 0x2) /* took care of *, keep going */ 1231 { 1232 flags ^= 0x2; 1233 goto again; 1234 } 1235 } 1236 1237 /* missing specifier for parameter, assume parameter is an int */ 1238 if (!found && i != argno) { 1239 (void)va_arg((*pargs).ap, int); 1240 i++; 1241 curargno++; 1242 found = 1; 1243 } 1244 } 1245 } 1246 1247 1248 /* 1249 * parse a string, mini parse 1250 */ 1251 static char * 1252 _check_dol(char *s, int *val) 1253 { 1254 char *os; /* save old string */ 1255 int tmp_val = 0; 1256 int flag = 0; 1257 1258 while (isdigit (*s)) { 1259 ++flag; 1260 tmp_val = tmp_val*10 + *s - '0'; 1261 s++; 1262 } 1263 if (flag == 0) 1264 return ((char *)NULL); 1265 if (*s == '$') { 1266 *val = tmp_val; 1267 return(++s); 1268 } 1269 return ((char *)NULL); 1270 } 1271