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