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