hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

printf.c (7588B)


      1 /*
      2  * printf - print a text string
      3  *
      4  * Gunnar Ritter, Freiburg i. Br., Germany, June 2005.
      5  */
      6 /*
      7  * Copyright (c) 2005 Gunnar Ritter
      8  *
      9  * This software is provided 'as-is', without any express or implied
     10  * warranty. In no event will the authors be held liable for any damages
     11  * arising from the use of this software.
     12  *
     13  * Permission is granted to anyone to use this software for any purpose,
     14  * including commercial applications, and to alter it and redistribute
     15  * it freely, subject to the following restrictions:
     16  *
     17  * 1. The origin of this software must not be misrepresented; you must not
     18  *    claim that you wrote the original software. If you use this software
     19  *    in a product, an acknowledgment in the product documentation would be
     20  *    appreciated but is not required.
     21  *
     22  * 2. Altered source versions must be plainly marked as such, and must not be
     23  *    misrepresented as being the original software.
     24  *
     25  * 3. This notice may not be removed or altered from any source distribution.
     26  */
     27 
     28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
     29 #define	USED	__attribute__ ((used))
     30 #elif defined __GNUC__
     31 #define	USED	__attribute__ ((unused))
     32 #else
     33 #define	USED
     34 #endif
     35 static const char sccsid[] USED = "@(#)printf.c	1.7 (gritter) 7/17/05";
     36 
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <libgen.h>
     40 #include <locale.h>
     41 #include <wchar.h>
     42 #include <limits.h>
     43 #include <errno.h>
     44 #include "asciitype.h"
     45 
     46 #if defined (__GLIBC__) && defined (_IO_getc_unlocked)
     47 #undef	putchar
     48 #define	putchar(c)	_IO_putc_unlocked(c, stdout)
     49 #endif
     50 
     51 static char		*fp;		/* format pointer */
     52 static int		a;		/* current argument index */
     53 static int		ab;		/* beginning of arguments */
     54 static int		ac;		/* argc to main() */
     55 static char		**av;		/* argv to main() */
     56 static int		c;		/* last character (byte) read */
     57 static const char	*progname;	/* argv[0] to main() */
     58 static int		status;		/* exit status */
     59 static int		mb_cur_max;	/* MB_CUR_MAX */
     60 static int		dolflag;	/* n$ field encountered */
     61 
     62 static void
     63 usage(void)
     64 {
     65 	fprintf(stderr, "Usage: %s format [[[arg1] arg2] ... argn]\n",
     66 			progname);
     67 	exit(2);
     68 }
     69 
     70 #define	getnum(T, type, func)	static type \
     71 T(const char *cp) \
     72 { \
     73 	char	*xp; \
     74 	wchar_t	wc; \
     75 	int	i; \
     76 	type	n; \
     77 \
     78 	if (*cp == '"' || *cp == '\'') { \
     79 		if (mb_cur_max > 1 && cp[1] & 0200) { \
     80 			if ((i = mbtowc(&wc, &cp[1], mb_cur_max)) < 0) \
     81 				return WEOF; \
     82 			return wc; \
     83 		} else \
     84 			return cp[1] & 0377; \
     85 	} \
     86 	errno = 0; \
     87 	n = func(cp, &xp); \
     88 	if (errno) { \
     89 		fprintf(stderr, "%s: \"%s\" arithmetic overflow\n", \
     90 			progname, cp); \
     91 		status |= 1; \
     92 		xp = ""; \
     93 	} \
     94 	if (*xp) { \
     95 		fprintf(stderr, "%s: \"%s\" %s\n", progname, cp, \
     96 			xp > cp ? "not completely converted" : \
     97 				"expected numeric value"); \
     98 		status |= 1; \
     99 	} \
    100 	return n; \
    101 }
    102 
    103 #define	getint(a, b)	strtol(a, b, 0)
    104 #define	getuns(a, b)	strtoul(a, b, 0)
    105 #define	getdouble(a, b)	strtod(a, b)
    106 
    107 getnum(integer, int, getint)
    108 getnum(unsgned, unsigned, getuns)
    109 getnum(floating, double, getdouble)
    110 
    111 static int
    112 backslash(int bflag, int really)
    113 {
    114 	int	c, i, n, z = 1;
    115 
    116 	fp++;
    117 	if (mb_cur_max > 1 && *fp & 0200) {
    118 		if ((n = mblen(fp, mb_cur_max)) < 0)
    119 			n = 1;
    120 	} else
    121 		n = 1;
    122 	switch (*fp) {
    123 	case '\0':
    124 		n = 0;
    125 		/*FALLTHRU*/
    126 	case '\\':
    127 		if (really) putchar('\\');
    128 		break;
    129 	case 'a':
    130 		if (really) putchar('\a');
    131 		break;
    132 	case 'b':
    133 		if (really) putchar('\b');
    134 		break;
    135 	case 'c':
    136 		if (bflag) {
    137 			if (really)
    138 				exit(status);
    139 			else {
    140 				while (*fp)
    141 					fp++;
    142 				return 0;
    143 			}
    144 		}
    145 		goto dfl;
    146 	case 'f':
    147 		if (really) putchar('\f');
    148 		break;
    149 	case 'n':
    150 		if (really) putchar('\n');
    151 		break;
    152 	case 'r':
    153 		if (really) putchar('\r');
    154 		break;
    155 	case 't':
    156 		if (really) putchar('\t');
    157 		break;
    158 	case 'v':
    159 		if (really) putchar('\v');
    160 		break;
    161 	case '0':
    162 		if (bflag) {
    163 			if (fp[1]) {
    164 				fp++;
    165 				goto digit;
    166 			}
    167 			if (really) putchar('\0');
    168 			break;
    169 		}
    170 		/*FALLTHRU*/
    171 	case '1': case '2': case '3':
    172 	case '4': case '5': case '6': case '7':
    173 		if (bflag)
    174 			goto dfl;
    175 	digit:	c = 0;
    176 		for (i = 0; i < 3 && octalchar(fp[i] & 0377); i++)
    177 			c = c << 3 | (fp[i] - '0');
    178 		if (really) putchar(c);
    179 		n = i;
    180 		break;
    181 	default:
    182 	dfl:	for (i = 0; i < n; i++)
    183 			if (really) putchar(fp[i] & 0377);
    184 		z = n;
    185 	}
    186 	fp += n - 1;
    187 	return z;
    188 }
    189 
    190 static void
    191 bconv(int width, int prec, char *sp)
    192 {
    193 	char	*ofp = fp;
    194 	int	i, n, really = 1;
    195 
    196 	fp = sp;
    197 	if (width > 0) {
    198 		really = 0;
    199 		goto try;
    200 	prt:	really = 1;
    201 		fp = sp;
    202 		for (i = 0; i < width - n && i + n < prec; i++)
    203 			putchar(' ');
    204 	}
    205 try:	for (n = 0; *fp && n < prec; fp++) {
    206 		switch (*fp) {
    207 		case '\\':
    208 			n += backslash(1, really);
    209 			break;
    210 		default:
    211 			if (really) putchar(*fp & 0377);
    212 			n++;
    213 		}
    214 	}
    215 	if (width > 0 && really == 0)
    216 		goto prt;
    217 	fp = ofp;
    218 	if (width < 0) {
    219 		while (n < prec && n++ < -width)
    220 			putchar(' ');
    221 	}
    222 }
    223 
    224 #define	nextarg()	(a < ac ? av[a++] : "")
    225 static void
    226 percent(void)
    227 {
    228 	char	*fmt = fp, *sp;
    229 	int	width = 0, prec = LONG_MAX;
    230 	int	n;
    231 	double	f;
    232 	int	c;
    233 	int	star = 0;
    234 	int	sign = 1;
    235 
    236 	if (*++fp == '\0') {
    237 		fp--;
    238 		return;
    239 	}
    240 	if (digitchar(*fp&0377)) {
    241 		n = 0;
    242 		for (sp = fp; digitchar(*sp&0377); sp++)
    243 			n = n * 10 + *sp - '0';
    244 		if (*sp == '$') {
    245 			a = n + ab - 1;
    246 			dolflag = 1;
    247 			fmt = sp;
    248 			fmt[0] = '%';
    249 			fp = &sp[1];
    250 		}
    251 	}
    252 loop:	switch (*fp) {
    253 	case '-':
    254 		sign = -1;
    255 		/*FALLTHRU*/
    256 	case '+':
    257 	case '#':
    258 	case '0':
    259 	case ' ':
    260 		fp++;
    261 		goto loop;
    262 	}
    263 	if (digitchar(*fp&0377)) {
    264 		do
    265 			width = width * 10 + *fp++ - '0';
    266 		while (digitchar(*fp&0377));
    267 	} else if (*fp == '*') {
    268 		width = a < ac ? integer(av[a++]) : 0;
    269 		fp++;
    270 		star |= 1;
    271 	}
    272 	width *= sign;
    273 	if (*fp == '.') {
    274 		fp++;
    275 		if (digitchar(*fp&0377)) {
    276 			prec = 0;
    277 			do
    278 				prec = prec * 10 + *fp++ - '0';
    279 			while (digitchar(*fp&0377));
    280 		} else if (*fp == '*') {
    281 			prec = a < ac ? integer(av[a++]) : 0;
    282 			fp++;
    283 			star |= 2;
    284 		}
    285 	}
    286 	switch (*fp) {
    287 	case 'b':
    288 		bconv(width, prec, nextarg());
    289 		return;
    290 	case '%':
    291 		putchar('%');
    292 		return;
    293 	case 'd':
    294 	case 'i':
    295 	case 'o':
    296 	case 'u':
    297 	case 'x':
    298 	case 'X':
    299 	case 'c':
    300 		n = *fp == 'c' ? *(nextarg()) & 0377 :
    301 			*fp == 'd' || *fp == 'i' ?
    302 				integer(nextarg()) :
    303 				unsgned(nextarg());
    304 		c = fp[1];
    305 		fp[1] = '\0';
    306 		switch (star) {
    307 		case 3:
    308 			printf(fmt, width, prec, n);
    309 			break;
    310 		case 2:
    311 			printf(fmt, prec, n);
    312 			break;
    313 		case 1:
    314 			printf(fmt, width, n);
    315 			break;
    316 		default:
    317 			printf(fmt, n);
    318 		}
    319 		fp[1] = c;
    320 		break;
    321 	case 'f':
    322 	case 'e':
    323 	case 'E':
    324 	case 'g':
    325 	case 'G':
    326 		f = floating(nextarg());
    327 		c = fp[1];
    328 		fp[1] = '\0';
    329 		switch (star) {
    330 		case 3:
    331 			printf(fmt, width, prec, f);
    332 			break;
    333 		case 2:
    334 			printf(fmt, prec, f);
    335 			break;
    336 		case 1:
    337 			printf(fmt, width, f);
    338 			break;
    339 		default:
    340 			printf(fmt, f);
    341 		}
    342 		fp[1] = c;
    343 		break;
    344 	case 's':
    345 		c = fp[1];
    346 		fp[1] = '\0';
    347 		sp = nextarg();
    348 		switch (star) {
    349 		case 3:
    350 			printf(fmt, width, prec, sp);
    351 			break;
    352 		case 2:
    353 			printf(fmt, prec, sp);
    354 			break;
    355 		case 1:
    356 			printf(fmt, width, sp);
    357 			break;
    358 		default:
    359 			printf(fmt, sp);
    360 		}
    361 		fp[1] = c;
    362 		break;
    363 	default:
    364 		putchar(*fp & 0377);
    365 		return;
    366 	}
    367 }
    368 
    369 int
    370 main(int argc, char **argv)
    371 {
    372 	setlocale(LC_CTYPE, "");
    373 	mb_cur_max = MB_CUR_MAX;
    374 	progname = basename(argv[0]);
    375 	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-' &&
    376 			argv[1][2] == '\0') {
    377 		argv++;
    378 		argc--;
    379 	}
    380 	if (argc <= 1)
    381 		usage();
    382 	ac = argc;
    383 	av = argv;
    384 	a = ab = 2;
    385 	do {
    386 		for (fp = av[1]; *fp; fp++) {
    387 			switch (c = *fp & 0377) {
    388 			case '\\':
    389 				backslash(0, 1);
    390 				break;
    391 			case '%':
    392 				percent();
    393 				break;
    394 			default:
    395 				putchar(c);
    396 			}
    397 		}
    398 	} while (a > ab && a < ac && dolflag == 0);
    399 	if (ferror(stdout))
    400 		status |= 1;
    401 	return status;
    402 }