10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*722Smuffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*722Smuffin * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
310Sstevel@tonic-gate
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate * _doprnt: common code for printf, fprintf, sprintf
340Sstevel@tonic-gate * Floating-point code is included or not, depending
350Sstevel@tonic-gate * on whether the preprocessor variable FLOAT is 1 or 0.
360Sstevel@tonic-gate */
370Sstevel@tonic-gate #define MAXARGS 50
380Sstevel@tonic-gate #ifndef FLOAT
390Sstevel@tonic-gate #define FLOAT 1 /* YES! we want floating */
400Sstevel@tonic-gate #endif
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include <stdio.h>
430Sstevel@tonic-gate #include <ctype.h>
44*722Smuffin #include <stdarg.h>
450Sstevel@tonic-gate #include <values.h>
460Sstevel@tonic-gate #include <locale.h>
470Sstevel@tonic-gate #include "doprnt.h"
480Sstevel@tonic-gate #include "stdiom.h"
490Sstevel@tonic-gate #include <string.h> /* strchr, strlen, strspn */
500Sstevel@tonic-gate
510Sstevel@tonic-gate #define max(a,b) ((a) > (b) ? (a) : (b))
520Sstevel@tonic-gate #define min(a,b) ((a) < (b) ? (a) : (b))
530Sstevel@tonic-gate
540Sstevel@tonic-gate /* If this symbol is nonzero, allow '0' as a flag */
550Sstevel@tonic-gate /* If this symbol is nonzero, allow '0' as a flag */
560Sstevel@tonic-gate #define FZERO 1
570Sstevel@tonic-gate
580Sstevel@tonic-gate #if FLOAT
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate * libc/gen/common functions for floating-point conversion
610Sstevel@tonic-gate */
620Sstevel@tonic-gate #include <floatingpoint.h>
630Sstevel@tonic-gate extern void _fourdigitsquick();
640Sstevel@tonic-gate #endif
650Sstevel@tonic-gate
660Sstevel@tonic-gate #define emitchar(c) { if (--filecnt < 0) { \
67*722Smuffin FILE *iop = file; \
680Sstevel@tonic-gate if (((iop->_flag & (_IOLBF|_IONBF)) == 0 \
690Sstevel@tonic-gate || -filecnt >= iop->_bufsiz)) { \
700Sstevel@tonic-gate iop->_ptr = fileptr; \
710Sstevel@tonic-gate if (iop->_flag & _IOSTRG) \
720Sstevel@tonic-gate return iop->_ptr - iop->_base; \
730Sstevel@tonic-gate else \
740Sstevel@tonic-gate (void) _xflsbuf(iop); \
750Sstevel@tonic-gate fileptr = iop->_ptr; \
760Sstevel@tonic-gate filecnt = iop->_cnt; \
770Sstevel@tonic-gate filecnt--; \
780Sstevel@tonic-gate } \
790Sstevel@tonic-gate } \
800Sstevel@tonic-gate *fileptr++ = (unsigned)(c); \
810Sstevel@tonic-gate count++; \
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate static char *nullstr = "(null)";
850Sstevel@tonic-gate static char *lowerhex = "0123456789abcdef";
860Sstevel@tonic-gate static char *upperhex = "0123456789ABCDEF";
870Sstevel@tonic-gate
880Sstevel@tonic-gate /* stva_list is used to subvert C's restriction that a variable with an
890Sstevel@tonic-gate * array type can not appear on the left hand side of an assignment operator.
900Sstevel@tonic-gate * By putting the array inside a structure, the functionality of assigning to
910Sstevel@tonic-gate * the whole array through a simple assignment is achieved..
920Sstevel@tonic-gate */
930Sstevel@tonic-gate typedef struct stva_list {
940Sstevel@tonic-gate va_list ap;
950Sstevel@tonic-gate } stva_list;
960Sstevel@tonic-gate
97*722Smuffin void _mkarglst(char *, stva_list, stva_list []);
98*722Smuffin void _getarg(char *, stva_list *, int);
99*722Smuffin static char *_check_dol(char *, int *);
100*722Smuffin
101*722Smuffin int
_doprnt(char * format,va_list in_args,FILE * file)102*722Smuffin _doprnt(char *format, va_list in_args, FILE *file)
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate char convertbuffer[1024] ;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /* Current position in format */
107*722Smuffin char *cp;
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /* Starting and ending points for value to be printed */
110*722Smuffin char *bp;
1110Sstevel@tonic-gate char *p;
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate /* Pointer and count for I/O buffer */
114*722Smuffin unsigned char *fileptr;
115*722Smuffin int filecnt;
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /* Field width and precision */
1180Sstevel@tonic-gate int width;
119*722Smuffin int prec;
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /* Format code */
1220Sstevel@tonic-gate char fcode;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /* Number of padding zeroes required on the left */
1250Sstevel@tonic-gate int lzero;
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate /* Flags - nonzero if corresponding character appears in format */
1280Sstevel@tonic-gate bool fplus; /* + */
1290Sstevel@tonic-gate bool fminus; /* - */
1300Sstevel@tonic-gate bool fblank; /* blank */
1310Sstevel@tonic-gate bool fsharp; /* # */
1320Sstevel@tonic-gate #if FZERO
1330Sstevel@tonic-gate bool ansi_fzero; /* 0 for ansi-dictated formats */
1340Sstevel@tonic-gate bool compat_fzero; /* 0 for backward compatibility */
1350Sstevel@tonic-gate #endif
1360Sstevel@tonic-gate bool Lsize; /* Capital L for size = long double = quadruple */
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /* Pointer to sign, "0x", "0X", or empty */
1390Sstevel@tonic-gate char *prefix;
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /* Scratch */
1420Sstevel@tonic-gate int nblank;
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate #if FLOAT
1450Sstevel@tonic-gate /* Exponent or empty */
1460Sstevel@tonic-gate char *suffix;
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate /* Buffer to create exponent */
1490Sstevel@tonic-gate char expbuf[7]; /* "e+xxxx\0" */
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate /* Number of padding zeroes required on the right */
1520Sstevel@tonic-gate int rzero;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /* Length of exponent suffix. */
1550Sstevel@tonic-gate int suffixlength;
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate /* The value being converted, if real or quadruple */
1580Sstevel@tonic-gate double dval;
1590Sstevel@tonic-gate quadruple qval;
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /* Output values from fconvert and econvert */
1620Sstevel@tonic-gate int decpt, sign;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /* Values are developed in this buffer */
1650Sstevel@tonic-gate char buf[1034]; /* Size of convertbuffer, plus some for exponent and sign. */
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /* Current locale's decimal point */
1680Sstevel@tonic-gate char decpt_char = *(localeconv()->decimal_point);
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate #else
1710Sstevel@tonic-gate /* Values are developed in this buffer */
1720Sstevel@tonic-gate char buf[MAXDIGS];
1730Sstevel@tonic-gate #endif
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /* The value being converted, if integer */
177*722Smuffin unsigned long val;
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* Work variables */
180*722Smuffin int n;
181*722Smuffin char c;
1820Sstevel@tonic-gate char radix;
1830Sstevel@tonic-gate int svswitch = 0;
1840Sstevel@tonic-gate /* count of output characters */
185*722Smuffin int count;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /* variables for positional parameters */
1880Sstevel@tonic-gate char *sformat = format; /* save the beginning of the format */
1890Sstevel@tonic-gate int fpos = 1; /* 1 if first positional parameter */
1900Sstevel@tonic-gate stva_list args, /* used to step through the argument list */
1910Sstevel@tonic-gate args_width, /* for width */
1920Sstevel@tonic-gate args_prec, /* for prec */
1930Sstevel@tonic-gate sargs; /* used to save the start of the argument list */
1940Sstevel@tonic-gate stva_list arglst[MAXARGS];/* array giving the approriate values
1950Sstevel@tonic-gate * for va_arg() to retrieve the
1960Sstevel@tonic-gate * corresponding argument:
1970Sstevel@tonic-gate * arglst[0] is the first argument
1980Sstevel@tonic-gate * arglst[1] is the second argument, etc.
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate int index = 0; /* argument placeolder */
2010Sstevel@tonic-gate /* Initialize args and sargs to the start of the argument list.
2020Sstevel@tonic-gate * Note that ANSI guarantees that the address of the first member of
2030Sstevel@tonic-gate * a structure will be the same as the address of the structure. */
2040Sstevel@tonic-gate args_width = args_prec = args = sargs = *(struct stva_list *)&in_args;
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /* initialize p an bp (starting and ending points) bugid 1141781 */
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate p = bp = NULL;
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate cp = format;
2120Sstevel@tonic-gate if ((c = *cp++) != '\0') {
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate * We know we're going to write something; make sure
2150Sstevel@tonic-gate * we can write and set up buffers, etc..
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate if (_WRTCHK(file))
2180Sstevel@tonic-gate return(EOF);
2190Sstevel@tonic-gate } else
2200Sstevel@tonic-gate return(0); /* no fault, no error */
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate count = 0;
2230Sstevel@tonic-gate fileptr = file->_ptr;
2240Sstevel@tonic-gate filecnt = file->_cnt;
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate * The main loop -- this loop goes through one iteration
2280Sstevel@tonic-gate * for each ordinary character or format specification.
2290Sstevel@tonic-gate */
2300Sstevel@tonic-gate do {
2310Sstevel@tonic-gate if (c != '%') {
2320Sstevel@tonic-gate /* Ordinary (non-%) character */
2330Sstevel@tonic-gate emitchar(c);
2340Sstevel@tonic-gate } else {
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate * % has been spotted!
2370Sstevel@tonic-gate *
2380Sstevel@tonic-gate * First, try the 99% cases.
2390Sstevel@tonic-gate * then parse the format specification.
2400Sstevel@tonic-gate *
2410Sstevel@tonic-gate * Note that this code assumes the Sun
2420Sstevel@tonic-gate * Workstation environment (all params
2430Sstevel@tonic-gate * passed as int == long, no interrupts
2440Sstevel@tonic-gate * for fixed point overflow from negating
2450Sstevel@tonic-gate * the most negative number).
2460Sstevel@tonic-gate */
2470Sstevel@tonic-gate skipit:
2480Sstevel@tonic-gate switch(c = *cp++) {
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate case 'l':
2510Sstevel@tonic-gate case 'h':
2520Sstevel@tonic-gate /* Quickly ignore long & short specifiers */
2530Sstevel@tonic-gate goto skipit;
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate case 's':
2560Sstevel@tonic-gate bp = va_arg(args.ap, char *);
2570Sstevel@tonic-gate if (bp == NULL)
2580Sstevel@tonic-gate bp = nullstr;
2590Sstevel@tonic-gate while (c = *bp++)
2600Sstevel@tonic-gate emitchar(c);
2610Sstevel@tonic-gate p = bp;
2620Sstevel@tonic-gate continue;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate case 'c':
2650Sstevel@tonic-gate c = va_arg(args.ap, int);
2660Sstevel@tonic-gate emitc:
2670Sstevel@tonic-gate emitchar(c);
2680Sstevel@tonic-gate continue;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate case 'i':
2710Sstevel@tonic-gate case 'd':
2720Sstevel@tonic-gate case 'D':
2730Sstevel@tonic-gate val = va_arg(args.ap, int);
2740Sstevel@tonic-gate if ((long) val < 0) {
2750Sstevel@tonic-gate emitchar('-');
2760Sstevel@tonic-gate val = -val;
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate goto udcommon;
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate case 'U':
2810Sstevel@tonic-gate case 'u':
2820Sstevel@tonic-gate val = va_arg(args.ap, unsigned);
2830Sstevel@tonic-gate udcommon:
2840Sstevel@tonic-gate {
285*722Smuffin char *stringp = lowerhex;
2860Sstevel@tonic-gate bp = buf+MAXDIGS;
2870Sstevel@tonic-gate stringp = lowerhex;
2880Sstevel@tonic-gate do {
2890Sstevel@tonic-gate *--bp = stringp[val%10];
2900Sstevel@tonic-gate val /= 10;
2910Sstevel@tonic-gate } while (val);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate goto intout;
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate case 'X':
2960Sstevel@tonic-gate {
297*722Smuffin char *stringp = upperhex;
2980Sstevel@tonic-gate val = va_arg(args.ap, unsigned);
2990Sstevel@tonic-gate bp = buf + MAXDIGS;
3000Sstevel@tonic-gate if (val == 0)
3010Sstevel@tonic-gate goto zero;
3020Sstevel@tonic-gate while (val) {
3030Sstevel@tonic-gate *--bp = stringp[val%16];
3040Sstevel@tonic-gate val /= 16;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate goto intout;
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate case 'x':
3100Sstevel@tonic-gate case 'p':
3110Sstevel@tonic-gate {
312*722Smuffin char *stringp = lowerhex;
3130Sstevel@tonic-gate val = va_arg(args.ap, unsigned);
3140Sstevel@tonic-gate bp = buf + MAXDIGS;
3150Sstevel@tonic-gate if (val == 0)
3160Sstevel@tonic-gate goto zero;
3170Sstevel@tonic-gate while (val) {
3180Sstevel@tonic-gate *--bp = stringp[val%16];
3190Sstevel@tonic-gate val /= 16;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate goto intout;
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate case 'O':
3250Sstevel@tonic-gate case 'o':
3260Sstevel@tonic-gate {
327*722Smuffin char *stringp = lowerhex;
3280Sstevel@tonic-gate val = va_arg(args.ap, unsigned);
3290Sstevel@tonic-gate bp = buf + MAXDIGS;
3300Sstevel@tonic-gate if (val == 0)
3310Sstevel@tonic-gate goto zero;
3320Sstevel@tonic-gate while (val) {
3330Sstevel@tonic-gate *--bp = stringp[val%8];
3340Sstevel@tonic-gate val /= 8;
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate /* Common code to output integers */
3380Sstevel@tonic-gate intout:
3390Sstevel@tonic-gate p = buf + MAXDIGS;
3400Sstevel@tonic-gate while (bp < p) {
3410Sstevel@tonic-gate c = *bp++;
3420Sstevel@tonic-gate emitchar(c);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate continue;
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate zero:
3470Sstevel@tonic-gate c = '0';
3480Sstevel@tonic-gate goto emitc;
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate default:
3510Sstevel@tonic-gate /*
3520Sstevel@tonic-gate * let AT&T deal with it
3530Sstevel@tonic-gate */
3540Sstevel@tonic-gate cp-= 2;
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate Lsize = 0; /* Not long double unless we say so. */
3580Sstevel@tonic-gate /* Scan the <flags> */
3590Sstevel@tonic-gate fplus = 0;
3600Sstevel@tonic-gate fminus = 0;
3610Sstevel@tonic-gate fblank = 0;
3620Sstevel@tonic-gate fsharp = 0;
3630Sstevel@tonic-gate #if FZERO
3640Sstevel@tonic-gate ansi_fzero = 0;
3650Sstevel@tonic-gate compat_fzero = 0;
3660Sstevel@tonic-gate #endif
3670Sstevel@tonic-gate scan: switch (*++cp) {
3680Sstevel@tonic-gate case '+':
3690Sstevel@tonic-gate fplus = 1;
3700Sstevel@tonic-gate goto scan;
3710Sstevel@tonic-gate case '-':
3720Sstevel@tonic-gate fminus = 1;
3730Sstevel@tonic-gate goto scan;
3740Sstevel@tonic-gate case ' ':
3750Sstevel@tonic-gate fblank = 1;
3760Sstevel@tonic-gate goto scan;
3770Sstevel@tonic-gate case '#':
3780Sstevel@tonic-gate fsharp = 1;
3790Sstevel@tonic-gate goto scan;
3800Sstevel@tonic-gate #if FZERO
3810Sstevel@tonic-gate case '0':
3820Sstevel@tonic-gate ansi_fzero = 1;
3830Sstevel@tonic-gate compat_fzero = 1;
3840Sstevel@tonic-gate goto scan;
3850Sstevel@tonic-gate #endif
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /* Scan the field width */
3890Sstevel@tonic-gate if (*cp == '*') {
3900Sstevel@tonic-gate char *p;
3910Sstevel@tonic-gate int val;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate p = _check_dol(cp+1, &val);
3940Sstevel@tonic-gate if (p != (char *)NULL) {
3950Sstevel@tonic-gate /*
3960Sstevel@tonic-gate * argument re-order
3970Sstevel@tonic-gate */
3980Sstevel@tonic-gate if (fpos) {
3990Sstevel@tonic-gate _mkarglst(sformat, sargs, arglst);
4000Sstevel@tonic-gate fpos = 0;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate if (val <= MAXARGS) {
4030Sstevel@tonic-gate args_width = arglst[val - 1];
4040Sstevel@tonic-gate } else {
4050Sstevel@tonic-gate args_width = arglst[MAXARGS - 1];
4060Sstevel@tonic-gate _getarg(sformat, &args_width, val);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate width = va_arg(args_width.ap, int);
4090Sstevel@tonic-gate if (width < 0) {
4100Sstevel@tonic-gate width = -width;
4110Sstevel@tonic-gate fminus = 1;
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate cp = p;
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate else {
4160Sstevel@tonic-gate width = va_arg(args.ap, int);
4170Sstevel@tonic-gate if (width < 0) {
4180Sstevel@tonic-gate width = -width;
4190Sstevel@tonic-gate fminus = 1;
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate cp++;
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate } else {
4240Sstevel@tonic-gate index = width = 0;
4250Sstevel@tonic-gate while (isdigit(*cp)) {
4260Sstevel@tonic-gate n = tonumber(*cp++);
4270Sstevel@tonic-gate index = width = width * 10 + n;
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /* Scan the precision */
4320Sstevel@tonic-gate if (*cp == '.') {
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate /* '*' instead of digits? */
4350Sstevel@tonic-gate if (*++cp == '*') {
4360Sstevel@tonic-gate char *p;
4370Sstevel@tonic-gate int val;
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate p = _check_dol(cp+1, &val);
4400Sstevel@tonic-gate if (p != (char *)NULL) {
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate * argument re-order
4430Sstevel@tonic-gate */
4440Sstevel@tonic-gate if (fpos) {
4450Sstevel@tonic-gate _mkarglst(sformat, sargs, arglst);
4460Sstevel@tonic-gate fpos = 0;
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate if (val <= MAXARGS) {
4490Sstevel@tonic-gate args_prec = arglst[val - 1];
4500Sstevel@tonic-gate } else {
4510Sstevel@tonic-gate args_prec = arglst[MAXARGS - 1];
4520Sstevel@tonic-gate _getarg(sformat, &args_prec, val);
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate prec = va_arg(args_prec.ap, int);
4550Sstevel@tonic-gate cp = p;
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate else {
4580Sstevel@tonic-gate prec = va_arg(args.ap, int);
4590Sstevel@tonic-gate cp++;
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate } else {
4620Sstevel@tonic-gate prec = 0;
4630Sstevel@tonic-gate while (isdigit(*cp)) {
4640Sstevel@tonic-gate n = tonumber(*cp++);
4650Sstevel@tonic-gate prec = prec * 10 + n;
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate } else
4690Sstevel@tonic-gate prec = -1;
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate if (*cp == '$') {
4720Sstevel@tonic-gate if (fpos) {
4730Sstevel@tonic-gate _mkarglst(sformat, sargs, arglst);
4740Sstevel@tonic-gate fpos = 0;
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate if (index <= MAXARGS) {
4770Sstevel@tonic-gate args = arglst[index - 1];
4780Sstevel@tonic-gate } else {
4790Sstevel@tonic-gate args = arglst[MAXARGS - 1];
4800Sstevel@tonic-gate _getarg(sformat, &args, index);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate goto scan;
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate /*
4850Sstevel@tonic-gate * The character addressed by cp must be the
4860Sstevel@tonic-gate * format letter -- there is nothing left for
4870Sstevel@tonic-gate * it to be.
4880Sstevel@tonic-gate *
4890Sstevel@tonic-gate * The status of the +, -, #, blank, and 0
4900Sstevel@tonic-gate * flags are reflected in the variables
4910Sstevel@tonic-gate * "fplus", "fminus", "fsharp", "fblank",
4920Sstevel@tonic-gate * and "ansi_fzero"/"compat_fzero", respectively.
4930Sstevel@tonic-gate * "width" and "prec" contain numbers
4940Sstevel@tonic-gate * corresponding to the digit strings
4950Sstevel@tonic-gate * before and after the decimal point,
4960Sstevel@tonic-gate * respectively. If there was no decimal
4970Sstevel@tonic-gate * point, "prec" is -1.
4980Sstevel@tonic-gate *
4990Sstevel@tonic-gate * The following switch sets things up
5000Sstevel@tonic-gate * for printing. What ultimately gets
5010Sstevel@tonic-gate * printed will be padding blanks, a prefix,
5020Sstevel@tonic-gate * left padding zeroes, a value, right padding
5030Sstevel@tonic-gate * zeroes, a suffix, and more padding
5040Sstevel@tonic-gate * blanks. Padding blanks will not appear
5050Sstevel@tonic-gate * simultaneously on both the left and the
5060Sstevel@tonic-gate * right. Each case in this switch will
5070Sstevel@tonic-gate * compute the value, and leave in several
5080Sstevel@tonic-gate * variables the information necessary to
5090Sstevel@tonic-gate * construct what is to be printed.
5100Sstevel@tonic-gate *
5110Sstevel@tonic-gate * The prefix is a sign, a blank, "0x", "0X",
5120Sstevel@tonic-gate * or null, and is addressed by "prefix".
5130Sstevel@tonic-gate *
5140Sstevel@tonic-gate * The suffix is either null or an exponent,
5150Sstevel@tonic-gate * and is addressed by "suffix".
5160Sstevel@tonic-gate *
5170Sstevel@tonic-gate * The value to be printed starts at "bp"
5180Sstevel@tonic-gate * and continues up to and not including "p".
5190Sstevel@tonic-gate *
5200Sstevel@tonic-gate * "lzero" and "rzero" will contain the number
5210Sstevel@tonic-gate * of padding zeroes required on the left
5220Sstevel@tonic-gate * and right, respectively. If either of
5230Sstevel@tonic-gate * these variables is negative, it will be
5240Sstevel@tonic-gate * treated as if it were zero.
5250Sstevel@tonic-gate *
5260Sstevel@tonic-gate * The number of padding blanks, and whether
5270Sstevel@tonic-gate * they go on the left or the right, will be
5280Sstevel@tonic-gate * computed on exit from the switch.
5290Sstevel@tonic-gate */
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate lzero = 0;
5320Sstevel@tonic-gate prefix = "";
5330Sstevel@tonic-gate #if FLOAT
5340Sstevel@tonic-gate rzero = 0;
5350Sstevel@tonic-gate suffix = prefix;
5360Sstevel@tonic-gate #endif
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate #if FZERO
5390Sstevel@tonic-gate /* if both zero-padding and left-justify flags
5400Sstevel@tonic-gate * are used, ignore zero-padding, per ansi c
5410Sstevel@tonic-gate */
5420Sstevel@tonic-gate if (ansi_fzero & fminus) {
5430Sstevel@tonic-gate ansi_fzero = 0;
5440Sstevel@tonic-gate compat_fzero = 0;
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate /* if zero-padding and precision are specified,
5480Sstevel@tonic-gate * ignore zero-padding for ansi-dictated formats,
5490Sstevel@tonic-gate * per ansi c
5500Sstevel@tonic-gate */
5510Sstevel@tonic-gate if (ansi_fzero & (prec != -1)) ansi_fzero = 0;
5520Sstevel@tonic-gate #endif
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate next:
5550Sstevel@tonic-gate switch (fcode = *cp++) {
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate /* toss the length modifier, if any */
5580Sstevel@tonic-gate case 'l':
5590Sstevel@tonic-gate case 'h':
5600Sstevel@tonic-gate goto next;
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate case 'L':
5630Sstevel@tonic-gate Lsize = 1; /* Remember long double size. */
5640Sstevel@tonic-gate goto next;
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * fixed point representations
5680Sstevel@tonic-gate *
5690Sstevel@tonic-gate * "radix" is the radix for the conversion.
5700Sstevel@tonic-gate * Conversion is unsigned unless fcode is 'd'.
5710Sstevel@tonic-gate * We assume a 2's complement machine and
5720Sstevel@tonic-gate * that fixed point overflow (from negating
5730Sstevel@tonic-gate * the largest negative int) is ignored.
5740Sstevel@tonic-gate */
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate case 'i':
5770Sstevel@tonic-gate case 'D':
5780Sstevel@tonic-gate case 'U':
5790Sstevel@tonic-gate case 'd':
5800Sstevel@tonic-gate case 'u':
5810Sstevel@tonic-gate radix = 10;
5820Sstevel@tonic-gate goto fixed;
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate case 'O':
5850Sstevel@tonic-gate case 'o':
5860Sstevel@tonic-gate radix = 8;
5870Sstevel@tonic-gate goto fixed;
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate case 'X':
5900Sstevel@tonic-gate case 'x':
5910Sstevel@tonic-gate radix = 16;
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate fixed:
5940Sstevel@tonic-gate /* Establish default precision */
5950Sstevel@tonic-gate if (prec < 0)
5960Sstevel@tonic-gate prec = 1;
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /* Fetch the argument to be printed */
5990Sstevel@tonic-gate val = va_arg(args.ap, unsigned);
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate /* If signed conversion, establish sign */
6020Sstevel@tonic-gate if (fcode == 'd' || fcode == 'D' || fcode == 'i') {
6030Sstevel@tonic-gate if ((long) val < 0) {
6040Sstevel@tonic-gate prefix = "-";
6050Sstevel@tonic-gate val = -val;
6060Sstevel@tonic-gate } else if (fplus)
6070Sstevel@tonic-gate prefix = "+";
6080Sstevel@tonic-gate else if (fblank)
6090Sstevel@tonic-gate prefix = " ";
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate /* Set translate table for digits */
6120Sstevel@tonic-gate {
613*722Smuffin char *stringp;
6140Sstevel@tonic-gate if (fcode == 'X')
6150Sstevel@tonic-gate stringp = upperhex;
6160Sstevel@tonic-gate else
6170Sstevel@tonic-gate stringp = lowerhex;
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate /* Develop the digits of the value */
6200Sstevel@tonic-gate bp = buf + MAXDIGS;
6210Sstevel@tonic-gate switch(radix) {
6220Sstevel@tonic-gate case 8: /*octal*/
6230Sstevel@tonic-gate while (val) {
6240Sstevel@tonic-gate *--bp = stringp[val%8];
6250Sstevel@tonic-gate val /= 8;
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate break;
6280Sstevel@tonic-gate case 16:/*hex*/
6290Sstevel@tonic-gate while (val) {
6300Sstevel@tonic-gate *--bp = stringp[val%16];
6310Sstevel@tonic-gate val /= 16;
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate break;
6340Sstevel@tonic-gate default:
6350Sstevel@tonic-gate while (val) {
6360Sstevel@tonic-gate *--bp = stringp[val%10];
6370Sstevel@tonic-gate val /= 10;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate break;
6400Sstevel@tonic-gate } /* switch */
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate /* Calculate padding zero requirement */
6440Sstevel@tonic-gate p = buf + MAXDIGS;
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate /* Handle the # flag */
6470Sstevel@tonic-gate if (fsharp && bp != p) {
6480Sstevel@tonic-gate switch (fcode) {
6490Sstevel@tonic-gate case 'x':
6500Sstevel@tonic-gate prefix = "0x";
6510Sstevel@tonic-gate break;
6520Sstevel@tonic-gate case 'X':
6530Sstevel@tonic-gate prefix = "0X";
6540Sstevel@tonic-gate break;
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate #if FZERO
6580Sstevel@tonic-gate if (ansi_fzero) {
6590Sstevel@tonic-gate n = width - strlen(prefix);
6600Sstevel@tonic-gate if (n > prec)
6610Sstevel@tonic-gate prec = n;
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate #endif
6640Sstevel@tonic-gate lzero = bp - p + prec;
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate /* Handle the # flag for 'o' */
6670Sstevel@tonic-gate if (fsharp && bp != p && fcode == 'o' &&
6680Sstevel@tonic-gate lzero < 1) {
6690Sstevel@tonic-gate lzero = 1;
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate break;
6720Sstevel@tonic-gate #if FLOAT
6730Sstevel@tonic-gate
674*722Smuffin #if defined(__sparc)
6750Sstevel@tonic-gate #define GETQVAL /* Sun-4 macro to get a quad q from the argument list, passed as a pointer. */ \
6760Sstevel@tonic-gate { qval = *(va_arg(args.ap, quadruple*)) ; }
6770Sstevel@tonic-gate #else
6780Sstevel@tonic-gate #define GETQVAL /* Sun-3 macro to get a quad q from the argument list, passed as a value. */ \
6790Sstevel@tonic-gate { int iq ; unsigned long * pl = (unsigned long *) (&qval) ; for(iq=0;iq<4;iq++) pl[iq] = (unsigned long) va_arg(args.ap, unsigned long) ; }
6800Sstevel@tonic-gate #endif
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate case 'E':
6830Sstevel@tonic-gate case 'e':
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate * E-format. The general strategy
6860Sstevel@tonic-gate * here is fairly easy: we take
6870Sstevel@tonic-gate * what econvert gives us and re-format it.
6880Sstevel@tonic-gate */
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate /* Establish default precision */
6910Sstevel@tonic-gate if (prec < 0)
6920Sstevel@tonic-gate prec = 6;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /* Fetch the value */
6950Sstevel@tonic-gate if (Lsize == 0) { /* Double */
6960Sstevel@tonic-gate dval = va_arg(args.ap, double);
6970Sstevel@tonic-gate bp = econvert(dval, prec + 1, &decpt, &sign, convertbuffer);
6980Sstevel@tonic-gate } else { /* Long Double = quadruple */
6990Sstevel@tonic-gate GETQVAL;
7000Sstevel@tonic-gate bp = qeconvert(&qval, prec + 1, &decpt, &sign, convertbuffer);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate /* Determine the prefix */
7040Sstevel@tonic-gate if (sign)
7050Sstevel@tonic-gate prefix = "-";
7060Sstevel@tonic-gate else if (fplus)
7070Sstevel@tonic-gate prefix = "+";
7080Sstevel@tonic-gate else if (fblank)
7090Sstevel@tonic-gate prefix = " ";
7100Sstevel@tonic-gate if (convertbuffer[0] > '9')
7110Sstevel@tonic-gate { /* handle infinity, nan */
7120Sstevel@tonic-gate bp = &convertbuffer[0];
7130Sstevel@tonic-gate for (p = bp+1 ; *p != 0 ; p++) ;
7140Sstevel@tonic-gate goto ebreak ;
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate {
717*722Smuffin char *stringp;
7180Sstevel@tonic-gate /* Place the first digit in the buffer */
7190Sstevel@tonic-gate stringp = &buf[0];
7200Sstevel@tonic-gate *stringp++ = *bp != '\0'? *bp++: '0';
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate /* Put in a decimal point if needed */
7230Sstevel@tonic-gate if (prec != 0 || fsharp)
7240Sstevel@tonic-gate *stringp++ = decpt_char;
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate /* Create the rest of the mantissa */
7270Sstevel@tonic-gate rzero = prec;
7280Sstevel@tonic-gate while (rzero > 0 && *bp!= '\0') {
7290Sstevel@tonic-gate --rzero;
7300Sstevel@tonic-gate *stringp++ = *bp++;
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate p = stringp;
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate bp = &buf[0];
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate /* Create the exponent */
7380Sstevel@tonic-gate if (convertbuffer[0] != '0')
7390Sstevel@tonic-gate n = decpt - 1;
7400Sstevel@tonic-gate else
7410Sstevel@tonic-gate n = 0 ;
7420Sstevel@tonic-gate if (n < 0)
7430Sstevel@tonic-gate n = -n;
7440Sstevel@tonic-gate _fourdigitsquick( (short unsigned) n, &(expbuf[2]) ) ;
7450Sstevel@tonic-gate expbuf[6] = 0 ;
7460Sstevel@tonic-gate if (n < 100)
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate * Normally two digit exponent field,
7490Sstevel@tonic-gate * three or four if required.
7500Sstevel@tonic-gate */
7510Sstevel@tonic-gate { suffix = &(expbuf[4]) ; suffixlength = 4 ; }
7520Sstevel@tonic-gate else if (n < 1000)
7530Sstevel@tonic-gate { suffix = &(expbuf[3]) ; suffixlength = 5 ; }
7540Sstevel@tonic-gate else
7550Sstevel@tonic-gate { suffix = &(expbuf[2]) ; suffixlength = 6 ; }
7560Sstevel@tonic-gate /* Put in the exponent sign */
7570Sstevel@tonic-gate *--suffix = (decpt > 0 || convertbuffer[0] == '0' )? '+': '-';
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate /* Put in the e; note kludge in 'g' format */
7600Sstevel@tonic-gate *--suffix = fcode;
7610Sstevel@tonic-gate ebreak:
7620Sstevel@tonic-gate #if FZERO
7630Sstevel@tonic-gate if (compat_fzero &! fminus)
7640Sstevel@tonic-gate /* Calculate padding zero requirement */
7650Sstevel@tonic-gate lzero = width - (strlen(prefix)
7660Sstevel@tonic-gate + (p - buf) + rzero + suffixlength);
7670Sstevel@tonic-gate #endif
7680Sstevel@tonic-gate break;
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate case 'f':
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate * F-format floating point. This is
7730Sstevel@tonic-gate * a good deal less simple than E-format.
7740Sstevel@tonic-gate * The overall strategy will be to call
7750Sstevel@tonic-gate * fconvert, reformat its result into buf,
7760Sstevel@tonic-gate * and calculate how many trailing
7770Sstevel@tonic-gate * zeroes will be required. There will
7780Sstevel@tonic-gate * never be any leading zeroes needed.
7790Sstevel@tonic-gate */
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate /* Establish default precision */
7820Sstevel@tonic-gate if (prec < 0)
7830Sstevel@tonic-gate prec = 6;
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate if (Lsize == 0) {
7860Sstevel@tonic-gate dval = va_arg(args.ap, double);
7870Sstevel@tonic-gate bp = fconvert(dval, prec, &decpt, &sign, convertbuffer);
7880Sstevel@tonic-gate } else {
7890Sstevel@tonic-gate GETQVAL ;
7900Sstevel@tonic-gate bp = qfconvert(&qval, prec, &decpt, &sign, convertbuffer);
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate /* Determine the prefix */
7940Sstevel@tonic-gate if (sign)
7950Sstevel@tonic-gate prefix = "-";
7960Sstevel@tonic-gate else if (fplus)
7970Sstevel@tonic-gate prefix = "+";
7980Sstevel@tonic-gate else if (fblank)
7990Sstevel@tonic-gate prefix = " ";
8000Sstevel@tonic-gate if (convertbuffer[0] > '9')
8010Sstevel@tonic-gate { /* handle infinity, nan */
8020Sstevel@tonic-gate bp = &convertbuffer[0];
8030Sstevel@tonic-gate for (p = bp+1 ; *p != 0 ; p++) ;
8040Sstevel@tonic-gate goto fbreak ;
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate {
807*722Smuffin char *stringp;
8080Sstevel@tonic-gate /* Initialize buffer pointer */
8090Sstevel@tonic-gate stringp = &buf[0];
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate /* Emit the digits before the decimal point */
8120Sstevel@tonic-gate n = decpt;
8130Sstevel@tonic-gate if (n <= 0)
8140Sstevel@tonic-gate *stringp++ = '0';
8150Sstevel@tonic-gate else
8160Sstevel@tonic-gate do
8170Sstevel@tonic-gate if (*bp == '\0' )
8180Sstevel@tonic-gate *stringp++ = '0';
8190Sstevel@tonic-gate else {
8200Sstevel@tonic-gate *stringp++ = *bp++;
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate while (--n != 0);
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate /* Decide whether we need a decimal point */
8250Sstevel@tonic-gate if (fsharp || prec > 0)
8260Sstevel@tonic-gate *stringp++ = decpt_char;
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate /* Digits(if any) after the decimal point */
8290Sstevel@tonic-gate n = prec;
8300Sstevel@tonic-gate rzero = prec - n;
8310Sstevel@tonic-gate while (--n >= 0) {
8320Sstevel@tonic-gate if (++decpt <= 0 || *bp == '\0')
8330Sstevel@tonic-gate *stringp++ = '0';
8340Sstevel@tonic-gate else {
8350Sstevel@tonic-gate *stringp++ = *bp++;
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate #if FZERO
8390Sstevel@tonic-gate if (compat_fzero &! fminus)
8400Sstevel@tonic-gate /* Calculate padding zero requirement */
8410Sstevel@tonic-gate lzero = width - (strlen(prefix)
8420Sstevel@tonic-gate + (stringp - buf) + rzero);
8430Sstevel@tonic-gate #endif
8440Sstevel@tonic-gate p = stringp;
8450Sstevel@tonic-gate }
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate bp = &buf[0];
8480Sstevel@tonic-gate fbreak:
8490Sstevel@tonic-gate break;
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate case 'G':
8520Sstevel@tonic-gate case 'g':
8530Sstevel@tonic-gate /*
8540Sstevel@tonic-gate * g-format. We play around a bit
8550Sstevel@tonic-gate * and then jump into e or f, as needed.
8560Sstevel@tonic-gate */
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate /* Establish default precision */
8590Sstevel@tonic-gate if (prec < 0)
8600Sstevel@tonic-gate prec = 6;
8610Sstevel@tonic-gate else if (prec == 0)
8620Sstevel@tonic-gate prec = 1;
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate if (Lsize == 0) {
8650Sstevel@tonic-gate dval = va_arg(args.ap, double);
8660Sstevel@tonic-gate bp = gconvert(dval, prec, fsharp, convertbuffer);
8670Sstevel@tonic-gate } else {
8680Sstevel@tonic-gate GETQVAL;
8690Sstevel@tonic-gate bp = qgconvert(&qval, prec, fsharp, convertbuffer);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate bp = convertbuffer ;
8720Sstevel@tonic-gate if (convertbuffer[0] == '-') {
8730Sstevel@tonic-gate prefix = "-" ;
8740Sstevel@tonic-gate bp++;
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate else if (fplus)
8770Sstevel@tonic-gate prefix = "+";
8780Sstevel@tonic-gate else if (fblank)
8790Sstevel@tonic-gate prefix = " ";
8800Sstevel@tonic-gate if (isupper(fcode))
8810Sstevel@tonic-gate { /* Put in a big E for small minds. */
8820Sstevel@tonic-gate for (p = bp ; (*p != NULL) && (*p != 'e') ; p++) ;
8830Sstevel@tonic-gate if (*p == 'e') *p = 'E' ;
8840Sstevel@tonic-gate for (; (*p != NULL) ; p++) ;
8850Sstevel@tonic-gate /* Find end of string. */
8860Sstevel@tonic-gate }
8870Sstevel@tonic-gate else
8880Sstevel@tonic-gate for (p = bp ; *p != NULL ; p++) ;
8890Sstevel@tonic-gate /* Find end of string. */
8900Sstevel@tonic-gate rzero = 0;
8910Sstevel@tonic-gate #if FZERO
8920Sstevel@tonic-gate if (compat_fzero & !fminus)
8930Sstevel@tonic-gate /* Calculate padding zero requirement */
8940Sstevel@tonic-gate lzero = width - (strlen(prefix)
8950Sstevel@tonic-gate + (p - bp) + rzero);
8960Sstevel@tonic-gate #endif
8970Sstevel@tonic-gate break ;
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate #endif
9000Sstevel@tonic-gate case 'c':
9010Sstevel@tonic-gate buf[0] = va_arg(args.ap, int);
9020Sstevel@tonic-gate bp = &buf[0];
9030Sstevel@tonic-gate p = bp + 1;
9040Sstevel@tonic-gate break;
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate case 's':
9070Sstevel@tonic-gate bp = va_arg(args.ap, char *);
9080Sstevel@tonic-gate if (prec < 0)
9090Sstevel@tonic-gate prec = MAXINT;
9100Sstevel@tonic-gate /* avoid *(0) */
9110Sstevel@tonic-gate if (bp == NULL)
9120Sstevel@tonic-gate bp = nullstr;
9130Sstevel@tonic-gate for (n=0; *bp++ != '\0' && n < prec; n++)
9140Sstevel@tonic-gate ;
9150Sstevel@tonic-gate #if FZERO
9160Sstevel@tonic-gate if (compat_fzero &! fminus)
9170Sstevel@tonic-gate lzero = width - n;
9180Sstevel@tonic-gate #endif
9190Sstevel@tonic-gate p = --bp;
9200Sstevel@tonic-gate bp -= n;
9210Sstevel@tonic-gate break;
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate case '\0':
9240Sstevel@tonic-gate /* well, what's the punch line? */
9250Sstevel@tonic-gate goto out;
9260Sstevel@tonic-gate
9270Sstevel@tonic-gate case 'n':
9280Sstevel@tonic-gate svswitch = 1;
9290Sstevel@tonic-gate break;
9300Sstevel@tonic-gate default:
9310Sstevel@tonic-gate p = bp = &fcode;
9320Sstevel@tonic-gate p++;
9330Sstevel@tonic-gate break;
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate /* Calculate number of padding blanks */
9370Sstevel@tonic-gate nblank = width
9380Sstevel@tonic-gate #if FLOAT
9390Sstevel@tonic-gate - (rzero < 0? 0: rzero)
9400Sstevel@tonic-gate - strlen(suffix)
9410Sstevel@tonic-gate #endif
9420Sstevel@tonic-gate - (p - bp)
9430Sstevel@tonic-gate - (lzero < 0? 0: lzero)
9440Sstevel@tonic-gate - strlen(prefix);
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate /* Blanks on left if required */
9470Sstevel@tonic-gate if (!fminus)
9480Sstevel@tonic-gate while (--nblank >= 0)
9490Sstevel@tonic-gate emitchar(' ');
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate /* Prefix, if any */
9520Sstevel@tonic-gate while (*prefix != '\0') {
9530Sstevel@tonic-gate emitchar(*prefix);
9540Sstevel@tonic-gate prefix++;
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate /* Zeroes on the left */
9580Sstevel@tonic-gate while (--lzero >= 0)
9590Sstevel@tonic-gate emitchar('0');
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate /* The value itself */
9620Sstevel@tonic-gate while (bp < p) {
9630Sstevel@tonic-gate emitchar(*bp);
9640Sstevel@tonic-gate bp++;
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate #if FLOAT
9670Sstevel@tonic-gate /* Zeroes on the right */
9680Sstevel@tonic-gate while (--rzero >= 0)
9690Sstevel@tonic-gate emitchar('0');
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate /* The suffix */
9720Sstevel@tonic-gate while (*suffix != '\0') {
9730Sstevel@tonic-gate emitchar(*suffix);
9740Sstevel@tonic-gate suffix++;
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate #endif
9770Sstevel@tonic-gate /* Blanks on the right if required */
9780Sstevel@tonic-gate if (fminus)
9790Sstevel@tonic-gate while (--nblank >= 0)
9800Sstevel@tonic-gate emitchar(' ');
9810Sstevel@tonic-gate /* If %n is seen, save count in argument */
9820Sstevel@tonic-gate if (svswitch == 1) {
9830Sstevel@tonic-gate long *svcount;
9840Sstevel@tonic-gate svcount = va_arg (args.ap, long *);
9850Sstevel@tonic-gate *svcount = count;
9860Sstevel@tonic-gate svswitch = 0;
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate } /* else */
9890Sstevel@tonic-gate } while ((c = *cp++) != '\0'); /* do */
9900Sstevel@tonic-gate out:
9910Sstevel@tonic-gate file->_ptr = fileptr;
9920Sstevel@tonic-gate file->_cnt = filecnt;
9930Sstevel@tonic-gate if (file->_flag & (_IONBF | _IOLBF) &&
9940Sstevel@tonic-gate (file->_flag & _IONBF ||
9950Sstevel@tonic-gate memchr((char *)file->_base, '\n', fileptr - file->_base) != NULL))
9960Sstevel@tonic-gate (void) _xflsbuf(file);
9970Sstevel@tonic-gate return (ferror(file)? EOF: count);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate
1000*722Smuffin #if defined(__sparc)
10010Sstevel@tonic-gate /*
10020Sstevel@tonic-gate * We use "double *" instead of "quadruple *" to skip over the pointer to
10030Sstevel@tonic-gate * long double on the argument list since a pointer is a pointer after all.
10040Sstevel@tonic-gate */
10050Sstevel@tonic-gate #define SKIPQVAL { \
10060Sstevel@tonic-gate (void) va_arg(args.ap, double *); \
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate #else /* Sun-3 */
10090Sstevel@tonic-gate #define SKIPQVAL { \
10100Sstevel@tonic-gate int iq; \
10110Sstevel@tonic-gate for (iq = 0; iq < 4; iq++) \
10120Sstevel@tonic-gate (void) va_arg(args.ap, unsigned long); \
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate #endif
1015*722Smuffin /*
1016*722Smuffin * This function initializes arglst, to contain the appropriate va_list values
1017*722Smuffin * for the first MAXARGS arguments.
1018*722Smuffin */
10190Sstevel@tonic-gate void
_mkarglst(char * fmt,stva_list args,stva_list arglst[])1020*722Smuffin _mkarglst(char *fmt, stva_list args, stva_list arglst[])
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate static char *digits = "01234567890", *skips = "# +-.0123456789h$";
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate enum types {INT = 1, LONG, CHAR_PTR, DOUBLE, LONG_DOUBLE, VOID_PTR,
10250Sstevel@tonic-gate LONG_PTR, INT_PTR};
10260Sstevel@tonic-gate enum types typelst[MAXARGS], curtype;
10270Sstevel@tonic-gate int maxnum, n, curargno, flags;
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate * Algorithm 1. set all argument types to zero.
10310Sstevel@tonic-gate * 2. walk through fmt putting arg types in typelst[].
10320Sstevel@tonic-gate * 3. walk through args using va_arg(args.ap, typelst[n])
10330Sstevel@tonic-gate * and set arglst[] to the appropriate values.
10340Sstevel@tonic-gate * Assumptions: Cannot use %*$... to specify variable position.
10350Sstevel@tonic-gate */
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate (void)memset((void *)typelst, 0, sizeof(typelst));
10380Sstevel@tonic-gate maxnum = -1;
10390Sstevel@tonic-gate curargno = 0;
10400Sstevel@tonic-gate while ((fmt = strchr(fmt, '%')) != 0)
10410Sstevel@tonic-gate {
10420Sstevel@tonic-gate fmt++; /* skip % */
10430Sstevel@tonic-gate if (fmt[n = strspn(fmt, digits)] == '$')
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate curargno = atoi(fmt) - 1; /* convert to zero base */
10460Sstevel@tonic-gate fmt += n + 1;
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate flags = 0;
10490Sstevel@tonic-gate again:;
10500Sstevel@tonic-gate fmt += strspn(fmt, skips);
10510Sstevel@tonic-gate switch (*fmt++)
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate case '%': /*there is no argument! */
10540Sstevel@tonic-gate continue;
10550Sstevel@tonic-gate case 'l':
10560Sstevel@tonic-gate flags |= 0x1;
10570Sstevel@tonic-gate goto again;
10580Sstevel@tonic-gate case 'L':
10590Sstevel@tonic-gate flags |= 0x8;
10600Sstevel@tonic-gate goto again;
10610Sstevel@tonic-gate case '*': /* int argument used for value */
10620Sstevel@tonic-gate flags |= 0x2;
10630Sstevel@tonic-gate curtype = INT;
10640Sstevel@tonic-gate break;
10650Sstevel@tonic-gate case 'e':
10660Sstevel@tonic-gate case 'E':
10670Sstevel@tonic-gate case 'f':
10680Sstevel@tonic-gate case 'g':
10690Sstevel@tonic-gate case 'G':
10700Sstevel@tonic-gate if (flags & 0x8)
10710Sstevel@tonic-gate curtype = LONG_DOUBLE;
10720Sstevel@tonic-gate else
10730Sstevel@tonic-gate curtype = DOUBLE;
10740Sstevel@tonic-gate break;
10750Sstevel@tonic-gate case 's':
10760Sstevel@tonic-gate curtype = CHAR_PTR;
10770Sstevel@tonic-gate break;
10780Sstevel@tonic-gate case 'p':
10790Sstevel@tonic-gate curtype = VOID_PTR;
10800Sstevel@tonic-gate break;
10810Sstevel@tonic-gate case 'n':
10820Sstevel@tonic-gate if (flags & 0x1)
10830Sstevel@tonic-gate curtype = LONG_PTR;
10840Sstevel@tonic-gate else
10850Sstevel@tonic-gate curtype = INT_PTR;
10860Sstevel@tonic-gate break;
10870Sstevel@tonic-gate default:
10880Sstevel@tonic-gate if (flags & 0x1)
10890Sstevel@tonic-gate curtype = LONG;
10900Sstevel@tonic-gate else
10910Sstevel@tonic-gate curtype = INT;
10920Sstevel@tonic-gate break;
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate if (curargno >= 0 && curargno < MAXARGS)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate typelst[curargno] = curtype;
10970Sstevel@tonic-gate if (maxnum < curargno)
10980Sstevel@tonic-gate maxnum = curargno;
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate curargno++; /* default to next in list */
11010Sstevel@tonic-gate if (flags & 0x2) /* took care of *, keep going */
11020Sstevel@tonic-gate {
11030Sstevel@tonic-gate flags ^= 0x2;
11040Sstevel@tonic-gate goto again;
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate for (n = 0 ; n <= maxnum; n++)
11080Sstevel@tonic-gate {
11090Sstevel@tonic-gate arglst[n] = args;
11100Sstevel@tonic-gate if (typelst[n] == 0)
11110Sstevel@tonic-gate typelst[n] = INT;
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate switch (typelst[n])
11140Sstevel@tonic-gate {
11150Sstevel@tonic-gate case INT:
11160Sstevel@tonic-gate va_arg(args.ap, int);
11170Sstevel@tonic-gate break;
11180Sstevel@tonic-gate case LONG:
11190Sstevel@tonic-gate va_arg(args.ap, long);
11200Sstevel@tonic-gate break;
11210Sstevel@tonic-gate case CHAR_PTR:
11220Sstevel@tonic-gate va_arg(args.ap, char *);
11230Sstevel@tonic-gate break;
11240Sstevel@tonic-gate case DOUBLE:
11250Sstevel@tonic-gate va_arg(args.ap, double);
11260Sstevel@tonic-gate break;
11270Sstevel@tonic-gate case LONG_DOUBLE:
11280Sstevel@tonic-gate SKIPQVAL
11290Sstevel@tonic-gate break;
11300Sstevel@tonic-gate case VOID_PTR:
11310Sstevel@tonic-gate va_arg(args.ap, void *);
11320Sstevel@tonic-gate break;
11330Sstevel@tonic-gate case LONG_PTR:
11340Sstevel@tonic-gate va_arg(args.ap, long *);
11350Sstevel@tonic-gate break;
11360Sstevel@tonic-gate case INT_PTR:
11370Sstevel@tonic-gate va_arg(args.ap, int *);
11380Sstevel@tonic-gate break;
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate /*
11440Sstevel@tonic-gate * This function is used to find the va_list value for arguments whose
11450Sstevel@tonic-gate * position is greater than MAXARGS. This function is slow, so hopefully
11460Sstevel@tonic-gate * MAXARGS will be big enough so that this function need only be called in
11470Sstevel@tonic-gate * unusual circumstances.
11480Sstevel@tonic-gate * pargs is assumed to contain the value of arglst[MAXARGS - 1].
11490Sstevel@tonic-gate */
11500Sstevel@tonic-gate void
_getarg(char * fmt,stva_list * pargs,int argno)1151*722Smuffin _getarg(char *fmt, stva_list *pargs, int argno)
11520Sstevel@tonic-gate {
11530Sstevel@tonic-gate static char *digits = "01234567890", *skips = "# +-.0123456789h$";
11540Sstevel@tonic-gate int i, n, curargno, flags;
11550Sstevel@tonic-gate char *sfmt = fmt;
11560Sstevel@tonic-gate int found = 1;
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate curargno = i = MAXARGS;
11590Sstevel@tonic-gate while (found)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate fmt = sfmt;
11620Sstevel@tonic-gate found = 0;
11630Sstevel@tonic-gate while ((i != argno) && (fmt = strchr(fmt, '%')) != 0)
11640Sstevel@tonic-gate {
11650Sstevel@tonic-gate fmt++; /* skip % */
11660Sstevel@tonic-gate if (fmt[n = strspn(fmt, digits)] == '$')
11670Sstevel@tonic-gate {
11680Sstevel@tonic-gate curargno = atoi(fmt);
11690Sstevel@tonic-gate fmt += n + 1;
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate
11720Sstevel@tonic-gate /* find conversion specifier for next argument */
11730Sstevel@tonic-gate if (i != curargno)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate curargno++;
11760Sstevel@tonic-gate continue;
11770Sstevel@tonic-gate } else
11780Sstevel@tonic-gate found = 1;
11790Sstevel@tonic-gate flags = 0;
11800Sstevel@tonic-gate again:;
11810Sstevel@tonic-gate fmt += strspn(fmt, skips);
11820Sstevel@tonic-gate switch (*fmt++)
11830Sstevel@tonic-gate {
11840Sstevel@tonic-gate case '%': /*there is no argument! */
11850Sstevel@tonic-gate continue;
11860Sstevel@tonic-gate case 'l':
11870Sstevel@tonic-gate flags |= 0x1;
11880Sstevel@tonic-gate goto again;
11890Sstevel@tonic-gate case 'L':
11900Sstevel@tonic-gate flags |= 0x8;
11910Sstevel@tonic-gate goto again;
11920Sstevel@tonic-gate case '*': /* int argument used for value */
11930Sstevel@tonic-gate flags |= 0x2;
11940Sstevel@tonic-gate (void)va_arg((*pargs).ap, int);
11950Sstevel@tonic-gate break;
11960Sstevel@tonic-gate case 'e':
11970Sstevel@tonic-gate case 'E':
11980Sstevel@tonic-gate case 'f':
11990Sstevel@tonic-gate case 'g':
12000Sstevel@tonic-gate case 'G':
12010Sstevel@tonic-gate if (flags & 0x8) {
12020Sstevel@tonic-gate #define args (*pargs)
12030Sstevel@tonic-gate SKIPQVAL
12040Sstevel@tonic-gate #undef args
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate else
12070Sstevel@tonic-gate (void)va_arg((*pargs).ap, double);
12080Sstevel@tonic-gate break;
12090Sstevel@tonic-gate case 's':
12100Sstevel@tonic-gate (void)va_arg((*pargs).ap, char *);
12110Sstevel@tonic-gate break;
12120Sstevel@tonic-gate case 'p':
12130Sstevel@tonic-gate (void)va_arg((*pargs).ap, void *);
12140Sstevel@tonic-gate break;
12150Sstevel@tonic-gate case 'n':
12160Sstevel@tonic-gate if (flags & 0x1)
12170Sstevel@tonic-gate (void)va_arg((*pargs).ap, long *);
12180Sstevel@tonic-gate else
12190Sstevel@tonic-gate (void)va_arg((*pargs).ap, int *);
12200Sstevel@tonic-gate break;
12210Sstevel@tonic-gate default:
12220Sstevel@tonic-gate if (flags & 0x1)
12230Sstevel@tonic-gate (void)va_arg((*pargs).ap, long int);
12240Sstevel@tonic-gate else
12250Sstevel@tonic-gate (void)va_arg((*pargs).ap, int);
12260Sstevel@tonic-gate break;
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate i++;
12290Sstevel@tonic-gate curargno++; /* default to next in list */
12300Sstevel@tonic-gate if (flags & 0x2) /* took care of *, keep going */
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate flags ^= 0x2;
12330Sstevel@tonic-gate goto again;
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate /* missing specifier for parameter, assume parameter is an int */
12380Sstevel@tonic-gate if (!found && i != argno) {
12390Sstevel@tonic-gate (void)va_arg((*pargs).ap, int);
12400Sstevel@tonic-gate i++;
12410Sstevel@tonic-gate curargno++;
12420Sstevel@tonic-gate found = 1;
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate }
12460Sstevel@tonic-gate
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate * parse a string, mini parse
12500Sstevel@tonic-gate */
12510Sstevel@tonic-gate static char *
_check_dol(char * s,int * val)1252*722Smuffin _check_dol(char *s, int *val)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate char *os; /* save old string */
12550Sstevel@tonic-gate int tmp_val = 0;
12560Sstevel@tonic-gate int flag = 0;
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate while (isdigit (*s)) {
12590Sstevel@tonic-gate ++flag;
12600Sstevel@tonic-gate tmp_val = tmp_val*10 + *s - '0';
12610Sstevel@tonic-gate s++;
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate if (flag == 0)
12640Sstevel@tonic-gate return ((char *)NULL);
12650Sstevel@tonic-gate if (*s == '$') {
12660Sstevel@tonic-gate *val = tmp_val;
12670Sstevel@tonic-gate return(++s);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate return ((char *)NULL);
12700Sstevel@tonic-gate }
1271