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