xref: /csrg-svn/usr.bin/printf/printf.c (revision 53564)
136725Sbostic /*
236725Sbostic  * Copyright (c) 1989 The Regents of the University of California.
336725Sbostic  * All rights reserved.
436725Sbostic  *
542758Sbostic  * %sccs.include.redist.c%
636725Sbostic  */
736725Sbostic 
8*53564Smarc #if ! defined(BUILTIN) && ! defined(SHELL)
936725Sbostic #ifndef lint
1036725Sbostic char copyright[] =
1136725Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
1236725Sbostic  All rights reserved.\n";
1336725Sbostic #endif /* not lint */
1450477Sbostic #endif
1536725Sbostic 
1636725Sbostic #ifndef lint
17*53564Smarc static char sccsid[] = "@(#)printf.c	5.11 (Berkeley) 05/14/92";
1836725Sbostic #endif /* not lint */
1936725Sbostic 
20*53564Smarc 
2136725Sbostic #include <sys/types.h>
2250477Sbostic #include <errno.h>
23*53564Smarc #ifndef SHELL
2436725Sbostic #include <stdio.h>
25*53564Smarc #endif
2650477Sbostic #include <stdlib.h>
2750477Sbostic #include <string.h>
2836725Sbostic 
29*53564Smarc #ifdef SHELL
30*53564Smarc #define main printfcmd
31*53564Smarc #define err error
32*53564Smarc #include "/usr/src/devel/sh/bltin/bltin.h"
33*53564Smarc #endif
34*53564Smarc 
3536725Sbostic #define PF(f, func) { \
3636725Sbostic 	if (fieldwidth) \
3736725Sbostic 		if (precision) \
3836811Sbostic 			(void)printf(f, fieldwidth, precision, func); \
3936725Sbostic 		else \
4036811Sbostic 			(void)printf(f, fieldwidth, func); \
4136725Sbostic 	else if (precision) \
4236811Sbostic 		(void)printf(f, precision, func); \
4336725Sbostic 	else \
4436811Sbostic 		(void)printf(f, func); \
4536725Sbostic }
4636725Sbostic 
4750477Sbostic static int	 asciicode __P((void));
48*53564Smarc #ifndef SHELL
4950477Sbostic static void	 err __P((const char *fmt, ...));
50*53564Smarc #endif
5150477Sbostic static void	 escape __P((char *));
5250477Sbostic static int	 getchr __P((void));
5350477Sbostic static double	 getdouble __P((void));
5450477Sbostic static int	 getint __P((void));
5550477Sbostic static long	 getlong __P((void));
5650477Sbostic static char	*getstr __P((void));
5750477Sbostic static char	*mklong __P((char *, int));
5836725Sbostic 
5950477Sbostic static char **gargv;
6050477Sbostic 
6150477Sbostic int
6250477Sbostic #ifdef BUILTIN
6350477Sbostic progprintf(argc, argv)
6450477Sbostic #else
6536725Sbostic main(argc, argv)
6650477Sbostic #endif
6736725Sbostic 	int argc;
6836725Sbostic 	char **argv;
6936725Sbostic {
7036725Sbostic 	static char *skip1, *skip2;
7136725Sbostic 	register char *format, *fmt, *start;
7236811Sbostic 	register int end, fieldwidth, precision;
7350477Sbostic 	char convch, nextch;
7436725Sbostic 
7536725Sbostic 	if (argc < 2) {
7650477Sbostic 		(void)fprintf(stderr, "usage: printf format [arg ...]\n");
7750477Sbostic 		return (1);
7836725Sbostic 	}
7936725Sbostic 
8036725Sbostic 	/*
8136725Sbostic 	 * Basic algorithm is to scan the format string for conversion
8236725Sbostic 	 * specifications -- once one is found, find out if the field
8336725Sbostic 	 * width or precision is a '*'; if it is, gather up value.  Note,
8436725Sbostic 	 * format strings are reused as necessary to use up the provided
8536725Sbostic 	 * arguments, arguments of zero/null string are provided to use
8636725Sbostic 	 * up the format string.
8736725Sbostic 	 */
8836725Sbostic 	skip1 = "#-+ 0";
8936725Sbostic 	skip2 = "*0123456789";
9036725Sbostic 
9136725Sbostic 	escape(fmt = format = *++argv);		/* backslash interpretation */
9236725Sbostic 	gargv = ++argv;
9336811Sbostic 	for (;;) {
9436725Sbostic 		end = 0;
9536725Sbostic 		/* find next format specification */
9636725Sbostic next:		for (start = fmt;; ++fmt) {
9736725Sbostic 			if (!*fmt) {
9836725Sbostic 				/* avoid infinite loop */
9936725Sbostic 				if (end == 1) {
10050477Sbostic 					err("missing format character");
10150477Sbostic 					return (1);
10236725Sbostic 				}
10336725Sbostic 				end = 1;
10436725Sbostic 				if (fmt > start)
10536811Sbostic 					(void)printf("%s", start);
10636725Sbostic 				if (!*gargv)
10750477Sbostic 					return (0);
10836725Sbostic 				fmt = format;
10936725Sbostic 				goto next;
11036725Sbostic 			}
11136725Sbostic 			/* %% prints a % */
11238480Sbostic 			if (*fmt == '%') {
11338480Sbostic 				if (*++fmt != '%')
11438480Sbostic 					break;
11538480Sbostic 				*fmt++ = '\0';
11638480Sbostic 				(void)printf("%s", start);
11738480Sbostic 				goto next;
11838480Sbostic 			}
11936725Sbostic 		}
12036725Sbostic 
12136725Sbostic 		/* skip to field width */
12236725Sbostic 		for (; index(skip1, *fmt); ++fmt);
12336879Sbostic 		fieldwidth = *fmt == '*' ? getint() : 0;
12436879Sbostic 
12536879Sbostic 		/* skip to possible '.', get following precision */
12636725Sbostic 		for (; index(skip2, *fmt); ++fmt);
12736725Sbostic 		if (*fmt == '.')
12836725Sbostic 			++fmt;
12936879Sbostic 		precision = *fmt == '*' ? getint() : 0;
13036879Sbostic 
13136725Sbostic 		/* skip to conversion char */
13236725Sbostic 		for (; index(skip2, *fmt); ++fmt);
13336725Sbostic 		if (!*fmt) {
13450477Sbostic 			err("missing format character");
13550477Sbostic 			return (1);
13636725Sbostic 		}
13736725Sbostic 
13836725Sbostic 		convch = *fmt;
13936725Sbostic 		nextch = *++fmt;
14036725Sbostic 		*fmt = '\0';
14136725Sbostic 		switch(convch) {
14236725Sbostic 		case 'c': {
14350477Sbostic 			char p;
14450477Sbostic 
14550477Sbostic 			p = getchr();
14636725Sbostic 			PF(start, p);
14736725Sbostic 			break;
14836725Sbostic 		}
14936725Sbostic 		case 's': {
15050477Sbostic 			char *p;
15150477Sbostic 
15250477Sbostic 			p = getstr();
15336725Sbostic 			PF(start, p);
15436725Sbostic 			break;
15536725Sbostic 		}
15636729Sbostic 		case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
15750477Sbostic 			long p;
15850477Sbostic 			char *f;
15950477Sbostic 
16050477Sbostic 			if ((f = mklong(start, convch)) == NULL)
16150477Sbostic 				return (1);
16250477Sbostic 			p = getlong();
16336725Sbostic 			PF(f, p);
16436725Sbostic 			break;
16536725Sbostic 		}
16636725Sbostic 		case 'e': case 'E': case 'f': case 'g': case 'G': {
16750477Sbostic 			double p;
16850477Sbostic 
16950477Sbostic 			p = getdouble();
17036725Sbostic 			PF(start, p);
17136725Sbostic 			break;
17236725Sbostic 		}
17336725Sbostic 		default:
17450477Sbostic 			err("illegal format character.\n");
17550477Sbostic 			return (1);
17636725Sbostic 		}
17736725Sbostic 		*fmt = nextch;
17836725Sbostic 	}
17936725Sbostic 	/* NOTREACHED */
18036725Sbostic }
18136725Sbostic 
18250477Sbostic static char *
18336725Sbostic mklong(str, ch)
18450477Sbostic 	char *str;
18550477Sbostic 	int ch;
18636725Sbostic {
187*53564Smarc 	static char copy[64];
18836725Sbostic 	int len;
18936725Sbostic 
19036725Sbostic 	len = strlen(str) + 2;
191*53564Smarc 	bcopy(str, copy, len - 3);
192*53564Smarc 	copy[len - 3] = 'l';
193*53564Smarc 	copy[len - 2] = ch;
194*53564Smarc 	copy[len - 1] = '\0';
19536725Sbostic 	return(copy);
19636725Sbostic }
19736725Sbostic 
19850477Sbostic static void
19936725Sbostic escape(fmt)
20036725Sbostic 	register char *fmt;
20136725Sbostic {
20236725Sbostic 	register char *store;
20336725Sbostic 	register int value, c;
20436725Sbostic 
20536725Sbostic 	for (store = fmt; c = *fmt; ++fmt, ++store) {
20636725Sbostic 		if (c != '\\') {
20736725Sbostic 			*store = c;
20836725Sbostic 			continue;
20936725Sbostic 		}
21036725Sbostic 		switch (*++fmt) {
21136725Sbostic 		case '\0':		/* EOS, user error */
21236725Sbostic 			*store = '\\';
21336725Sbostic 			*++store = '\0';
21436725Sbostic 			return;
21536725Sbostic 		case '\\':		/* backslash */
21636728Sbostic 		case '\'':		/* single quote */
21736728Sbostic 			*store = *fmt;
21836725Sbostic 			break;
21936725Sbostic 		case 'a':		/* bell/alert */
22036725Sbostic 			*store = '\7';
22136725Sbostic 			break;
22236725Sbostic 		case 'b':		/* backspace */
22336725Sbostic 			*store = '\b';
22436725Sbostic 			break;
22536725Sbostic 		case 'f':		/* form-feed */
22636725Sbostic 			*store = '\f';
22736725Sbostic 			break;
22836725Sbostic 		case 'n':		/* newline */
22936725Sbostic 			*store = '\n';
23036725Sbostic 			break;
23136725Sbostic 		case 'r':		/* carriage-return */
23236725Sbostic 			*store = '\r';
23336725Sbostic 			break;
23436725Sbostic 		case 't':		/* horizontal tab */
23536725Sbostic 			*store = '\t';
23636725Sbostic 			break;
23736725Sbostic 		case 'v':		/* vertical tab */
23836725Sbostic 			*store = '\13';
23936725Sbostic 			break;
24036725Sbostic 					/* octal constant */
24136725Sbostic 		case '0': case '1': case '2': case '3':
24236725Sbostic 		case '4': case '5': case '6': case '7':
24336725Sbostic 			for (c = 3, value = 0;
24436725Sbostic 			    c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
24536725Sbostic 				value <<= 3;
24636725Sbostic 				value += *fmt - '0';
24736725Sbostic 			}
24836725Sbostic 			--fmt;
24936725Sbostic 			*store = value;
25036725Sbostic 			break;
25136725Sbostic 		default:
25236725Sbostic 			*store = *fmt;
25336725Sbostic 			break;
25436725Sbostic 		}
25536725Sbostic 	}
25636725Sbostic 	*store = '\0';
25736725Sbostic }
25836725Sbostic 
25950477Sbostic static int
26036725Sbostic getchr()
26136725Sbostic {
26236725Sbostic 	if (!*gargv)
26350477Sbostic 		return('\0');
26436725Sbostic 	return((int)**gargv++);
26536725Sbostic }
26636725Sbostic 
26750477Sbostic static char *
26836725Sbostic getstr()
26936725Sbostic {
27036725Sbostic 	if (!*gargv)
27136725Sbostic 		return("");
27236725Sbostic 	return(*gargv++);
27336725Sbostic }
27436725Sbostic 
275*53564Smarc static char *Number = "+-.0123456789";
27650477Sbostic static int
27736725Sbostic getint()
27836725Sbostic {
27936725Sbostic 	if (!*gargv)
28036725Sbostic 		return(0);
281*53564Smarc 	if (index(Number, **gargv))
28236725Sbostic 		return(atoi(*gargv++));
28336725Sbostic 	return(asciicode());
28436725Sbostic }
28536725Sbostic 
28650477Sbostic static long
28736725Sbostic getlong()
28836725Sbostic {
28936725Sbostic 	if (!*gargv)
29036725Sbostic 		return((long)0);
291*53564Smarc 	if (index(Number, **gargv))
29240959Sbostic 		return(strtol(*gargv++, (char **)NULL, 0));
29336725Sbostic 	return((long)asciicode());
29436725Sbostic }
29536725Sbostic 
29650477Sbostic static double
29736725Sbostic getdouble()
29836725Sbostic {
29936725Sbostic 	if (!*gargv)
30036725Sbostic 		return((double)0);
301*53564Smarc 	if (index(Number, **gargv))
30236725Sbostic 		return(atof(*gargv++));
30336725Sbostic 	return((double)asciicode());
30436725Sbostic }
30536725Sbostic 
30650477Sbostic static int
30736725Sbostic asciicode()
30836725Sbostic {
30950477Sbostic 	register int ch;
31036725Sbostic 
31136725Sbostic 	ch = **gargv;
31236725Sbostic 	if (ch == '\'' || ch == '"')
31336725Sbostic 		ch = (*gargv)[1];
31436725Sbostic 	++gargv;
31536725Sbostic 	return(ch);
31636725Sbostic }
31750477Sbostic 
318*53564Smarc #ifndef SHELL
31950477Sbostic #if __STDC__
32050477Sbostic #include <stdarg.h>
32150477Sbostic #else
32250477Sbostic #include <varargs.h>
32350477Sbostic #endif
32450477Sbostic 
32550477Sbostic static void
32650477Sbostic #if __STDC__
32750477Sbostic err(const char *fmt, ...)
32850477Sbostic #else
32950477Sbostic err(fmt, va_alist)
33050477Sbostic 	char *fmt;
33150477Sbostic 	va_dcl
33250477Sbostic #endif
33350477Sbostic {
33450477Sbostic 	va_list ap;
33550477Sbostic #if __STDC__
33650477Sbostic 	va_start(ap, fmt);
33750477Sbostic #else
33850477Sbostic 	va_start(ap);
33950477Sbostic #endif
34050477Sbostic 	(void)fprintf(stderr, "printf: ");
34150477Sbostic 	(void)vfprintf(stderr, fmt, ap);
34250477Sbostic 	va_end(ap);
34350477Sbostic 	(void)fprintf(stderr, "\n");
34450477Sbostic }
345*53564Smarc #endif /* !SHELL */
346