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