10Sstevel@tonic-gate /*
2*356Smuffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
70Sstevel@tonic-gate /* All Rights Reserved */
80Sstevel@tonic-gate
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California.
110Sstevel@tonic-gate * All rights reserved. The Berkeley Software License Agreement
120Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
130Sstevel@tonic-gate */
140Sstevel@tonic-gate
150Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
160Sstevel@tonic-gate
170Sstevel@tonic-gate /*
180Sstevel@tonic-gate * Hacked "printf" which prints through putbyte and Putchar.
190Sstevel@tonic-gate * putbyte() is used to send a pure byte, which might be a part
200Sstevel@tonic-gate * of a mutlibyte character, mainly for %s. A control character
210Sstevel@tonic-gate * for putbyte() may be QUOTE'd meaning not to convert it to ^x
220Sstevel@tonic-gate * sequence. In all other cases Putchar() is used to send a character
230Sstevel@tonic-gate * in tchar (== wchar_t + * optional QUOE.)
240Sstevel@tonic-gate * DONT USE WITH STDIO!
250Sstevel@tonic-gate * This printf has been hacked again so that it understands tchar string
260Sstevel@tonic-gate * when the format specifier %t is used. Also %c has been expanded
270Sstevel@tonic-gate * to take a tchar character as well as normal int.
280Sstevel@tonic-gate * %t is supported in its simplest form; no width or precision will
290Sstevel@tonic-gate * be understood.
300Sstevel@tonic-gate * Assumption here is that sizeof(tchar)<=sizeof(int) so that tchar is
310Sstevel@tonic-gate * passed as int. Otherwise, %T must be specified instead of %c to
320Sstevel@tonic-gate * print a character in tchar.
330Sstevel@tonic-gate */
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include <stdarg.h>
360Sstevel@tonic-gate #include <values.h>
370Sstevel@tonic-gate #include "sh.h" /* For tchar. */
380Sstevel@tonic-gate
390Sstevel@tonic-gate #define HIBITLL (1ULL << 63)
400Sstevel@tonic-gate
410Sstevel@tonic-gate void _print(char *format, va_list *args);
420Sstevel@tonic-gate
430Sstevel@tonic-gate static char *p;
440Sstevel@tonic-gate
450Sstevel@tonic-gate int
printf(const char * format,...)460Sstevel@tonic-gate printf(const char *format, ...)
470Sstevel@tonic-gate {
480Sstevel@tonic-gate va_list stupid;
490Sstevel@tonic-gate
500Sstevel@tonic-gate p = (char *)gettext(format);
510Sstevel@tonic-gate va_start(stupid, format);
520Sstevel@tonic-gate _print(p, &stupid);
530Sstevel@tonic-gate va_end(stupid);
54*356Smuffin
55*356Smuffin return (0);
560Sstevel@tonic-gate }
570Sstevel@tonic-gate
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate * Floating-point code is included or not, depending
600Sstevel@tonic-gate * on whether the preprocessor variable FLOAT is 1 or 0.
610Sstevel@tonic-gate */
620Sstevel@tonic-gate
630Sstevel@tonic-gate /* Maximum number of digits in any integer (long) representation */
640Sstevel@tonic-gate #define MAXDIGS 20
650Sstevel@tonic-gate
660Sstevel@tonic-gate /* Convert a digit character to the corresponding number */
670Sstevel@tonic-gate #define tonumber(x) ((x) - '0')
680Sstevel@tonic-gate
690Sstevel@tonic-gate /* Convert a number between 0 and 9 to the corresponding digit */
700Sstevel@tonic-gate #define todigit(x) ((x) + '0')
710Sstevel@tonic-gate
720Sstevel@tonic-gate /* Maximum total number of digits in E format */
730Sstevel@tonic-gate #define MAXECVT 17
740Sstevel@tonic-gate
750Sstevel@tonic-gate /* Maximum number of digits after decimal point in F format */
760Sstevel@tonic-gate #define MAXFCVT 60
770Sstevel@tonic-gate
780Sstevel@tonic-gate /* Maximum significant figures in a floating-point number */
790Sstevel@tonic-gate #define MAXFSIG 17
800Sstevel@tonic-gate
810Sstevel@tonic-gate /* Maximum number of characters in an exponent */
820Sstevel@tonic-gate #define MAXESIZ 4
830Sstevel@tonic-gate
840Sstevel@tonic-gate /* Maximum (positive) exponent or greater */
850Sstevel@tonic-gate #define MAXEXP 40
860Sstevel@tonic-gate
870Sstevel@tonic-gate
880Sstevel@tonic-gate
890Sstevel@tonic-gate #define max(a, b) ((a) > (b) ? (a) : (b))
900Sstevel@tonic-gate #define min(a, b) ((a) < (b) ? (a) : (b))
910Sstevel@tonic-gate
920Sstevel@tonic-gate /* If this symbol is nonzero, allow '0' as a flag */
930Sstevel@tonic-gate #define FZERO 1
940Sstevel@tonic-gate
950Sstevel@tonic-gate #if FLOAT
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate * System-supplied routines for floating conversion
980Sstevel@tonic-gate */
990Sstevel@tonic-gate char *fcvt();
1000Sstevel@tonic-gate char *ecvt();
1010Sstevel@tonic-gate #endif
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate void
_print(char * format,va_list * args)1040Sstevel@tonic-gate _print(char *format, va_list *args)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate /* Current position in format */
1070Sstevel@tonic-gate char *cp;
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /* Starting and ending points for value to be printed */
1100Sstevel@tonic-gate char *bp, *p;
1110Sstevel@tonic-gate tchar *tbp, *tep; /* For "%t". */
1120Sstevel@tonic-gate tchar tcbuf[2]; /* For "%c" or "%T". */
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate /* Field width and precision */
1150Sstevel@tonic-gate int width, prec;
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /* Format code */
1180Sstevel@tonic-gate char fcode;
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /* Number of padding zeroes required on the left */
1210Sstevel@tonic-gate int lzero;
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /* Flags - nonzero if corresponding character appears in format */
1240Sstevel@tonic-gate bool length; /* l */
1250Sstevel@tonic-gate bool double_length; /* ll */
1260Sstevel@tonic-gate bool fplus; /* + */
1270Sstevel@tonic-gate bool fminus; /* - */
1280Sstevel@tonic-gate bool fblank; /* blank */
1290Sstevel@tonic-gate bool fsharp; /* # */
1300Sstevel@tonic-gate #if FZERO
1310Sstevel@tonic-gate bool fzero; /* 0 */
1320Sstevel@tonic-gate #endif
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /* Pointer to sign, "0x", "0X", or empty */
1350Sstevel@tonic-gate char *prefix;
1360Sstevel@tonic-gate #if FLOAT
1370Sstevel@tonic-gate /* Exponent or empty */
1380Sstevel@tonic-gate char *suffix;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate /* Buffer to create exponent */
1410Sstevel@tonic-gate char expbuf[MAXESIZ + 1];
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /* Number of padding zeroes required on the right */
1440Sstevel@tonic-gate int rzero;
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate /* The value being converted, if real */
1470Sstevel@tonic-gate double dval;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /* Output values from fcvt and ecvt */
1500Sstevel@tonic-gate int decpt, sign;
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /* Scratch */
1530Sstevel@tonic-gate int k;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate /* Values are developed in this buffer */
1560Sstevel@tonic-gate char buf[max(MAXDIGS, max(MAXFCVT + DMAXEXP, MAXECVT) + 1)];
1570Sstevel@tonic-gate #else
1580Sstevel@tonic-gate char buf[MAXDIGS];
1590Sstevel@tonic-gate #endif
1600Sstevel@tonic-gate /* The value being converted, if integer */
1610Sstevel@tonic-gate long long val;
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate /* Set to point to a translate table for digits of whatever radix */
1640Sstevel@tonic-gate char *tab;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate /* Work variables */
1670Sstevel@tonic-gate int n, hradix, lowbit;
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate cp = format;
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate * The main loop -- this loop goes through one iteration
1730Sstevel@tonic-gate * for each ordinary character or format specification.
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate while (*cp)
1760Sstevel@tonic-gate if (*cp != '%') {
1770Sstevel@tonic-gate /* Ordinary (non-%) character */
1780Sstevel@tonic-gate putbyte (*cp++);
1790Sstevel@tonic-gate } else {
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate * % has been found.
1820Sstevel@tonic-gate * First, parse the format specification.
1830Sstevel@tonic-gate */
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate /* Scan the <flags> */
1860Sstevel@tonic-gate fplus = fminus = fblank = fsharp = 0;
1870Sstevel@tonic-gate #if FZERO
1880Sstevel@tonic-gate fzero = 0;
1890Sstevel@tonic-gate #endif
1900Sstevel@tonic-gate scan:
1910Sstevel@tonic-gate switch (*++cp) {
1920Sstevel@tonic-gate case '+':
1930Sstevel@tonic-gate fplus = 1;
1940Sstevel@tonic-gate goto scan;
1950Sstevel@tonic-gate case '-':
1960Sstevel@tonic-gate fminus = 1;
1970Sstevel@tonic-gate goto scan;
1980Sstevel@tonic-gate case ' ':
1990Sstevel@tonic-gate fblank = 1;
2000Sstevel@tonic-gate goto scan;
2010Sstevel@tonic-gate case '#':
2020Sstevel@tonic-gate fsharp = 1;
2030Sstevel@tonic-gate goto scan;
2040Sstevel@tonic-gate #if FZERO
2050Sstevel@tonic-gate case '0':
2060Sstevel@tonic-gate fzero = 1;
2070Sstevel@tonic-gate goto scan;
2080Sstevel@tonic-gate #endif
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /* Scan the field width */
2120Sstevel@tonic-gate if (*cp == '*') {
2130Sstevel@tonic-gate width = va_arg (*args, int);
2140Sstevel@tonic-gate if (width < 0) {
2150Sstevel@tonic-gate width = -width;
2160Sstevel@tonic-gate fminus = 1;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate cp++;
2190Sstevel@tonic-gate } else {
2200Sstevel@tonic-gate width = 0;
2210Sstevel@tonic-gate while (isdigit(*cp)) {
2220Sstevel@tonic-gate n = tonumber(*cp++);
2230Sstevel@tonic-gate width = width * 10 + n;
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate /* Scan the precision */
2280Sstevel@tonic-gate if (*cp == '.') {
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate /* '*' instead of digits? */
2310Sstevel@tonic-gate if (*++cp == '*') {
2320Sstevel@tonic-gate prec = va_arg(*args, int);
2330Sstevel@tonic-gate cp++;
2340Sstevel@tonic-gate } else {
2350Sstevel@tonic-gate prec = 0;
2360Sstevel@tonic-gate while (isdigit(*cp)) {
2370Sstevel@tonic-gate n = tonumber(*cp++);
2380Sstevel@tonic-gate prec = prec * 10 + n;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate } else {
2420Sstevel@tonic-gate prec = -1;
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate /* Scan the length modifier */
2460Sstevel@tonic-gate double_length = length = 0;
2470Sstevel@tonic-gate switch (*cp) {
2480Sstevel@tonic-gate case 'l':
2490Sstevel@tonic-gate if (*(cp + 1) == 'l') {
2500Sstevel@tonic-gate cp++;
2510Sstevel@tonic-gate double_length = 1;
2520Sstevel@tonic-gate } else {
2530Sstevel@tonic-gate length = 1;
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate /* No break */
2560Sstevel@tonic-gate case 'h':
2570Sstevel@tonic-gate cp++;
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate /*
2610Sstevel@tonic-gate * The character addressed by cp must be the
2620Sstevel@tonic-gate * format letter -- there is nothing left for
2630Sstevel@tonic-gate * it to be.
2640Sstevel@tonic-gate *
2650Sstevel@tonic-gate * The status of the +, -, #, blank, and 0
2660Sstevel@tonic-gate * flags are reflected in the variables
2670Sstevel@tonic-gate * "fplus", "fminus", "fsharp", "fblank",
2680Sstevel@tonic-gate * and "fzero", respectively.
2690Sstevel@tonic-gate * "width" and "prec" contain numbers
2700Sstevel@tonic-gate * corresponding to the digit strings
2710Sstevel@tonic-gate * before and after the decimal point,
2720Sstevel@tonic-gate * respectively. If there was no decimal
2730Sstevel@tonic-gate * point, "prec" is -1.
2740Sstevel@tonic-gate *
2750Sstevel@tonic-gate * The following switch sets things up
2760Sstevel@tonic-gate * for printing. What ultimately gets
2770Sstevel@tonic-gate * printed will be padding blanks, a prefix,
2780Sstevel@tonic-gate * left padding zeroes, a value, right padding
2790Sstevel@tonic-gate * zeroes, a suffix, and more padding
2800Sstevel@tonic-gate * blanks. Padding blanks will not appear
2810Sstevel@tonic-gate * simultaneously on both the left and the
2820Sstevel@tonic-gate * right. Each case in this switch will
2830Sstevel@tonic-gate * compute the value, and leave in several
2840Sstevel@tonic-gate * variables the information necessary to
2850Sstevel@tonic-gate * construct what is to be printed.
2860Sstevel@tonic-gate *
2870Sstevel@tonic-gate * The prefix is a sign, a blank, "0x", "0X",
2880Sstevel@tonic-gate * or null, and is addressed by "prefix".
2890Sstevel@tonic-gate *
2900Sstevel@tonic-gate * The suffix is either null or an exponent,
2910Sstevel@tonic-gate * and is addressed by "suffix".
2920Sstevel@tonic-gate *
2930Sstevel@tonic-gate * The value to be printed starts at "bp"
2940Sstevel@tonic-gate * and continues up to and not including "p".
2950Sstevel@tonic-gate *
2960Sstevel@tonic-gate * "lzero" and "rzero" will contain the number
2970Sstevel@tonic-gate * of padding zeroes required on the left
2980Sstevel@tonic-gate * and right, respectively. If either of
2990Sstevel@tonic-gate * these variables is negative, it will be
3000Sstevel@tonic-gate * treated as if it were zero.
3010Sstevel@tonic-gate *
3020Sstevel@tonic-gate * The number of padding blanks, and whether
3030Sstevel@tonic-gate * they go on the left or the right, will be
3040Sstevel@tonic-gate * computed on exit from the switch.
3050Sstevel@tonic-gate */
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate lzero = 0;
3080Sstevel@tonic-gate prefix = "";
3090Sstevel@tonic-gate #if FLOAT
3100Sstevel@tonic-gate rzero = lzero;
3110Sstevel@tonic-gate suffix = prefix;
3120Sstevel@tonic-gate #endif
3130Sstevel@tonic-gate switch (fcode = *cp++) {
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate /*
3160Sstevel@tonic-gate * fixed point representations
3170Sstevel@tonic-gate *
3180Sstevel@tonic-gate * "hradix" is half the radix for the conversion.
3190Sstevel@tonic-gate * Conversion is unsigned unless fcode is 'd'.
3200Sstevel@tonic-gate * HIBITLL is 1000...000 binary, and is equal to
3210Sstevel@tonic-gate * the maximum negative number.
3220Sstevel@tonic-gate * We assume a 2's complement machine
3230Sstevel@tonic-gate */
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate case 'D':
3260Sstevel@tonic-gate case 'U':
3270Sstevel@tonic-gate length = 1;
3280Sstevel@tonic-gate case 'd':
3290Sstevel@tonic-gate case 'u':
3300Sstevel@tonic-gate hradix = 5;
3310Sstevel@tonic-gate goto fixed;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate case 'O':
3340Sstevel@tonic-gate length = 1;
3350Sstevel@tonic-gate case 'o':
3360Sstevel@tonic-gate hradix = 4;
3370Sstevel@tonic-gate goto fixed;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate case 'X':
3400Sstevel@tonic-gate case 'x':
3410Sstevel@tonic-gate hradix = 8;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate fixed:
3440Sstevel@tonic-gate /* Establish default precision */
3450Sstevel@tonic-gate if (prec < 0) {
3460Sstevel@tonic-gate prec = 1;
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate /* Fetch the argument to be printed */
3500Sstevel@tonic-gate if (double_length) {
3510Sstevel@tonic-gate val = va_arg(*args, long long);
3520Sstevel@tonic-gate } else if (length) {
3530Sstevel@tonic-gate val = va_arg(*args, long);
3540Sstevel@tonic-gate } else if (fcode == 'd') {
3550Sstevel@tonic-gate val = va_arg(*args, int);
3560Sstevel@tonic-gate } else {
3570Sstevel@tonic-gate val = va_arg(*args, unsigned);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate /* If signed conversion, establish sign */
3610Sstevel@tonic-gate if (fcode == 'd' || fcode == 'D') {
3620Sstevel@tonic-gate if (val < 0) {
3630Sstevel@tonic-gate prefix = "-";
3640Sstevel@tonic-gate /*
3650Sstevel@tonic-gate * Negate, checking in
3660Sstevel@tonic-gate * advance for possible
3670Sstevel@tonic-gate * overflow.
3680Sstevel@tonic-gate */
3690Sstevel@tonic-gate if (val != HIBITLL) {
3700Sstevel@tonic-gate val = -val;
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate } else if (fplus) {
3730Sstevel@tonic-gate prefix = "+";
3740Sstevel@tonic-gate } else if (fblank) {
3750Sstevel@tonic-gate prefix = " ";
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate #if FZERO
3790Sstevel@tonic-gate if (fzero) {
3800Sstevel@tonic-gate int n = width - strlen(prefix);
3810Sstevel@tonic-gate if (n > prec) {
3820Sstevel@tonic-gate prec = n;
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate #endif
3860Sstevel@tonic-gate /* Set translate table for digits */
3870Sstevel@tonic-gate if (fcode == 'X') {
3880Sstevel@tonic-gate tab = "0123456789ABCDEF";
3890Sstevel@tonic-gate } else {
3900Sstevel@tonic-gate tab = "0123456789abcdef";
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /* Develop the digits of the value */
3940Sstevel@tonic-gate p = bp = buf + MAXDIGS;
3950Sstevel@tonic-gate while (val) {
3960Sstevel@tonic-gate lowbit = val & 1;
3970Sstevel@tonic-gate val = (val >> 1) & ~HIBITLL;
3980Sstevel@tonic-gate *--bp = tab[val % hradix * 2 + lowbit];
3990Sstevel@tonic-gate val /= hradix;
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /* Calculate padding zero requirement */
4030Sstevel@tonic-gate lzero = bp - p + prec;
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate /* Handle the # flag */
4060Sstevel@tonic-gate if (fsharp && bp != p) {
4070Sstevel@tonic-gate switch (fcode) {
4080Sstevel@tonic-gate case 'o':
4090Sstevel@tonic-gate if (lzero < 1)
4100Sstevel@tonic-gate lzero = 1;
4110Sstevel@tonic-gate break;
4120Sstevel@tonic-gate case 'x':
4130Sstevel@tonic-gate prefix = "0x";
4140Sstevel@tonic-gate break;
4150Sstevel@tonic-gate case 'X':
4160Sstevel@tonic-gate prefix = "0X";
4170Sstevel@tonic-gate break;
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate break;
4220Sstevel@tonic-gate #if FLOAT
4230Sstevel@tonic-gate case 'E':
4240Sstevel@tonic-gate case 'e':
4250Sstevel@tonic-gate /*
4260Sstevel@tonic-gate * E-format. The general strategy
4270Sstevel@tonic-gate * here is fairly easy: we take
4280Sstevel@tonic-gate * what ecvt gives us and re-format it.
4290Sstevel@tonic-gate */
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /* Establish default precision */
4320Sstevel@tonic-gate if (prec < 0) {
4330Sstevel@tonic-gate prec = 6;
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate /* Fetch the value */
4370Sstevel@tonic-gate dval = va_arg(*args, double);
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate /* Develop the mantissa */
4400Sstevel@tonic-gate bp = ecvt(dval,
4410Sstevel@tonic-gate min(prec + 1, MAXECVT),
4420Sstevel@tonic-gate &decpt,
4430Sstevel@tonic-gate &sign);
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate /* Determine the prefix */
4460Sstevel@tonic-gate e_merge:
4470Sstevel@tonic-gate if (sign) {
4480Sstevel@tonic-gate prefix = "-";
4490Sstevel@tonic-gate } else if (fplus) {
4500Sstevel@tonic-gate prefix = "+";
4510Sstevel@tonic-gate } else if (fblank) {
4520Sstevel@tonic-gate prefix = " ";
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate /* Place the first digit in the buffer */
4560Sstevel@tonic-gate p = &buf[0];
4570Sstevel@tonic-gate *p++ = *bp != '\0' ? *bp++ : '0';
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate /* Put in a decimal point if needed */
4600Sstevel@tonic-gate if (prec != 0 || fsharp) {
4610Sstevel@tonic-gate *p++ = '.';
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate
4640Sstevel@tonic-gate /* Create the rest of the mantissa */
4650Sstevel@tonic-gate rzero = prec;
4660Sstevel@tonic-gate while (rzero > 0 && *bp != '\0') {
4670Sstevel@tonic-gate --rzero;
4680Sstevel@tonic-gate *p++ = *bp++;
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate bp = &buf[0];
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate /* Create the exponent */
4740Sstevel@tonic-gate suffix = &expbuf[MAXESIZ];
4750Sstevel@tonic-gate *suffix = '\0';
4760Sstevel@tonic-gate if (dval != 0) {
4770Sstevel@tonic-gate n = decpt - 1;
4780Sstevel@tonic-gate if (n < 0) {
4790Sstevel@tonic-gate n = -n;
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate while (n != 0) {
4820Sstevel@tonic-gate *--suffix = todigit(n % 10);
4830Sstevel@tonic-gate n /= 10;
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate /* Prepend leading zeroes to the exponent */
4880Sstevel@tonic-gate while (suffix > &expbuf[MAXESIZ - 2]) {
4890Sstevel@tonic-gate *--suffix = '0';
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate /* Put in the exponent sign */
4930Sstevel@tonic-gate *--suffix = (decpt > 0 || dval == 0) ?
4940Sstevel@tonic-gate '+' : '-';
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate /* Put in the e */
4970Sstevel@tonic-gate *--suffix = isupper(fcode) ? 'E' : 'e';
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate break;
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate case 'f':
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * F-format floating point. This is
5040Sstevel@tonic-gate * a good deal less simple than E-format.
5050Sstevel@tonic-gate * The overall strategy will be to call
5060Sstevel@tonic-gate * fcvt, reformat its result into buf,
5070Sstevel@tonic-gate * and calculate how many trailing
5080Sstevel@tonic-gate * zeroes will be required. There will
5090Sstevel@tonic-gate * never be any leading zeroes needed.
5100Sstevel@tonic-gate */
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate /* Establish default precision */
5130Sstevel@tonic-gate if (prec < 0) {
5140Sstevel@tonic-gate prec = 6;
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate /* Fetch the value */
5180Sstevel@tonic-gate dval = va_arg(*args, double);
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate /* Do the conversion */
5210Sstevel@tonic-gate bp = fcvt(dval,
5220Sstevel@tonic-gate min(prec, MAXFCVT),
5230Sstevel@tonic-gate &decpt,
5240Sstevel@tonic-gate &sign);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate /* Determine the prefix */
5270Sstevel@tonic-gate f_merge:
5280Sstevel@tonic-gate if (sign && decpt > -prec &&
5290Sstevel@tonic-gate *bp != '\0' && *bp != '0') {
5300Sstevel@tonic-gate prefix = "-";
5310Sstevel@tonic-gate } else if (fplus) {
5320Sstevel@tonic-gate prefix = "+";
5330Sstevel@tonic-gate } else if (fblank) {
5340Sstevel@tonic-gate prefix = " ";
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate /* Initialize buffer pointer */
5380Sstevel@tonic-gate p = &buf[0];
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate /* Emit the digits before the decimal point */
5410Sstevel@tonic-gate n = decpt;
5420Sstevel@tonic-gate k = 0;
5430Sstevel@tonic-gate if (n <= 0) {
5440Sstevel@tonic-gate *p++ = '0';
5450Sstevel@tonic-gate } else {
5460Sstevel@tonic-gate do {
5470Sstevel@tonic-gate if (*bp == '\0' ||
5480Sstevel@tonic-gate k >= MAXFSIG) {
5490Sstevel@tonic-gate *p++ = '0';
5500Sstevel@tonic-gate } else {
5510Sstevel@tonic-gate *p++ = *bp++;
5520Sstevel@tonic-gate ++k;
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate } while (--n != 0);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate /* Decide whether we need a decimal point */
5580Sstevel@tonic-gate if (fsharp || prec > 0) {
5590Sstevel@tonic-gate *p++ = '.';
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate /* Digits (if any) after the decimal point */
5630Sstevel@tonic-gate n = min(prec, MAXFCVT);
5640Sstevel@tonic-gate rzero = prec - n;
5650Sstevel@tonic-gate while (--n >= 0) {
5660Sstevel@tonic-gate if (++decpt <= 0 || *bp == '\0' ||
5670Sstevel@tonic-gate k >= MAXFSIG) {
5680Sstevel@tonic-gate *p++ = '0';
5690Sstevel@tonic-gate } else {
5700Sstevel@tonic-gate *p++ = *bp++;
5710Sstevel@tonic-gate ++k;
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate bp = &buf[0];
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate case 'G':
5800Sstevel@tonic-gate case 'g':
5810Sstevel@tonic-gate /*
5820Sstevel@tonic-gate * g-format. We play around a bit
5830Sstevel@tonic-gate * and then jump into e or f, as needed.
5840Sstevel@tonic-gate */
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate /* Establish default precision */
5870Sstevel@tonic-gate if (prec < 0) {
5880Sstevel@tonic-gate prec = 6;
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate /* Fetch the value */
5920Sstevel@tonic-gate dval = va_arg(*args, double);
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate /* Do the conversion */
5950Sstevel@tonic-gate bp = ecvt(dval,
5960Sstevel@tonic-gate min(prec, MAXECVT),
5970Sstevel@tonic-gate &decpt,
5980Sstevel@tonic-gate &sign);
5990Sstevel@tonic-gate if (dval == 0) {
6000Sstevel@tonic-gate decpt = 1;
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate k = prec;
6040Sstevel@tonic-gate if (!fsharp) {
6050Sstevel@tonic-gate n = strlen(bp);
6060Sstevel@tonic-gate if (n < k) {
6070Sstevel@tonic-gate k = n;
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate while (k >= 1 && bp[k-1] == '0') {
6100Sstevel@tonic-gate --k;
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate if (decpt < -3 || decpt > prec) {
6150Sstevel@tonic-gate prec = k - 1;
6160Sstevel@tonic-gate goto e_merge;
6170Sstevel@tonic-gate } else {
6180Sstevel@tonic-gate prec = k - decpt;
6190Sstevel@tonic-gate goto f_merge;
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate #endif
6230Sstevel@tonic-gate case 'c':
6240Sstevel@tonic-gate #ifdef MBCHAR_1 /* sizeof(int)>=sizeof(tchar) */
6250Sstevel@tonic-gate /*
6260Sstevel@tonic-gate * A tchar arg is passed as int so we used the normal %c to specify
6270Sstevel@tonic-gate * such an arugument.
6280Sstevel@tonic-gate */
6290Sstevel@tonic-gate tcbuf[0] = va_arg(*args, int);
6300Sstevel@tonic-gate tbp = &tcbuf[0];
6310Sstevel@tonic-gate tep = tbp + 1;
6320Sstevel@tonic-gate fcode = 't'; /* Fake the rest of code. */
6330Sstevel@tonic-gate break;
6340Sstevel@tonic-gate #else
6350Sstevel@tonic-gate /*
6360Sstevel@tonic-gate * We would have to invent another new format speficier such as "%T" to
6370Sstevel@tonic-gate * take a tchar arg. Let's worry about when that time comes.
6380Sstevel@tonic-gate */
6390Sstevel@tonic-gate /*
6400Sstevel@tonic-gate * Following code take care of a char arg
6410Sstevel@tonic-gate * only.
6420Sstevel@tonic-gate */
6430Sstevel@tonic-gate buf[0] = va_arg(*args, int);
6440Sstevel@tonic-gate bp = &buf[0];
6450Sstevel@tonic-gate p = bp + 1;
6460Sstevel@tonic-gate break;
6470Sstevel@tonic-gate case 'T': /* Corresponding arg is tchar. */
6480Sstevel@tonic-gate tcbuf[0] = va_arg(*args, tchar);
6490Sstevel@tonic-gate tbp = &tcbuf[0];
6500Sstevel@tonic-gate tep = tbp + 1;
6510Sstevel@tonic-gate fcode = 't'; /* Fake the rest of code. */
6520Sstevel@tonic-gate break;
6530Sstevel@tonic-gate #endif
6540Sstevel@tonic-gate case 's':
6550Sstevel@tonic-gate bp = va_arg(*args, char *);
6560Sstevel@tonic-gate if (bp == 0) {
6570Sstevel@tonic-gate nullstr: bp = "(null)";
6580Sstevel@tonic-gate p = bp + strlen("(null)");
6590Sstevel@tonic-gate break;
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate if (prec < 0) {
6620Sstevel@tonic-gate prec = MAXINT;
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate for (n = 0; *bp++ != '\0' && n < prec; n++)
6650Sstevel@tonic-gate ;
6660Sstevel@tonic-gate p = --bp;
6670Sstevel@tonic-gate bp -= n;
6680Sstevel@tonic-gate break;
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate case 't':
6710Sstevel@tonic-gate /*
6720Sstevel@tonic-gate * Special format specifier "%t" tells
6730Sstevel@tonic-gate * printf() to print char strings written
6740Sstevel@tonic-gate * as tchar string.
6750Sstevel@tonic-gate */
6760Sstevel@tonic-gate tbp = va_arg(*args, tchar *);
6770Sstevel@tonic-gate if (tbp == 0) {
6780Sstevel@tonic-gate fcode = 's'; /* Act as if it were %s. */
6790Sstevel@tonic-gate goto nullstr;
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate if (prec < 0) {
6820Sstevel@tonic-gate prec = MAXINT;
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate for (n = 0; *tbp++ != 0 && n < prec; n++)
6850Sstevel@tonic-gate ;
6860Sstevel@tonic-gate tep = --tbp;
6870Sstevel@tonic-gate tbp -= n;
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate * Just to make the following padding
6910Sstevel@tonic-gate * calculation not to go very crazy...
6920Sstevel@tonic-gate */
6930Sstevel@tonic-gate bp = NULL;
6940Sstevel@tonic-gate p = bp + n;
6950Sstevel@tonic-gate break;
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate case '\0':
6980Sstevel@tonic-gate cp--;
6990Sstevel@tonic-gate break;
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate default:
7020Sstevel@tonic-gate p = bp = &fcode;
7030Sstevel@tonic-gate p++;
7040Sstevel@tonic-gate break;
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate if (fcode != '\0') {
7080Sstevel@tonic-gate /* Calculate number of padding blanks */
7090Sstevel@tonic-gate int nblank;
7100Sstevel@tonic-gate nblank = width
7110Sstevel@tonic-gate #if FLOAT
7120Sstevel@tonic-gate - (rzero < 0 ? 0: rzero)
7130Sstevel@tonic-gate - strlen(suffix)
7140Sstevel@tonic-gate #endif
7150Sstevel@tonic-gate - (p - bp)
7160Sstevel@tonic-gate - (lzero < 0 ? 0 : lzero)
7170Sstevel@tonic-gate - strlen(prefix);
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate /* Blanks on left if required */
7200Sstevel@tonic-gate if (!fminus) {
7210Sstevel@tonic-gate while (--nblank >= 0) {
7220Sstevel@tonic-gate Putchar(' ');
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate /* Prefix, if any */
7270Sstevel@tonic-gate while (*prefix != '\0') {
7280Sstevel@tonic-gate Putchar(*prefix++);
7290Sstevel@tonic-gate }
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate /* Zeroes on the left */
7320Sstevel@tonic-gate while (--lzero >= 0) {
7330Sstevel@tonic-gate Putchar('0');
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate /* The value itself */
7370Sstevel@tonic-gate if (fcode == 't') { /* %t is special. */
7380Sstevel@tonic-gate while (tbp < tep) {
7390Sstevel@tonic-gate Putchar(*tbp++);
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate } else { /* For rest of the cases. */
7420Sstevel@tonic-gate while (bp < p) {
7430Sstevel@tonic-gate putbyte(*bp++);
7440Sstevel@tonic-gate }
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate #if FLOAT
7470Sstevel@tonic-gate /* Zeroes on the right */
7480Sstevel@tonic-gate while (--rzero >= 0)
7490Sstevel@tonic-gate Putchar('0');
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate /* The suffix */
7520Sstevel@tonic-gate while (*suffix != '\0') {
7530Sstevel@tonic-gate Putchar(*suffix++);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate #endif
7560Sstevel@tonic-gate /* Blanks on the right if required */
7570Sstevel@tonic-gate if (fminus) {
7580Sstevel@tonic-gate while (--nblank >= 0) {
7590Sstevel@tonic-gate Putchar(' ');
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate }
765