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
_doprnt(char * format,va_list in_args,FILE * file)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
_mkarglst(char * fmt,stva_list args,stva_list arglst[])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
_getarg(char * fmt,stva_list * pargs,int argno)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 *
_check_dol(char * s,int * val)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