Home | History | Annotate | Line # | Download | only in printf
printf.c revision 1.1.1.2
      1      1.1  cgd /*
      2  1.1.1.2  mrg  * Copyright (c) 1989, 1993
      3  1.1.1.2  mrg  *	The Regents of the University of California.  All rights reserved.
      4      1.1  cgd  *
      5      1.1  cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1  cgd  * modification, are permitted provided that the following conditions
      7      1.1  cgd  * are met:
      8      1.1  cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1  cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1  cgd  *    must display the following acknowledgement:
     15      1.1  cgd  *	This product includes software developed by the University of
     16      1.1  cgd  *	California, Berkeley and its contributors.
     17      1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1  cgd  *    may be used to endorse or promote products derived from this software
     19      1.1  cgd  *    without specific prior written permission.
     20      1.1  cgd  *
     21      1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1  cgd  * SUCH DAMAGE.
     32      1.1  cgd  */
     33      1.1  cgd 
     34  1.1.1.2  mrg #if !defined(BUILTIN) && !defined(SHELL)
     35      1.1  cgd #ifndef lint
     36  1.1.1.2  mrg static char copyright[] =
     37  1.1.1.2  mrg "@(#) Copyright (c) 1989, 1993\n\
     38  1.1.1.2  mrg 	The Regents of the University of California.  All rights reserved.\n";
     39      1.1  cgd #endif /* not lint */
     40  1.1.1.2  mrg #endif
     41      1.1  cgd 
     42      1.1  cgd #ifndef lint
     43  1.1.1.2  mrg static char sccsid[] = "@(#)printf.c	8.2 (Berkeley) 3/22/95";
     44      1.1  cgd #endif /* not lint */
     45      1.1  cgd 
     46      1.1  cgd #include <sys/types.h>
     47  1.1.1.2  mrg 
     48  1.1.1.2  mrg #include <err.h>
     49  1.1.1.2  mrg #include <errno.h>
     50  1.1.1.2  mrg #include <limits.h>
     51  1.1.1.2  mrg #ifdef SHELL
     52  1.1.1.2  mrg #define	EOF	-1
     53  1.1.1.2  mrg #else
     54      1.1  cgd #include <stdio.h>
     55  1.1.1.2  mrg #endif
     56  1.1.1.2  mrg #include <stdlib.h>
     57  1.1.1.2  mrg #include <string.h>
     58  1.1.1.2  mrg 
     59  1.1.1.2  mrg /*
     60  1.1.1.2  mrg  * XXX
     61  1.1.1.2  mrg  * This *has* to go away.  TK.
     62  1.1.1.2  mrg  */
     63  1.1.1.2  mrg #ifdef SHELL
     64  1.1.1.2  mrg #define main printfcmd
     65  1.1.1.2  mrg #define warnx(a, b, c) {						\
     66  1.1.1.2  mrg 	char buf[64];							\
     67  1.1.1.2  mrg 	(void)sprintf(buf, sizeof(buf), a, b, c);			\
     68  1.1.1.2  mrg 	error(buf);							\
     69  1.1.1.2  mrg }
     70  1.1.1.2  mrg #include "../../bin/sh/bltin/bltin.h"
     71  1.1.1.2  mrg #endif
     72      1.1  cgd 
     73      1.1  cgd #define PF(f, func) { \
     74      1.1  cgd 	if (fieldwidth) \
     75      1.1  cgd 		if (precision) \
     76      1.1  cgd 			(void)printf(f, fieldwidth, precision, func); \
     77      1.1  cgd 		else \
     78      1.1  cgd 			(void)printf(f, fieldwidth, func); \
     79      1.1  cgd 	else if (precision) \
     80      1.1  cgd 		(void)printf(f, precision, func); \
     81      1.1  cgd 	else \
     82      1.1  cgd 		(void)printf(f, func); \
     83      1.1  cgd }
     84      1.1  cgd 
     85  1.1.1.2  mrg static int	 asciicode __P((void));
     86  1.1.1.2  mrg static void	 escape __P((char *));
     87  1.1.1.2  mrg static int	 getchr __P((void));
     88  1.1.1.2  mrg static double	 getdouble __P((void));
     89  1.1.1.2  mrg static int	 getint __P((int *));
     90  1.1.1.2  mrg static int	 getlong __P((long *));
     91  1.1.1.2  mrg static char	*getstr __P((void));
     92  1.1.1.2  mrg static char	*mklong __P((char *, int));
     93  1.1.1.2  mrg static void	 usage __P((void));
     94  1.1.1.2  mrg 
     95  1.1.1.2  mrg static char **gargv;
     96  1.1.1.2  mrg 
     97  1.1.1.2  mrg int
     98  1.1.1.2  mrg #ifdef BUILTIN
     99  1.1.1.2  mrg progprintf(argc, argv)
    100  1.1.1.2  mrg #else
    101      1.1  cgd main(argc, argv)
    102  1.1.1.2  mrg #endif
    103      1.1  cgd 	int argc;
    104  1.1.1.2  mrg 	char *argv[];
    105      1.1  cgd {
    106  1.1.1.2  mrg 	extern int optind;
    107      1.1  cgd 	static char *skip1, *skip2;
    108  1.1.1.2  mrg 	int ch, end, fieldwidth, precision;
    109  1.1.1.2  mrg 	char convch, nextch, *format, *fmt, *start;
    110  1.1.1.2  mrg 
    111  1.1.1.2  mrg 	while ((ch = getopt(argc, argv, "")) != EOF)
    112  1.1.1.2  mrg 		switch (ch) {
    113  1.1.1.2  mrg 		case '?':
    114  1.1.1.2  mrg 		default:
    115  1.1.1.2  mrg 			usage();
    116  1.1.1.2  mrg 			return (1);
    117  1.1.1.2  mrg 		}
    118  1.1.1.2  mrg 	argc -= optind;
    119  1.1.1.2  mrg 	argv += optind;
    120  1.1.1.2  mrg 
    121  1.1.1.2  mrg 	if (argc < 1) {
    122  1.1.1.2  mrg 		usage();
    123  1.1.1.2  mrg 		return (1);
    124      1.1  cgd 	}
    125      1.1  cgd 
    126      1.1  cgd 	/*
    127      1.1  cgd 	 * Basic algorithm is to scan the format string for conversion
    128      1.1  cgd 	 * specifications -- once one is found, find out if the field
    129      1.1  cgd 	 * width or precision is a '*'; if it is, gather up value.  Note,
    130      1.1  cgd 	 * format strings are reused as necessary to use up the provided
    131      1.1  cgd 	 * arguments, arguments of zero/null string are provided to use
    132      1.1  cgd 	 * up the format string.
    133      1.1  cgd 	 */
    134      1.1  cgd 	skip1 = "#-+ 0";
    135      1.1  cgd 	skip2 = "*0123456789";
    136      1.1  cgd 
    137  1.1.1.2  mrg 	escape(fmt = format = *argv);		/* backslash interpretation */
    138      1.1  cgd 	gargv = ++argv;
    139      1.1  cgd 	for (;;) {
    140      1.1  cgd 		end = 0;
    141      1.1  cgd 		/* find next format specification */
    142      1.1  cgd next:		for (start = fmt;; ++fmt) {
    143      1.1  cgd 			if (!*fmt) {
    144      1.1  cgd 				/* avoid infinite loop */
    145      1.1  cgd 				if (end == 1) {
    146  1.1.1.2  mrg 					warnx("missing format character",
    147  1.1.1.2  mrg 					    NULL, NULL);
    148  1.1.1.2  mrg 					return (1);
    149      1.1  cgd 				}
    150      1.1  cgd 				end = 1;
    151      1.1  cgd 				if (fmt > start)
    152      1.1  cgd 					(void)printf("%s", start);
    153      1.1  cgd 				if (!*gargv)
    154  1.1.1.2  mrg 					return (0);
    155      1.1  cgd 				fmt = format;
    156      1.1  cgd 				goto next;
    157      1.1  cgd 			}
    158      1.1  cgd 			/* %% prints a % */
    159      1.1  cgd 			if (*fmt == '%') {
    160      1.1  cgd 				if (*++fmt != '%')
    161      1.1  cgd 					break;
    162      1.1  cgd 				*fmt++ = '\0';
    163      1.1  cgd 				(void)printf("%s", start);
    164      1.1  cgd 				goto next;
    165      1.1  cgd 			}
    166      1.1  cgd 		}
    167      1.1  cgd 
    168      1.1  cgd 		/* skip to field width */
    169  1.1.1.2  mrg 		for (; strchr(skip1, *fmt); ++fmt);
    170  1.1.1.2  mrg 		if (*fmt == '*') {
    171  1.1.1.2  mrg 			if (getint(&fieldwidth))
    172  1.1.1.2  mrg 				return (1);
    173  1.1.1.2  mrg 		} else
    174  1.1.1.2  mrg 			fieldwidth = 0;
    175      1.1  cgd 
    176      1.1  cgd 		/* skip to possible '.', get following precision */
    177  1.1.1.2  mrg 		for (; strchr(skip2, *fmt); ++fmt);
    178      1.1  cgd 		if (*fmt == '.')
    179      1.1  cgd 			++fmt;
    180  1.1.1.2  mrg 		if (*fmt == '*') {
    181  1.1.1.2  mrg 			if (getint(&precision))
    182  1.1.1.2  mrg 				return (1);
    183  1.1.1.2  mrg 		} else
    184  1.1.1.2  mrg 			precision = 0;
    185      1.1  cgd 
    186      1.1  cgd 		/* skip to conversion char */
    187  1.1.1.2  mrg 		for (; strchr(skip2, *fmt); ++fmt);
    188      1.1  cgd 		if (!*fmt) {
    189  1.1.1.2  mrg 			warnx("missing format character", NULL, NULL);
    190  1.1.1.2  mrg 			return (1);
    191      1.1  cgd 		}
    192      1.1  cgd 
    193      1.1  cgd 		convch = *fmt;
    194      1.1  cgd 		nextch = *++fmt;
    195      1.1  cgd 		*fmt = '\0';
    196      1.1  cgd 		switch(convch) {
    197      1.1  cgd 		case 'c': {
    198  1.1.1.2  mrg 			char p;
    199  1.1.1.2  mrg 
    200  1.1.1.2  mrg 			p = getchr();
    201      1.1  cgd 			PF(start, p);
    202      1.1  cgd 			break;
    203      1.1  cgd 		}
    204      1.1  cgd 		case 's': {
    205  1.1.1.2  mrg 			char *p;
    206  1.1.1.2  mrg 
    207  1.1.1.2  mrg 			p = getstr();
    208      1.1  cgd 			PF(start, p);
    209      1.1  cgd 			break;
    210      1.1  cgd 		}
    211      1.1  cgd 		case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
    212  1.1.1.2  mrg 			long p;
    213  1.1.1.2  mrg 			char *f;
    214  1.1.1.2  mrg 
    215  1.1.1.2  mrg 			if ((f = mklong(start, convch)) == NULL)
    216  1.1.1.2  mrg 				return (1);
    217  1.1.1.2  mrg 			if (getlong(&p))
    218  1.1.1.2  mrg 				return (1);
    219      1.1  cgd 			PF(f, p);
    220      1.1  cgd 			break;
    221      1.1  cgd 		}
    222      1.1  cgd 		case 'e': case 'E': case 'f': case 'g': case 'G': {
    223  1.1.1.2  mrg 			double p;
    224  1.1.1.2  mrg 
    225  1.1.1.2  mrg 			p = getdouble();
    226      1.1  cgd 			PF(start, p);
    227      1.1  cgd 			break;
    228      1.1  cgd 		}
    229      1.1  cgd 		default:
    230  1.1.1.2  mrg 			warnx("illegal format character", NULL, NULL);
    231  1.1.1.2  mrg 			return (1);
    232      1.1  cgd 		}
    233      1.1  cgd 		*fmt = nextch;
    234      1.1  cgd 	}
    235      1.1  cgd 	/* NOTREACHED */
    236      1.1  cgd }
    237      1.1  cgd 
    238  1.1.1.2  mrg static char *
    239      1.1  cgd mklong(str, ch)
    240  1.1.1.2  mrg 	char *str;
    241  1.1.1.2  mrg 	int ch;
    242      1.1  cgd {
    243  1.1.1.2  mrg 	static char copy[64];
    244      1.1  cgd 	int len;
    245      1.1  cgd 
    246      1.1  cgd 	len = strlen(str) + 2;
    247  1.1.1.2  mrg 	memmove(copy, str, len - 3);
    248      1.1  cgd 	copy[len - 3] = 'l';
    249      1.1  cgd 	copy[len - 2] = ch;
    250      1.1  cgd 	copy[len - 1] = '\0';
    251  1.1.1.2  mrg 	return (copy);
    252      1.1  cgd }
    253      1.1  cgd 
    254  1.1.1.2  mrg static void
    255      1.1  cgd escape(fmt)
    256      1.1  cgd 	register char *fmt;
    257      1.1  cgd {
    258      1.1  cgd 	register char *store;
    259      1.1  cgd 	register int value, c;
    260      1.1  cgd 
    261  1.1.1.2  mrg 	for (store = fmt; (c = *fmt) != '\0'; ++fmt, ++store) {
    262      1.1  cgd 		if (c != '\\') {
    263      1.1  cgd 			*store = c;
    264      1.1  cgd 			continue;
    265      1.1  cgd 		}
    266      1.1  cgd 		switch (*++fmt) {
    267      1.1  cgd 		case '\0':		/* EOS, user error */
    268      1.1  cgd 			*store = '\\';
    269      1.1  cgd 			*++store = '\0';
    270      1.1  cgd 			return;
    271      1.1  cgd 		case '\\':		/* backslash */
    272      1.1  cgd 		case '\'':		/* single quote */
    273      1.1  cgd 			*store = *fmt;
    274      1.1  cgd 			break;
    275      1.1  cgd 		case 'a':		/* bell/alert */
    276      1.1  cgd 			*store = '\7';
    277      1.1  cgd 			break;
    278      1.1  cgd 		case 'b':		/* backspace */
    279      1.1  cgd 			*store = '\b';
    280      1.1  cgd 			break;
    281      1.1  cgd 		case 'f':		/* form-feed */
    282      1.1  cgd 			*store = '\f';
    283      1.1  cgd 			break;
    284      1.1  cgd 		case 'n':		/* newline */
    285      1.1  cgd 			*store = '\n';
    286      1.1  cgd 			break;
    287      1.1  cgd 		case 'r':		/* carriage-return */
    288      1.1  cgd 			*store = '\r';
    289      1.1  cgd 			break;
    290      1.1  cgd 		case 't':		/* horizontal tab */
    291      1.1  cgd 			*store = '\t';
    292      1.1  cgd 			break;
    293      1.1  cgd 		case 'v':		/* vertical tab */
    294      1.1  cgd 			*store = '\13';
    295      1.1  cgd 			break;
    296      1.1  cgd 					/* octal constant */
    297      1.1  cgd 		case '0': case '1': case '2': case '3':
    298      1.1  cgd 		case '4': case '5': case '6': case '7':
    299      1.1  cgd 			for (c = 3, value = 0;
    300      1.1  cgd 			    c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
    301      1.1  cgd 				value <<= 3;
    302      1.1  cgd 				value += *fmt - '0';
    303      1.1  cgd 			}
    304      1.1  cgd 			--fmt;
    305      1.1  cgd 			*store = value;
    306      1.1  cgd 			break;
    307      1.1  cgd 		default:
    308      1.1  cgd 			*store = *fmt;
    309      1.1  cgd 			break;
    310      1.1  cgd 		}
    311      1.1  cgd 	}
    312      1.1  cgd 	*store = '\0';
    313      1.1  cgd }
    314      1.1  cgd 
    315  1.1.1.2  mrg static int
    316      1.1  cgd getchr()
    317      1.1  cgd {
    318      1.1  cgd 	if (!*gargv)
    319  1.1.1.2  mrg 		return ('\0');
    320  1.1.1.2  mrg 	return ((int)**gargv++);
    321      1.1  cgd }
    322      1.1  cgd 
    323  1.1.1.2  mrg static char *
    324      1.1  cgd getstr()
    325      1.1  cgd {
    326      1.1  cgd 	if (!*gargv)
    327  1.1.1.2  mrg 		return ("");
    328  1.1.1.2  mrg 	return (*gargv++);
    329      1.1  cgd }
    330      1.1  cgd 
    331  1.1.1.2  mrg static char *Number = "+-.0123456789";
    332  1.1.1.2  mrg static int
    333  1.1.1.2  mrg getint(ip)
    334  1.1.1.2  mrg 	int *ip;
    335      1.1  cgd {
    336  1.1.1.2  mrg 	long val;
    337  1.1.1.2  mrg 
    338  1.1.1.2  mrg 	if (getlong(&val))
    339  1.1.1.2  mrg 		return (1);
    340  1.1.1.2  mrg 	if (val > INT_MAX) {
    341  1.1.1.2  mrg 		warnx("%s: %s", *gargv, strerror(ERANGE));
    342  1.1.1.2  mrg 		return (1);
    343  1.1.1.2  mrg 	}
    344  1.1.1.2  mrg 	*ip = val;
    345  1.1.1.2  mrg 	return (0);
    346      1.1  cgd }
    347      1.1  cgd 
    348  1.1.1.2  mrg static int
    349  1.1.1.2  mrg getlong(lp)
    350  1.1.1.2  mrg 	long *lp;
    351      1.1  cgd {
    352  1.1.1.2  mrg 	long val;
    353  1.1.1.2  mrg 	char *ep;
    354      1.1  cgd 
    355  1.1.1.2  mrg 	if (!*gargv) {
    356  1.1.1.2  mrg 		*lp = 0;
    357  1.1.1.2  mrg 		return (0);
    358  1.1.1.2  mrg 	}
    359  1.1.1.2  mrg 	if (strchr(Number, **gargv)) {
    360  1.1.1.2  mrg 		errno = 0;
    361  1.1.1.2  mrg 		val = strtol(*gargv, &ep, 0);
    362  1.1.1.2  mrg 		if (*ep != '\0') {
    363  1.1.1.2  mrg 			warnx("%s: illegal number", *gargv, NULL);
    364  1.1.1.2  mrg 			return (1);
    365  1.1.1.2  mrg 		}
    366  1.1.1.2  mrg 		if (errno == ERANGE)
    367  1.1.1.2  mrg 			if (val == LONG_MAX) {
    368  1.1.1.2  mrg 				warnx("%s: %s", *gargv, strerror(ERANGE));
    369  1.1.1.2  mrg 				return (1);
    370  1.1.1.2  mrg 			}
    371  1.1.1.2  mrg 			if (val == LONG_MIN) {
    372  1.1.1.2  mrg 				warnx("%s: %s", *gargv, strerror(ERANGE));
    373  1.1.1.2  mrg 				return (1);
    374  1.1.1.2  mrg 			}
    375  1.1.1.2  mrg 
    376  1.1.1.2  mrg 		*lp = val;
    377  1.1.1.2  mrg 		++gargv;
    378  1.1.1.2  mrg 		return (0);
    379  1.1.1.2  mrg 	}
    380  1.1.1.2  mrg 	*lp =  (long)asciicode();
    381  1.1.1.2  mrg 	return (0);
    382      1.1  cgd }
    383      1.1  cgd 
    384  1.1.1.2  mrg static double
    385      1.1  cgd getdouble()
    386      1.1  cgd {
    387      1.1  cgd 	if (!*gargv)
    388  1.1.1.2  mrg 		return ((double)0);
    389  1.1.1.2  mrg 	if (strchr(Number, **gargv))
    390  1.1.1.2  mrg 		return (atof(*gargv++));
    391  1.1.1.2  mrg 	return ((double)asciicode());
    392      1.1  cgd }
    393      1.1  cgd 
    394  1.1.1.2  mrg static int
    395      1.1  cgd asciicode()
    396      1.1  cgd {
    397  1.1.1.2  mrg 	register int ch;
    398      1.1  cgd 
    399      1.1  cgd 	ch = **gargv;
    400      1.1  cgd 	if (ch == '\'' || ch == '"')
    401      1.1  cgd 		ch = (*gargv)[1];
    402      1.1  cgd 	++gargv;
    403  1.1.1.2  mrg 	return (ch);
    404  1.1.1.2  mrg }
    405  1.1.1.2  mrg 
    406  1.1.1.2  mrg static void
    407  1.1.1.2  mrg usage()
    408  1.1.1.2  mrg {
    409  1.1.1.2  mrg 	(void)fprintf(stderr, "usage: printf format [arg ...]\n");
    410      1.1  cgd }
    411