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