1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7*0Sstevel@tonic-gate /* All Rights Reserved */ 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate /* 10*0Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 11*0Sstevel@tonic-gate * All rights reserved. The Berkeley Software License Agreement 12*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate /* 18*0Sstevel@tonic-gate * Hacked "printf" which prints through putbyte and Putchar. 19*0Sstevel@tonic-gate * putbyte() is used to send a pure byte, which might be a part 20*0Sstevel@tonic-gate * of a mutlibyte character, mainly for %s. A control character 21*0Sstevel@tonic-gate * for putbyte() may be QUOTE'd meaning not to convert it to ^x 22*0Sstevel@tonic-gate * sequence. In all other cases Putchar() is used to send a character 23*0Sstevel@tonic-gate * in tchar (== wchar_t + * optional QUOE.) 24*0Sstevel@tonic-gate * DONT USE WITH STDIO! 25*0Sstevel@tonic-gate * This printf has been hacked again so that it understands tchar string 26*0Sstevel@tonic-gate * when the format specifier %t is used. Also %c has been expanded 27*0Sstevel@tonic-gate * to take a tchar character as well as normal int. 28*0Sstevel@tonic-gate * %t is supported in its simplest form; no width or precision will 29*0Sstevel@tonic-gate * be understood. 30*0Sstevel@tonic-gate * Assumption here is that sizeof(tchar)<=sizeof(int) so that tchar is 31*0Sstevel@tonic-gate * passed as int. Otherwise, %T must be specified instead of %c to 32*0Sstevel@tonic-gate * print a character in tchar. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <stdarg.h> 36*0Sstevel@tonic-gate #include <values.h> 37*0Sstevel@tonic-gate #include "sh.h" /* For tchar. */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #define HIBITLL (1ULL << 63) 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate void _print(char *format, va_list *args); 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate static char *p; 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate int 46*0Sstevel@tonic-gate printf(const char *format, ...) 47*0Sstevel@tonic-gate { 48*0Sstevel@tonic-gate va_list stupid; 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate p = (char *)gettext(format); 51*0Sstevel@tonic-gate va_start(stupid, format); 52*0Sstevel@tonic-gate _print(p, &stupid); 53*0Sstevel@tonic-gate va_end(stupid); 54*0Sstevel@tonic-gate } 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * Floating-point code is included or not, depending 58*0Sstevel@tonic-gate * on whether the preprocessor variable FLOAT is 1 or 0. 59*0Sstevel@tonic-gate */ 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate /* Maximum number of digits in any integer (long) representation */ 62*0Sstevel@tonic-gate #define MAXDIGS 20 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate /* Convert a digit character to the corresponding number */ 65*0Sstevel@tonic-gate #define tonumber(x) ((x) - '0') 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* Convert a number between 0 and 9 to the corresponding digit */ 68*0Sstevel@tonic-gate #define todigit(x) ((x) + '0') 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* Maximum total number of digits in E format */ 71*0Sstevel@tonic-gate #define MAXECVT 17 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* Maximum number of digits after decimal point in F format */ 74*0Sstevel@tonic-gate #define MAXFCVT 60 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* Maximum significant figures in a floating-point number */ 77*0Sstevel@tonic-gate #define MAXFSIG 17 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* Maximum number of characters in an exponent */ 80*0Sstevel@tonic-gate #define MAXESIZ 4 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* Maximum (positive) exponent or greater */ 83*0Sstevel@tonic-gate #define MAXEXP 40 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate #define max(a, b) ((a) > (b) ? (a) : (b)) 88*0Sstevel@tonic-gate #define min(a, b) ((a) < (b) ? (a) : (b)) 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* If this symbol is nonzero, allow '0' as a flag */ 91*0Sstevel@tonic-gate #define FZERO 1 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate #if FLOAT 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * System-supplied routines for floating conversion 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate char *fcvt(); 98*0Sstevel@tonic-gate char *ecvt(); 99*0Sstevel@tonic-gate #endif 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate void 102*0Sstevel@tonic-gate _print(char *format, va_list *args) 103*0Sstevel@tonic-gate { 104*0Sstevel@tonic-gate /* Current position in format */ 105*0Sstevel@tonic-gate char *cp; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* Starting and ending points for value to be printed */ 108*0Sstevel@tonic-gate char *bp, *p; 109*0Sstevel@tonic-gate tchar *tbp, *tep; /* For "%t". */ 110*0Sstevel@tonic-gate tchar tcbuf[2]; /* For "%c" or "%T". */ 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate /* Field width and precision */ 113*0Sstevel@tonic-gate int width, prec; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* Format code */ 116*0Sstevel@tonic-gate char fcode; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* Number of padding zeroes required on the left */ 119*0Sstevel@tonic-gate int lzero; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* Flags - nonzero if corresponding character appears in format */ 122*0Sstevel@tonic-gate bool length; /* l */ 123*0Sstevel@tonic-gate bool double_length; /* ll */ 124*0Sstevel@tonic-gate bool fplus; /* + */ 125*0Sstevel@tonic-gate bool fminus; /* - */ 126*0Sstevel@tonic-gate bool fblank; /* blank */ 127*0Sstevel@tonic-gate bool fsharp; /* # */ 128*0Sstevel@tonic-gate #if FZERO 129*0Sstevel@tonic-gate bool fzero; /* 0 */ 130*0Sstevel@tonic-gate #endif 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate /* Pointer to sign, "0x", "0X", or empty */ 133*0Sstevel@tonic-gate char *prefix; 134*0Sstevel@tonic-gate #if FLOAT 135*0Sstevel@tonic-gate /* Exponent or empty */ 136*0Sstevel@tonic-gate char *suffix; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate /* Buffer to create exponent */ 139*0Sstevel@tonic-gate char expbuf[MAXESIZ + 1]; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* Number of padding zeroes required on the right */ 142*0Sstevel@tonic-gate int rzero; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate /* The value being converted, if real */ 145*0Sstevel@tonic-gate double dval; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate /* Output values from fcvt and ecvt */ 148*0Sstevel@tonic-gate int decpt, sign; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* Scratch */ 151*0Sstevel@tonic-gate int k; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate /* Values are developed in this buffer */ 154*0Sstevel@tonic-gate char buf[max(MAXDIGS, max(MAXFCVT + DMAXEXP, MAXECVT) + 1)]; 155*0Sstevel@tonic-gate #else 156*0Sstevel@tonic-gate char buf[MAXDIGS]; 157*0Sstevel@tonic-gate #endif 158*0Sstevel@tonic-gate /* The value being converted, if integer */ 159*0Sstevel@tonic-gate long long val; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* Set to point to a translate table for digits of whatever radix */ 162*0Sstevel@tonic-gate char *tab; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* Work variables */ 165*0Sstevel@tonic-gate int n, hradix, lowbit; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate cp = format; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * The main loop -- this loop goes through one iteration 171*0Sstevel@tonic-gate * for each ordinary character or format specification. 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate while (*cp) 174*0Sstevel@tonic-gate if (*cp != '%') { 175*0Sstevel@tonic-gate /* Ordinary (non-%) character */ 176*0Sstevel@tonic-gate putbyte (*cp++); 177*0Sstevel@tonic-gate } else { 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * % has been found. 180*0Sstevel@tonic-gate * First, parse the format specification. 181*0Sstevel@tonic-gate */ 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate /* Scan the <flags> */ 184*0Sstevel@tonic-gate fplus = fminus = fblank = fsharp = 0; 185*0Sstevel@tonic-gate #if FZERO 186*0Sstevel@tonic-gate fzero = 0; 187*0Sstevel@tonic-gate #endif 188*0Sstevel@tonic-gate scan: 189*0Sstevel@tonic-gate switch (*++cp) { 190*0Sstevel@tonic-gate case '+': 191*0Sstevel@tonic-gate fplus = 1; 192*0Sstevel@tonic-gate goto scan; 193*0Sstevel@tonic-gate case '-': 194*0Sstevel@tonic-gate fminus = 1; 195*0Sstevel@tonic-gate goto scan; 196*0Sstevel@tonic-gate case ' ': 197*0Sstevel@tonic-gate fblank = 1; 198*0Sstevel@tonic-gate goto scan; 199*0Sstevel@tonic-gate case '#': 200*0Sstevel@tonic-gate fsharp = 1; 201*0Sstevel@tonic-gate goto scan; 202*0Sstevel@tonic-gate #if FZERO 203*0Sstevel@tonic-gate case '0': 204*0Sstevel@tonic-gate fzero = 1; 205*0Sstevel@tonic-gate goto scan; 206*0Sstevel@tonic-gate #endif 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* Scan the field width */ 210*0Sstevel@tonic-gate if (*cp == '*') { 211*0Sstevel@tonic-gate width = va_arg (*args, int); 212*0Sstevel@tonic-gate if (width < 0) { 213*0Sstevel@tonic-gate width = -width; 214*0Sstevel@tonic-gate fminus = 1; 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate cp++; 217*0Sstevel@tonic-gate } else { 218*0Sstevel@tonic-gate width = 0; 219*0Sstevel@tonic-gate while (isdigit(*cp)) { 220*0Sstevel@tonic-gate n = tonumber(*cp++); 221*0Sstevel@tonic-gate width = width * 10 + n; 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate /* Scan the precision */ 226*0Sstevel@tonic-gate if (*cp == '.') { 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate /* '*' instead of digits? */ 229*0Sstevel@tonic-gate if (*++cp == '*') { 230*0Sstevel@tonic-gate prec = va_arg(*args, int); 231*0Sstevel@tonic-gate cp++; 232*0Sstevel@tonic-gate } else { 233*0Sstevel@tonic-gate prec = 0; 234*0Sstevel@tonic-gate while (isdigit(*cp)) { 235*0Sstevel@tonic-gate n = tonumber(*cp++); 236*0Sstevel@tonic-gate prec = prec * 10 + n; 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate } else { 240*0Sstevel@tonic-gate prec = -1; 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate /* Scan the length modifier */ 244*0Sstevel@tonic-gate double_length = length = 0; 245*0Sstevel@tonic-gate switch (*cp) { 246*0Sstevel@tonic-gate case 'l': 247*0Sstevel@tonic-gate if (*(cp + 1) == 'l') { 248*0Sstevel@tonic-gate cp++; 249*0Sstevel@tonic-gate double_length = 1; 250*0Sstevel@tonic-gate } else { 251*0Sstevel@tonic-gate length = 1; 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate /* No break */ 254*0Sstevel@tonic-gate case 'h': 255*0Sstevel@tonic-gate cp++; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * The character addressed by cp must be the 260*0Sstevel@tonic-gate * format letter -- there is nothing left for 261*0Sstevel@tonic-gate * it to be. 262*0Sstevel@tonic-gate * 263*0Sstevel@tonic-gate * The status of the +, -, #, blank, and 0 264*0Sstevel@tonic-gate * flags are reflected in the variables 265*0Sstevel@tonic-gate * "fplus", "fminus", "fsharp", "fblank", 266*0Sstevel@tonic-gate * and "fzero", respectively. 267*0Sstevel@tonic-gate * "width" and "prec" contain numbers 268*0Sstevel@tonic-gate * corresponding to the digit strings 269*0Sstevel@tonic-gate * before and after the decimal point, 270*0Sstevel@tonic-gate * respectively. If there was no decimal 271*0Sstevel@tonic-gate * point, "prec" is -1. 272*0Sstevel@tonic-gate * 273*0Sstevel@tonic-gate * The following switch sets things up 274*0Sstevel@tonic-gate * for printing. What ultimately gets 275*0Sstevel@tonic-gate * printed will be padding blanks, a prefix, 276*0Sstevel@tonic-gate * left padding zeroes, a value, right padding 277*0Sstevel@tonic-gate * zeroes, a suffix, and more padding 278*0Sstevel@tonic-gate * blanks. Padding blanks will not appear 279*0Sstevel@tonic-gate * simultaneously on both the left and the 280*0Sstevel@tonic-gate * right. Each case in this switch will 281*0Sstevel@tonic-gate * compute the value, and leave in several 282*0Sstevel@tonic-gate * variables the information necessary to 283*0Sstevel@tonic-gate * construct what is to be printed. 284*0Sstevel@tonic-gate * 285*0Sstevel@tonic-gate * The prefix is a sign, a blank, "0x", "0X", 286*0Sstevel@tonic-gate * or null, and is addressed by "prefix". 287*0Sstevel@tonic-gate * 288*0Sstevel@tonic-gate * The suffix is either null or an exponent, 289*0Sstevel@tonic-gate * and is addressed by "suffix". 290*0Sstevel@tonic-gate * 291*0Sstevel@tonic-gate * The value to be printed starts at "bp" 292*0Sstevel@tonic-gate * and continues up to and not including "p". 293*0Sstevel@tonic-gate * 294*0Sstevel@tonic-gate * "lzero" and "rzero" will contain the number 295*0Sstevel@tonic-gate * of padding zeroes required on the left 296*0Sstevel@tonic-gate * and right, respectively. If either of 297*0Sstevel@tonic-gate * these variables is negative, it will be 298*0Sstevel@tonic-gate * treated as if it were zero. 299*0Sstevel@tonic-gate * 300*0Sstevel@tonic-gate * The number of padding blanks, and whether 301*0Sstevel@tonic-gate * they go on the left or the right, will be 302*0Sstevel@tonic-gate * computed on exit from the switch. 303*0Sstevel@tonic-gate */ 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate lzero = 0; 306*0Sstevel@tonic-gate prefix = ""; 307*0Sstevel@tonic-gate #if FLOAT 308*0Sstevel@tonic-gate rzero = lzero; 309*0Sstevel@tonic-gate suffix = prefix; 310*0Sstevel@tonic-gate #endif 311*0Sstevel@tonic-gate switch (fcode = *cp++) { 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate /* 314*0Sstevel@tonic-gate * fixed point representations 315*0Sstevel@tonic-gate * 316*0Sstevel@tonic-gate * "hradix" is half the radix for the conversion. 317*0Sstevel@tonic-gate * Conversion is unsigned unless fcode is 'd'. 318*0Sstevel@tonic-gate * HIBITLL is 1000...000 binary, and is equal to 319*0Sstevel@tonic-gate * the maximum negative number. 320*0Sstevel@tonic-gate * We assume a 2's complement machine 321*0Sstevel@tonic-gate */ 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate case 'D': 324*0Sstevel@tonic-gate case 'U': 325*0Sstevel@tonic-gate length = 1; 326*0Sstevel@tonic-gate case 'd': 327*0Sstevel@tonic-gate case 'u': 328*0Sstevel@tonic-gate hradix = 5; 329*0Sstevel@tonic-gate goto fixed; 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate case 'O': 332*0Sstevel@tonic-gate length = 1; 333*0Sstevel@tonic-gate case 'o': 334*0Sstevel@tonic-gate hradix = 4; 335*0Sstevel@tonic-gate goto fixed; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate case 'X': 338*0Sstevel@tonic-gate case 'x': 339*0Sstevel@tonic-gate hradix = 8; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate fixed: 342*0Sstevel@tonic-gate /* Establish default precision */ 343*0Sstevel@tonic-gate if (prec < 0) { 344*0Sstevel@tonic-gate prec = 1; 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* Fetch the argument to be printed */ 348*0Sstevel@tonic-gate if (double_length) { 349*0Sstevel@tonic-gate val = va_arg(*args, long long); 350*0Sstevel@tonic-gate } else if (length) { 351*0Sstevel@tonic-gate val = va_arg(*args, long); 352*0Sstevel@tonic-gate } else if (fcode == 'd') { 353*0Sstevel@tonic-gate val = va_arg(*args, int); 354*0Sstevel@tonic-gate } else { 355*0Sstevel@tonic-gate val = va_arg(*args, unsigned); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate /* If signed conversion, establish sign */ 359*0Sstevel@tonic-gate if (fcode == 'd' || fcode == 'D') { 360*0Sstevel@tonic-gate if (val < 0) { 361*0Sstevel@tonic-gate prefix = "-"; 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * Negate, checking in 364*0Sstevel@tonic-gate * advance for possible 365*0Sstevel@tonic-gate * overflow. 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate if (val != HIBITLL) { 368*0Sstevel@tonic-gate val = -val; 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate } else if (fplus) { 371*0Sstevel@tonic-gate prefix = "+"; 372*0Sstevel@tonic-gate } else if (fblank) { 373*0Sstevel@tonic-gate prefix = " "; 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate #if FZERO 377*0Sstevel@tonic-gate if (fzero) { 378*0Sstevel@tonic-gate int n = width - strlen(prefix); 379*0Sstevel@tonic-gate if (n > prec) { 380*0Sstevel@tonic-gate prec = n; 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate #endif 384*0Sstevel@tonic-gate /* Set translate table for digits */ 385*0Sstevel@tonic-gate if (fcode == 'X') { 386*0Sstevel@tonic-gate tab = "0123456789ABCDEF"; 387*0Sstevel@tonic-gate } else { 388*0Sstevel@tonic-gate tab = "0123456789abcdef"; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* Develop the digits of the value */ 392*0Sstevel@tonic-gate p = bp = buf + MAXDIGS; 393*0Sstevel@tonic-gate while (val) { 394*0Sstevel@tonic-gate lowbit = val & 1; 395*0Sstevel@tonic-gate val = (val >> 1) & ~HIBITLL; 396*0Sstevel@tonic-gate *--bp = tab[val % hradix * 2 + lowbit]; 397*0Sstevel@tonic-gate val /= hradix; 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate /* Calculate padding zero requirement */ 401*0Sstevel@tonic-gate lzero = bp - p + prec; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate /* Handle the # flag */ 404*0Sstevel@tonic-gate if (fsharp && bp != p) { 405*0Sstevel@tonic-gate switch (fcode) { 406*0Sstevel@tonic-gate case 'o': 407*0Sstevel@tonic-gate if (lzero < 1) 408*0Sstevel@tonic-gate lzero = 1; 409*0Sstevel@tonic-gate break; 410*0Sstevel@tonic-gate case 'x': 411*0Sstevel@tonic-gate prefix = "0x"; 412*0Sstevel@tonic-gate break; 413*0Sstevel@tonic-gate case 'X': 414*0Sstevel@tonic-gate prefix = "0X"; 415*0Sstevel@tonic-gate break; 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate break; 420*0Sstevel@tonic-gate #if FLOAT 421*0Sstevel@tonic-gate case 'E': 422*0Sstevel@tonic-gate case 'e': 423*0Sstevel@tonic-gate /* 424*0Sstevel@tonic-gate * E-format. The general strategy 425*0Sstevel@tonic-gate * here is fairly easy: we take 426*0Sstevel@tonic-gate * what ecvt gives us and re-format it. 427*0Sstevel@tonic-gate */ 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate /* Establish default precision */ 430*0Sstevel@tonic-gate if (prec < 0) { 431*0Sstevel@tonic-gate prec = 6; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* Fetch the value */ 435*0Sstevel@tonic-gate dval = va_arg(*args, double); 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* Develop the mantissa */ 438*0Sstevel@tonic-gate bp = ecvt(dval, 439*0Sstevel@tonic-gate min(prec + 1, MAXECVT), 440*0Sstevel@tonic-gate &decpt, 441*0Sstevel@tonic-gate &sign); 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate /* Determine the prefix */ 444*0Sstevel@tonic-gate e_merge: 445*0Sstevel@tonic-gate if (sign) { 446*0Sstevel@tonic-gate prefix = "-"; 447*0Sstevel@tonic-gate } else if (fplus) { 448*0Sstevel@tonic-gate prefix = "+"; 449*0Sstevel@tonic-gate } else if (fblank) { 450*0Sstevel@tonic-gate prefix = " "; 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* Place the first digit in the buffer */ 454*0Sstevel@tonic-gate p = &buf[0]; 455*0Sstevel@tonic-gate *p++ = *bp != '\0' ? *bp++ : '0'; 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate /* Put in a decimal point if needed */ 458*0Sstevel@tonic-gate if (prec != 0 || fsharp) { 459*0Sstevel@tonic-gate *p++ = '.'; 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate /* Create the rest of the mantissa */ 463*0Sstevel@tonic-gate rzero = prec; 464*0Sstevel@tonic-gate while (rzero > 0 && *bp != '\0') { 465*0Sstevel@tonic-gate --rzero; 466*0Sstevel@tonic-gate *p++ = *bp++; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate bp = &buf[0]; 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate /* Create the exponent */ 472*0Sstevel@tonic-gate suffix = &expbuf[MAXESIZ]; 473*0Sstevel@tonic-gate *suffix = '\0'; 474*0Sstevel@tonic-gate if (dval != 0) { 475*0Sstevel@tonic-gate n = decpt - 1; 476*0Sstevel@tonic-gate if (n < 0) { 477*0Sstevel@tonic-gate n = -n; 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate while (n != 0) { 480*0Sstevel@tonic-gate *--suffix = todigit(n % 10); 481*0Sstevel@tonic-gate n /= 10; 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* Prepend leading zeroes to the exponent */ 486*0Sstevel@tonic-gate while (suffix > &expbuf[MAXESIZ - 2]) { 487*0Sstevel@tonic-gate *--suffix = '0'; 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate /* Put in the exponent sign */ 491*0Sstevel@tonic-gate *--suffix = (decpt > 0 || dval == 0) ? 492*0Sstevel@tonic-gate '+' : '-'; 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* Put in the e */ 495*0Sstevel@tonic-gate *--suffix = isupper(fcode) ? 'E' : 'e'; 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate break; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate case 'f': 500*0Sstevel@tonic-gate /* 501*0Sstevel@tonic-gate * F-format floating point. This is 502*0Sstevel@tonic-gate * a good deal less simple than E-format. 503*0Sstevel@tonic-gate * The overall strategy will be to call 504*0Sstevel@tonic-gate * fcvt, reformat its result into buf, 505*0Sstevel@tonic-gate * and calculate how many trailing 506*0Sstevel@tonic-gate * zeroes will be required. There will 507*0Sstevel@tonic-gate * never be any leading zeroes needed. 508*0Sstevel@tonic-gate */ 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate /* Establish default precision */ 511*0Sstevel@tonic-gate if (prec < 0) { 512*0Sstevel@tonic-gate prec = 6; 513*0Sstevel@tonic-gate } 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* Fetch the value */ 516*0Sstevel@tonic-gate dval = va_arg(*args, double); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate /* Do the conversion */ 519*0Sstevel@tonic-gate bp = fcvt(dval, 520*0Sstevel@tonic-gate min(prec, MAXFCVT), 521*0Sstevel@tonic-gate &decpt, 522*0Sstevel@tonic-gate &sign); 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate /* Determine the prefix */ 525*0Sstevel@tonic-gate f_merge: 526*0Sstevel@tonic-gate if (sign && decpt > -prec && 527*0Sstevel@tonic-gate *bp != '\0' && *bp != '0') { 528*0Sstevel@tonic-gate prefix = "-"; 529*0Sstevel@tonic-gate } else if (fplus) { 530*0Sstevel@tonic-gate prefix = "+"; 531*0Sstevel@tonic-gate } else if (fblank) { 532*0Sstevel@tonic-gate prefix = " "; 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* Initialize buffer pointer */ 536*0Sstevel@tonic-gate p = &buf[0]; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate /* Emit the digits before the decimal point */ 539*0Sstevel@tonic-gate n = decpt; 540*0Sstevel@tonic-gate k = 0; 541*0Sstevel@tonic-gate if (n <= 0) { 542*0Sstevel@tonic-gate *p++ = '0'; 543*0Sstevel@tonic-gate } else { 544*0Sstevel@tonic-gate do { 545*0Sstevel@tonic-gate if (*bp == '\0' || 546*0Sstevel@tonic-gate k >= MAXFSIG) { 547*0Sstevel@tonic-gate *p++ = '0'; 548*0Sstevel@tonic-gate } else { 549*0Sstevel@tonic-gate *p++ = *bp++; 550*0Sstevel@tonic-gate ++k; 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate } while (--n != 0); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate /* Decide whether we need a decimal point */ 556*0Sstevel@tonic-gate if (fsharp || prec > 0) { 557*0Sstevel@tonic-gate *p++ = '.'; 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate /* Digits (if any) after the decimal point */ 561*0Sstevel@tonic-gate n = min(prec, MAXFCVT); 562*0Sstevel@tonic-gate rzero = prec - n; 563*0Sstevel@tonic-gate while (--n >= 0) { 564*0Sstevel@tonic-gate if (++decpt <= 0 || *bp == '\0' || 565*0Sstevel@tonic-gate k >= MAXFSIG) { 566*0Sstevel@tonic-gate *p++ = '0'; 567*0Sstevel@tonic-gate } else { 568*0Sstevel@tonic-gate *p++ = *bp++; 569*0Sstevel@tonic-gate ++k; 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate bp = &buf[0]; 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate break; 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate case 'G': 578*0Sstevel@tonic-gate case 'g': 579*0Sstevel@tonic-gate /* 580*0Sstevel@tonic-gate * g-format. We play around a bit 581*0Sstevel@tonic-gate * and then jump into e or f, as needed. 582*0Sstevel@tonic-gate */ 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate /* Establish default precision */ 585*0Sstevel@tonic-gate if (prec < 0) { 586*0Sstevel@tonic-gate prec = 6; 587*0Sstevel@tonic-gate } 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate /* Fetch the value */ 590*0Sstevel@tonic-gate dval = va_arg(*args, double); 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* Do the conversion */ 593*0Sstevel@tonic-gate bp = ecvt(dval, 594*0Sstevel@tonic-gate min(prec, MAXECVT), 595*0Sstevel@tonic-gate &decpt, 596*0Sstevel@tonic-gate &sign); 597*0Sstevel@tonic-gate if (dval == 0) { 598*0Sstevel@tonic-gate decpt = 1; 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate k = prec; 602*0Sstevel@tonic-gate if (!fsharp) { 603*0Sstevel@tonic-gate n = strlen(bp); 604*0Sstevel@tonic-gate if (n < k) { 605*0Sstevel@tonic-gate k = n; 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate while (k >= 1 && bp[k-1] == '0') { 608*0Sstevel@tonic-gate --k; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate if (decpt < -3 || decpt > prec) { 613*0Sstevel@tonic-gate prec = k - 1; 614*0Sstevel@tonic-gate goto e_merge; 615*0Sstevel@tonic-gate } else { 616*0Sstevel@tonic-gate prec = k - decpt; 617*0Sstevel@tonic-gate goto f_merge; 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate #endif 621*0Sstevel@tonic-gate case 'c': 622*0Sstevel@tonic-gate #ifdef MBCHAR_1 /* sizeof(int)>=sizeof(tchar) */ 623*0Sstevel@tonic-gate /* 624*0Sstevel@tonic-gate * A tchar arg is passed as int so we used the normal %c to specify 625*0Sstevel@tonic-gate * such an arugument. 626*0Sstevel@tonic-gate */ 627*0Sstevel@tonic-gate tcbuf[0] = va_arg(*args, int); 628*0Sstevel@tonic-gate tbp = &tcbuf[0]; 629*0Sstevel@tonic-gate tep = tbp + 1; 630*0Sstevel@tonic-gate fcode = 't'; /* Fake the rest of code. */ 631*0Sstevel@tonic-gate break; 632*0Sstevel@tonic-gate #else 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * We would have to invent another new format speficier such as "%T" to 635*0Sstevel@tonic-gate * take a tchar arg. Let's worry about when that time comes. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate /* 638*0Sstevel@tonic-gate * Following code take care of a char arg 639*0Sstevel@tonic-gate * only. 640*0Sstevel@tonic-gate */ 641*0Sstevel@tonic-gate buf[0] = va_arg(*args, int); 642*0Sstevel@tonic-gate bp = &buf[0]; 643*0Sstevel@tonic-gate p = bp + 1; 644*0Sstevel@tonic-gate break; 645*0Sstevel@tonic-gate case 'T': /* Corresponding arg is tchar. */ 646*0Sstevel@tonic-gate tcbuf[0] = va_arg(*args, tchar); 647*0Sstevel@tonic-gate tbp = &tcbuf[0]; 648*0Sstevel@tonic-gate tep = tbp + 1; 649*0Sstevel@tonic-gate fcode = 't'; /* Fake the rest of code. */ 650*0Sstevel@tonic-gate break; 651*0Sstevel@tonic-gate #endif 652*0Sstevel@tonic-gate case 's': 653*0Sstevel@tonic-gate bp = va_arg(*args, char *); 654*0Sstevel@tonic-gate if (bp == 0) { 655*0Sstevel@tonic-gate nullstr: bp = "(null)"; 656*0Sstevel@tonic-gate p = bp + strlen("(null)"); 657*0Sstevel@tonic-gate break; 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate if (prec < 0) { 660*0Sstevel@tonic-gate prec = MAXINT; 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate for (n = 0; *bp++ != '\0' && n < prec; n++) 663*0Sstevel@tonic-gate ; 664*0Sstevel@tonic-gate p = --bp; 665*0Sstevel@tonic-gate bp -= n; 666*0Sstevel@tonic-gate break; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate case 't': 669*0Sstevel@tonic-gate /* 670*0Sstevel@tonic-gate * Special format specifier "%t" tells 671*0Sstevel@tonic-gate * printf() to print char strings written 672*0Sstevel@tonic-gate * as tchar string. 673*0Sstevel@tonic-gate */ 674*0Sstevel@tonic-gate tbp = va_arg(*args, tchar *); 675*0Sstevel@tonic-gate if (tbp == 0) { 676*0Sstevel@tonic-gate fcode = 's'; /* Act as if it were %s. */ 677*0Sstevel@tonic-gate goto nullstr; 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate if (prec < 0) { 680*0Sstevel@tonic-gate prec = MAXINT; 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate for (n = 0; *tbp++ != 0 && n < prec; n++) 683*0Sstevel@tonic-gate ; 684*0Sstevel@tonic-gate tep = --tbp; 685*0Sstevel@tonic-gate tbp -= n; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate /* 688*0Sstevel@tonic-gate * Just to make the following padding 689*0Sstevel@tonic-gate * calculation not to go very crazy... 690*0Sstevel@tonic-gate */ 691*0Sstevel@tonic-gate bp = NULL; 692*0Sstevel@tonic-gate p = bp + n; 693*0Sstevel@tonic-gate break; 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate case '\0': 696*0Sstevel@tonic-gate cp--; 697*0Sstevel@tonic-gate break; 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate default: 700*0Sstevel@tonic-gate p = bp = &fcode; 701*0Sstevel@tonic-gate p++; 702*0Sstevel@tonic-gate break; 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate if (fcode != '\0') { 706*0Sstevel@tonic-gate /* Calculate number of padding blanks */ 707*0Sstevel@tonic-gate int nblank; 708*0Sstevel@tonic-gate nblank = width 709*0Sstevel@tonic-gate #if FLOAT 710*0Sstevel@tonic-gate - (rzero < 0 ? 0: rzero) 711*0Sstevel@tonic-gate - strlen(suffix) 712*0Sstevel@tonic-gate #endif 713*0Sstevel@tonic-gate - (p - bp) 714*0Sstevel@tonic-gate - (lzero < 0 ? 0 : lzero) 715*0Sstevel@tonic-gate - strlen(prefix); 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate /* Blanks on left if required */ 718*0Sstevel@tonic-gate if (!fminus) { 719*0Sstevel@tonic-gate while (--nblank >= 0) { 720*0Sstevel@tonic-gate Putchar(' '); 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate /* Prefix, if any */ 725*0Sstevel@tonic-gate while (*prefix != '\0') { 726*0Sstevel@tonic-gate Putchar(*prefix++); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate /* Zeroes on the left */ 730*0Sstevel@tonic-gate while (--lzero >= 0) { 731*0Sstevel@tonic-gate Putchar('0'); 732*0Sstevel@tonic-gate } 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate /* The value itself */ 735*0Sstevel@tonic-gate if (fcode == 't') { /* %t is special. */ 736*0Sstevel@tonic-gate while (tbp < tep) { 737*0Sstevel@tonic-gate Putchar(*tbp++); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate } else { /* For rest of the cases. */ 740*0Sstevel@tonic-gate while (bp < p) { 741*0Sstevel@tonic-gate putbyte(*bp++); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate #if FLOAT 745*0Sstevel@tonic-gate /* Zeroes on the right */ 746*0Sstevel@tonic-gate while (--rzero >= 0) 747*0Sstevel@tonic-gate Putchar('0'); 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate /* The suffix */ 750*0Sstevel@tonic-gate while (*suffix != '\0') { 751*0Sstevel@tonic-gate Putchar(*suffix++); 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate #endif 754*0Sstevel@tonic-gate /* Blanks on the right if required */ 755*0Sstevel@tonic-gate if (fminus) { 756*0Sstevel@tonic-gate while (--nblank >= 0) { 757*0Sstevel@tonic-gate Putchar(' '); 758*0Sstevel@tonic-gate } 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate } 763