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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
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.
39 #define FLOAT 1 /* YES! we want floating */
49 #include <string.h> /* strchr, strlen, strspn */
51 #define max(a,b) ((a) > (b) ? (a) : (b))
52 #define min(a,b) ((a) < (b) ? (a) : (b))
54 /* If this symbol is nonzero, allow '0' as a flag */
55 /* If this symbol is nonzero, allow '0' as a flag */
60 * libc/gen/common functions for floating-point conversion
62 #include <floatingpoint.h>
63 extern void _fourdigitsquick();
66 #define emitchar(c) { if (--filecnt < 0) { \
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; \
74 (void) _xflsbuf(iop); \
75 fileptr = iop->_ptr; \
76 filecnt = iop->_cnt; \
80 *fileptr++ = (unsigned)(c); \
84 static char *nullstr
= "(null)";
85 static char *lowerhex
= "0123456789abcdef";
86 static char *upperhex
= "0123456789ABCDEF";
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..
93 typedef struct stva_list
{
97 void _mkarglst(char *, stva_list
, stva_list
[]);
98 void _getarg(char *, stva_list
*, int);
99 static char *_check_dol(char *, int *);
102 _doprnt(char *format
, va_list in_args
, FILE *file
)
104 char convertbuffer
[1024] ;
106 /* Current position in format */
109 /* Starting and ending points for value to be printed */
113 /* Pointer and count for I/O buffer */
114 unsigned char *fileptr
;
117 /* Field width and precision */
124 /* Number of padding zeroes required on the left */
127 /* Flags - nonzero if corresponding character appears in format */
130 bool fblank
; /* blank */
133 bool ansi_fzero
; /* 0 for ansi-dictated formats */
134 bool compat_fzero
; /* 0 for backward compatibility */
136 bool Lsize
; /* Capital L for size = long double = quadruple */
138 /* Pointer to sign, "0x", "0X", or empty */
145 /* Exponent or empty */
148 /* Buffer to create exponent */
149 char expbuf
[7]; /* "e+xxxx\0" */
151 /* Number of padding zeroes required on the right */
154 /* Length of exponent suffix. */
157 /* The value being converted, if real or quadruple */
161 /* Output values from fconvert and econvert */
164 /* Values are developed in this buffer */
165 char buf
[1034]; /* Size of convertbuffer, plus some for exponent and sign. */
167 /* Current locale's decimal point */
168 char decpt_char
= *(localeconv()->decimal_point
);
171 /* Values are developed in this buffer */
176 /* The value being converted, if integer */
184 /* count of output characters */
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.
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
;
207 /* initialize p an bp (starting and ending points) bugid 1141781 */
212 if ((c
= *cp
++) != '\0') {
214 * We know we're going to write something; make sure
215 * we can write and set up buffers, etc..
220 return(0); /* no fault, no error */
223 fileptr
= file
->_ptr
;
224 filecnt
= file
->_cnt
;
227 * The main loop -- this loop goes through one iteration
228 * for each ordinary character or format specification.
232 /* Ordinary (non-%) character */
236 * % has been spotted!
238 * First, try the 99% cases.
239 * then parse the format specification.
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).
252 /* Quickly ignore long & short specifiers */
256 bp
= va_arg(args
.ap
, char *);
265 c
= va_arg(args
.ap
, int);
273 val
= va_arg(args
.ap
, int);
274 if ((long) val
< 0) {
282 val
= va_arg(args
.ap
, unsigned);
285 char *stringp
= lowerhex
;
289 *--bp
= stringp
[val
%10];
297 char *stringp
= upperhex
;
298 val
= va_arg(args
.ap
, unsigned);
303 *--bp
= stringp
[val
%16];
312 char *stringp
= lowerhex
;
313 val
= va_arg(args
.ap
, unsigned);
318 *--bp
= stringp
[val
%16];
327 char *stringp
= lowerhex
;
328 val
= va_arg(args
.ap
, unsigned);
333 *--bp
= stringp
[val
%8];
337 /* Common code to output integers */
352 * let AT&T deal with it
357 Lsize
= 0; /* Not long double unless we say so. */
358 /* Scan the <flags> */
367 scan
: switch (*++cp
) {
388 /* Scan the field width */
393 p
= _check_dol(cp
+1, &val
);
394 if (p
!= (char *)NULL
) {
399 _mkarglst(sformat
, sargs
, arglst
);
402 if (val
<= MAXARGS
) {
403 args_width
= arglst
[val
- 1];
405 args_width
= arglst
[MAXARGS
- 1];
406 _getarg(sformat
, &args_width
, val
);
408 width
= va_arg(args_width
.ap
, int);
416 width
= va_arg(args
.ap
, int);
425 while (isdigit(*cp
)) {
427 index
= width
= width
* 10 + n
;
431 /* Scan the precision */
434 /* '*' instead of digits? */
439 p
= _check_dol(cp
+1, &val
);
440 if (p
!= (char *)NULL
) {
445 _mkarglst(sformat
, sargs
, arglst
);
448 if (val
<= MAXARGS
) {
449 args_prec
= arglst
[val
- 1];
451 args_prec
= arglst
[MAXARGS
- 1];
452 _getarg(sformat
, &args_prec
, val
);
454 prec
= va_arg(args_prec
.ap
, int);
458 prec
= va_arg(args
.ap
, int);
463 while (isdigit(*cp
)) {
465 prec
= prec
* 10 + n
;
473 _mkarglst(sformat
, sargs
, arglst
);
476 if (index
<= MAXARGS
) {
477 args
= arglst
[index
- 1];
479 args
= arglst
[MAXARGS
- 1];
480 _getarg(sformat
, &args
, index
);
485 * The character addressed by cp must be the
486 * format letter -- there is nothing left for
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.
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.
511 * The prefix is a sign, a blank, "0x", "0X",
512 * or null, and is addressed by "prefix".
514 * The suffix is either null or an exponent,
515 * and is addressed by "suffix".
517 * The value to be printed starts at "bp"
518 * and continues up to and not including "p".
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.
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.
539 /* if both zero-padding and left-justify flags
540 * are used, ignore zero-padding, per ansi c
542 if (ansi_fzero
& fminus
) {
547 /* if zero-padding and precision are specified,
548 * ignore zero-padding for ansi-dictated formats,
551 if (ansi_fzero
& (prec
!= -1)) ansi_fzero
= 0;
555 switch (fcode
= *cp
++) {
557 /* toss the length modifier, if any */
563 Lsize
= 1; /* Remember long double size. */
567 * fixed point representations
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.
594 /* Establish default precision */
598 /* Fetch the argument to be printed */
599 val
= va_arg(args
.ap
, unsigned);
601 /* If signed conversion, establish sign */
602 if (fcode
== 'd' || fcode
== 'D' || fcode
== 'i') {
603 if ((long) val
< 0) {
611 /* Set translate table for digits */
619 /* Develop the digits of the value */
624 *--bp
= stringp
[val
%8];
630 *--bp
= stringp
[val
%16];
636 *--bp
= stringp
[val
%10];
643 /* Calculate padding zero requirement */
646 /* Handle the # flag */
647 if (fsharp
&& bp
!= p
) {
659 n
= width
- strlen(prefix
);
664 lzero
= bp
- p
+ prec
;
666 /* Handle the # flag for 'o' */
667 if (fsharp
&& bp
!= p
&& fcode
== 'o' &&
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*)) ; }
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) ; }
685 * E-format. The general strategy
686 * here is fairly easy: we take
687 * what econvert gives us and re-format it.
690 /* Establish default precision */
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 */
700 bp
= qeconvert(&qval
, prec
+ 1, &decpt
, &sign
, convertbuffer
);
703 /* Determine the prefix */
710 if (convertbuffer
[0] > '9')
711 { /* handle infinity, nan */
712 bp
= &convertbuffer
[0];
713 for (p
= bp
+1 ; *p
!= 0 ; p
++) ;
718 /* Place the first digit in the buffer */
720 *stringp
++ = *bp
!= '\0'? *bp
++: '0';
722 /* Put in a decimal point if needed */
723 if (prec
!= 0 || fsharp
)
724 *stringp
++ = decpt_char
;
726 /* Create the rest of the mantissa */
728 while (rzero
> 0 && *bp
!= '\0') {
737 /* Create the exponent */
738 if (convertbuffer
[0] != '0')
744 _fourdigitsquick( (short unsigned) n
, &(expbuf
[2]) ) ;
748 * Normally two digit exponent field,
749 * three or four if required.
751 { suffix
= &(expbuf
[4]) ; suffixlength
= 4 ; }
753 { suffix
= &(expbuf
[3]) ; suffixlength
= 5 ; }
755 { suffix
= &(expbuf
[2]) ; suffixlength
= 6 ; }
756 /* Put in the exponent sign */
757 *--suffix
= (decpt
> 0 || convertbuffer
[0] == '0' )? '+': '-';
759 /* Put in the e; note kludge in 'g' format */
763 if (compat_fzero
&! fminus
)
764 /* Calculate padding zero requirement */
765 lzero
= width
- (strlen(prefix
)
766 + (p
- buf
) + rzero
+ suffixlength
);
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.
781 /* Establish default precision */
786 dval
= va_arg(args
.ap
, double);
787 bp
= fconvert(dval
, prec
, &decpt
, &sign
, convertbuffer
);
790 bp
= qfconvert(&qval
, prec
, &decpt
, &sign
, convertbuffer
);
793 /* Determine the prefix */
800 if (convertbuffer
[0] > '9')
801 { /* handle infinity, nan */
802 bp
= &convertbuffer
[0];
803 for (p
= bp
+1 ; *p
!= 0 ; p
++) ;
808 /* Initialize buffer pointer */
811 /* Emit the digits before the decimal point */
824 /* Decide whether we need a decimal point */
825 if (fsharp
|| prec
> 0)
826 *stringp
++ = decpt_char
;
828 /* Digits(if any) after the decimal point */
832 if (++decpt
<= 0 || *bp
== '\0')
839 if (compat_fzero
&! fminus
)
840 /* Calculate padding zero requirement */
841 lzero
= width
- (strlen(prefix
)
842 + (stringp
- buf
) + rzero
);
854 * g-format. We play around a bit
855 * and then jump into e or f, as needed.
858 /* Establish default precision */
865 dval
= va_arg(args
.ap
, double);
866 bp
= gconvert(dval
, prec
, fsharp
, convertbuffer
);
869 bp
= qgconvert(&qval
, prec
, fsharp
, convertbuffer
);
872 if (convertbuffer
[0] == '-') {
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. */
888 for (p
= bp
; *p
!= NULL
; p
++) ;
889 /* Find end of string. */
892 if (compat_fzero
& !fminus
)
893 /* Calculate padding zero requirement */
894 lzero
= width
- (strlen(prefix
)
901 buf
[0] = va_arg(args
.ap
, int);
907 bp
= va_arg(args
.ap
, char *);
913 for (n
=0; *bp
++ != '\0' && n
< prec
; n
++)
916 if (compat_fzero
&! fminus
)
924 /* well, what's the punch line? */
936 /* Calculate number of padding blanks */
939 - (rzero
< 0? 0: rzero
)
943 - (lzero
< 0? 0: lzero
)
946 /* Blanks on left if required */
948 while (--nblank
>= 0)
952 while (*prefix
!= '\0') {
957 /* Zeroes on the left */
961 /* The value itself */
967 /* Zeroes on the right */
972 while (*suffix
!= '\0') {
977 /* Blanks on the right if required */
979 while (--nblank
>= 0)
981 /* If %n is seen, save count in argument */
984 svcount
= va_arg (args
.ap
, long *);
989 } while ((c
= *cp
++) != '\0'); /* do */
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
);
1000 #if defined(__sparc)
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.
1005 #define SKIPQVAL { \
1006 (void) va_arg(args.ap, double *); \
1009 #define SKIPQVAL { \
1011 for (iq = 0; iq < 4; iq++) \
1012 (void) va_arg(args.ap, unsigned long); \
1016 * This function initializes arglst, to contain the appropriate va_list values
1017 * for the first MAXARGS arguments.
1020 _mkarglst(char *fmt
, stva_list args
, stva_list arglst
[])
1022 static char *digits
= "01234567890", *skips
= "# +-.0123456789h$";
1024 enum types
{INT
= 1, LONG
, CHAR_PTR
, DOUBLE
, LONG_DOUBLE
, VOID_PTR
,
1026 enum types typelst
[MAXARGS
], curtype
;
1027 int maxnum
, n
, curargno
, flags
;
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.
1037 (void)memset((void *)typelst
, 0, sizeof(typelst
));
1040 while ((fmt
= strchr(fmt
, '%')) != 0)
1043 if (fmt
[n
= strspn(fmt
, digits
)] == '$')
1045 curargno
= atoi(fmt
) - 1; /* convert to zero base */
1050 fmt
+= strspn(fmt
, skips
);
1053 case '%': /*there is no argument! */
1061 case '*': /* int argument used for value */
1071 curtype
= LONG_DOUBLE
;
1094 if (curargno
>= 0 && curargno
< MAXARGS
)
1096 typelst
[curargno
] = curtype
;
1097 if (maxnum
< curargno
)
1100 curargno
++; /* default to next in list */
1101 if (flags
& 0x2) /* took care of *, keep going */
1107 for (n
= 0 ; n
<= maxnum
; n
++)
1110 if (typelst
[n
] == 0)
1116 va_arg(args
.ap
, int);
1119 va_arg(args
.ap
, long);
1122 va_arg(args
.ap
, char *);
1125 va_arg(args
.ap
, double);
1131 va_arg(args
.ap
, void *);
1134 va_arg(args
.ap
, long *);
1137 va_arg(args
.ap
, int *);
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].
1151 _getarg(char *fmt
, stva_list
*pargs
, int argno
)
1153 static char *digits
= "01234567890", *skips
= "# +-.0123456789h$";
1154 int i
, n
, curargno
, flags
;
1158 curargno
= i
= MAXARGS
;
1163 while ((i
!= argno
) && (fmt
= strchr(fmt
, '%')) != 0)
1166 if (fmt
[n
= strspn(fmt
, digits
)] == '$')
1168 curargno
= atoi(fmt
);
1172 /* find conversion specifier for next argument */
1181 fmt
+= strspn(fmt
, skips
);
1184 case '%': /*there is no argument! */
1192 case '*': /* int argument used for value */
1194 (void)va_arg((*pargs
).ap
, int);
1202 #define args (*pargs)
1207 (void)va_arg((*pargs
).ap
, double);
1210 (void)va_arg((*pargs
).ap
, char *);
1213 (void)va_arg((*pargs
).ap
, void *);
1217 (void)va_arg((*pargs
).ap
, long *);
1219 (void)va_arg((*pargs
).ap
, int *);
1223 (void)va_arg((*pargs
).ap
, long int);
1225 (void)va_arg((*pargs
).ap
, int);
1229 curargno
++; /* default to next in list */
1230 if (flags
& 0x2) /* took care of *, keep going */
1237 /* missing specifier for parameter, assume parameter is an int */
1238 if (!found
&& i
!= argno
) {
1239 (void)va_arg((*pargs
).ap
, int);
1249 * parse a string, mini parse
1252 _check_dol(char *s
, int *val
)
1254 char *os
; /* save old string */
1258 while (isdigit (*s
)) {
1260 tmp_val
= tmp_val
*10 + *s
- '0';
1264 return ((char *)NULL
);
1269 return ((char *)NULL
);