Home | History | Annotate | Download | only in csh
      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
     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
    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