printf.c revision 265160
1/*-
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29/*
30 * Important: This file is used both as a standalone program /usr/bin/printf
31 * and as a builtin for /bin/sh (#define SHELL).
32 */
33
34#ifndef SHELL
35#ifndef lint
36static char const copyright[] =
37"@(#) Copyright (c) 1989, 1993\n\
38	The Regents of the University of California.  All rights reserved.\n";
39#endif /* not lint */
40#endif
41
42#ifndef lint
43#if 0
44static char const sccsid[] = "@(#)printf.c	8.1 (Berkeley) 7/20/93";
45#endif
46static const char rcsid[] =
47  "$FreeBSD: stable/10/usr.bin/printf/printf.c 265160 2014-04-30 20:39:08Z pfg $";
48#endif /* not lint */
49
50#include <sys/types.h>
51
52#include <err.h>
53#include <errno.h>
54#include <inttypes.h>
55#include <limits.h>
56#include <locale.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <unistd.h>
61#include <wchar.h>
62
63#ifdef SHELL
64#define	main printfcmd
65#include "bltin/bltin.h"
66#include "error.h"
67#include "options.h"
68#endif
69
70#define	PF(f, func) do {						\
71	char *b = NULL;							\
72	if (havewidth)							\
73		if (haveprec)						\
74			(void)asprintf(&b, f, fieldwidth, precision, func); \
75		else							\
76			(void)asprintf(&b, f, fieldwidth, func);	\
77	else if (haveprec)						\
78		(void)asprintf(&b, f, precision, func);			\
79	else								\
80		(void)asprintf(&b, f, func);				\
81	if (b) {							\
82		(void)fputs(b, stdout);					\
83		free(b);						\
84	}								\
85} while (0)
86
87static int	 asciicode(void);
88static char	*printf_doformat(char *, int *);
89static int	 escape(char *, int, size_t *);
90static int	 getchr(void);
91static int	 getfloating(long double *, int);
92static int	 getint(int *);
93static int	 getnum(intmax_t *, uintmax_t *, int);
94static const char
95		*getstr(void);
96static char	*mknum(char *, char);
97static void	 usage(void);
98
99static char **gargv;
100
101int
102main(int argc, char *argv[])
103{
104	size_t len;
105	int chopped, end, rval;
106	char *format, *fmt, *start;
107#ifndef SHELL
108	int ch;
109
110	(void) setlocale(LC_ALL, "");
111#endif
112
113#ifdef SHELL
114	nextopt("");
115	argc -= argptr - argv;
116	argv = argptr;
117#else
118	while ((ch = getopt(argc, argv, "")) != -1)
119		switch (ch) {
120		case '?':
121		default:
122			usage();
123			return (1);
124		}
125	argc -= optind;
126	argv += optind;
127#endif
128
129	if (argc < 1) {
130		usage();
131		return (1);
132	}
133
134#ifdef SHELL
135	INTOFF;
136#endif
137	/*
138	 * Basic algorithm is to scan the format string for conversion
139	 * specifications -- once one is found, find out if the field
140	 * width or precision is a '*'; if it is, gather up value.  Note,
141	 * format strings are reused as necessary to use up the provided
142	 * arguments, arguments of zero/null string are provided to use
143	 * up the format string.
144	 */
145	fmt = format = *argv;
146	chopped = escape(fmt, 1, &len);		/* backslash interpretation */
147	rval = end = 0;
148	gargv = ++argv;
149	for (;;) {
150		start = fmt;
151		while (fmt < format + len) {
152			if (fmt[0] == '%') {
153				fwrite(start, 1, fmt - start, stdout);
154				if (fmt[1] == '%') {
155					/* %% prints a % */
156					putchar('%');
157					fmt += 2;
158				} else {
159					fmt = printf_doformat(fmt, &rval);
160					if (fmt == NULL) {
161#ifdef SHELL
162						INTON;
163#endif
164						return (1);
165					}
166					end = 0;
167				}
168				start = fmt;
169			} else
170				fmt++;
171		}
172
173		if (end == 1) {
174			warnx("missing format character");
175#ifdef SHELL
176			INTON;
177#endif
178			return (1);
179		}
180		fwrite(start, 1, fmt - start, stdout);
181		if (chopped || !*gargv) {
182#ifdef SHELL
183			INTON;
184#endif
185			return (rval);
186		}
187		/* Restart at the beginning of the format string. */
188		fmt = format;
189		end = 1;
190	}
191	/* NOTREACHED */
192}
193
194
195static char *
196printf_doformat(char *start, int *rval)
197{
198	static const char skip1[] = "#'-+ 0";
199	static const char skip2[] = "0123456789";
200	char *fmt;
201	int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
202	char convch, nextch;
203
204	fmt = start + 1;
205	/* skip to field width */
206	fmt += strspn(fmt, skip1);
207	if (*fmt == '*') {
208		if (getint(&fieldwidth))
209			return (NULL);
210		havewidth = 1;
211		++fmt;
212	} else {
213		havewidth = 0;
214
215		/* skip to possible '.', get following precision */
216		fmt += strspn(fmt, skip2);
217	}
218	if (*fmt == '.') {
219		/* precision present? */
220		++fmt;
221		if (*fmt == '*') {
222			if (getint(&precision))
223				return (NULL);
224			haveprec = 1;
225			++fmt;
226		} else {
227			haveprec = 0;
228
229			/* skip to conversion char */
230			fmt += strspn(fmt, skip2);
231		}
232	} else
233		haveprec = 0;
234	if (!*fmt) {
235		warnx("missing format character");
236		return (NULL);
237	}
238
239	/*
240	 * Look for a length modifier.  POSIX doesn't have these, so
241	 * we only support them for floating-point conversions, which
242	 * are extensions.  This is useful because the L modifier can
243	 * be used to gain extra range and precision, while omitting
244	 * it is more likely to produce consistent results on different
245	 * architectures.  This is not so important for integers
246	 * because overflow is the only bad thing that can happen to
247	 * them, but consider the command  printf %a 1.1
248	 */
249	if (*fmt == 'L') {
250		mod_ldbl = 1;
251		fmt++;
252		if (!strchr("aAeEfFgG", *fmt)) {
253			warnx("bad modifier L for %%%c", *fmt);
254			return (NULL);
255		}
256	} else {
257		mod_ldbl = 0;
258	}
259
260	convch = *fmt;
261	nextch = *++fmt;
262	*fmt = '\0';
263	switch (convch) {
264	case 'b': {
265		size_t len;
266		char *p;
267		int getout;
268
269		p = strdup(getstr());
270		if (p == NULL) {
271			warnx("%s", strerror(ENOMEM));
272			return (NULL);
273		}
274		getout = escape(p, 0, &len);
275		*(fmt - 1) = 's';
276		PF(start, p);
277		*(fmt - 1) = 'b';
278		free(p);
279		if (getout)
280			return (fmt);
281		break;
282	}
283	case 'c': {
284		char p;
285
286		p = getchr();
287		PF(start, p);
288		break;
289	}
290	case 's': {
291		const char *p;
292
293		p = getstr();
294		PF(start, p);
295		break;
296	}
297	case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
298		char *f;
299		intmax_t val;
300		uintmax_t uval;
301		int signedconv;
302
303		signedconv = (convch == 'd' || convch == 'i');
304		if ((f = mknum(start, convch)) == NULL)
305			return (NULL);
306		if (getnum(&val, &uval, signedconv))
307			*rval = 1;
308		if (signedconv)
309			PF(f, val);
310		else
311			PF(f, uval);
312		break;
313	}
314	case 'e': case 'E':
315	case 'f': case 'F':
316	case 'g': case 'G':
317	case 'a': case 'A': {
318		long double p;
319
320		if (getfloating(&p, mod_ldbl))
321			*rval = 1;
322		if (mod_ldbl)
323			PF(start, p);
324		else
325			PF(start, (double)p);
326		break;
327	}
328	default:
329		warnx("illegal format character %c", convch);
330		return (NULL);
331	}
332	*fmt = nextch;
333	return (fmt);
334}
335
336static char *
337mknum(char *str, char ch)
338{
339	static char *copy;
340	static size_t copy_size;
341	char *newcopy;
342	size_t len, newlen;
343
344	len = strlen(str) + 2;
345	if (len > copy_size) {
346		newlen = ((len + 1023) >> 10) << 10;
347		if ((newcopy = realloc(copy, newlen)) == NULL)
348		{
349			warnx("%s", strerror(ENOMEM));
350			return (NULL);
351		}
352		copy = newcopy;
353		copy_size = newlen;
354	}
355
356	memmove(copy, str, len - 3);
357	copy[len - 3] = 'j';
358	copy[len - 2] = ch;
359	copy[len - 1] = '\0';
360	return (copy);
361}
362
363static int
364escape(char *fmt, int percent, size_t *len)
365{
366	char *save, *store, c;
367	int value;
368
369	for (save = store = fmt; ((c = *fmt) != 0); ++fmt, ++store) {
370		if (c != '\\') {
371			*store = c;
372			continue;
373		}
374		switch (*++fmt) {
375		case '\0':		/* EOS, user error */
376			*store = '\\';
377			*++store = '\0';
378			*len = store - save;
379			return (0);
380		case '\\':		/* backslash */
381		case '\'':		/* single quote */
382			*store = *fmt;
383			break;
384		case 'a':		/* bell/alert */
385			*store = '\a';
386			break;
387		case 'b':		/* backspace */
388			*store = '\b';
389			break;
390		case 'c':
391			*store = '\0';
392			*len = store - save;
393			return (1);
394		case 'f':		/* form-feed */
395			*store = '\f';
396			break;
397		case 'n':		/* newline */
398			*store = '\n';
399			break;
400		case 'r':		/* carriage-return */
401			*store = '\r';
402			break;
403		case 't':		/* horizontal tab */
404			*store = '\t';
405			break;
406		case 'v':		/* vertical tab */
407			*store = '\v';
408			break;
409					/* octal constant */
410		case '0': case '1': case '2': case '3':
411		case '4': case '5': case '6': case '7':
412			c = (!percent && *fmt == '0') ? 4 : 3;
413			for (value = 0;
414			    c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
415				value <<= 3;
416				value += *fmt - '0';
417			}
418			--fmt;
419			if (percent && value == '%') {
420				*store++ = '%';
421				*store = '%';
422			} else
423				*store = (char)value;
424			break;
425		default:
426			*store = *fmt;
427			break;
428		}
429	}
430	*store = '\0';
431	*len = store - save;
432	return (0);
433}
434
435static int
436getchr(void)
437{
438	if (!*gargv)
439		return ('\0');
440	return ((int)**gargv++);
441}
442
443static const char *
444getstr(void)
445{
446	if (!*gargv)
447		return ("");
448	return (*gargv++);
449}
450
451static int
452getint(int *ip)
453{
454	intmax_t val;
455	uintmax_t uval;
456	int rval;
457
458	if (getnum(&val, &uval, 1))
459		return (1);
460	rval = 0;
461	if (val < INT_MIN || val > INT_MAX) {
462		warnx("%s: %s", *gargv, strerror(ERANGE));
463		rval = 1;
464	}
465	*ip = (int)val;
466	return (rval);
467}
468
469static int
470getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
471{
472	char *ep;
473	int rval;
474
475	if (!*gargv) {
476		*ip = *uip = 0;
477		return (0);
478	}
479	if (**gargv == '"' || **gargv == '\'') {
480		if (signedconv)
481			*ip = asciicode();
482		else
483			*uip = asciicode();
484		return (0);
485	}
486	rval = 0;
487	errno = 0;
488	if (signedconv)
489		*ip = strtoimax(*gargv, &ep, 0);
490	else
491		*uip = strtoumax(*gargv, &ep, 0);
492	if (ep == *gargv) {
493		warnx("%s: expected numeric value", *gargv);
494		rval = 1;
495	}
496	else if (*ep != '\0') {
497		warnx("%s: not completely converted", *gargv);
498		rval = 1;
499	}
500	if (errno == ERANGE) {
501		warnx("%s: %s", *gargv, strerror(ERANGE));
502		rval = 1;
503	}
504	++gargv;
505	return (rval);
506}
507
508static int
509getfloating(long double *dp, int mod_ldbl)
510{
511	char *ep;
512	int rval;
513
514	if (!*gargv) {
515		*dp = 0.0;
516		return (0);
517	}
518	if (**gargv == '"' || **gargv == '\'') {
519		*dp = asciicode();
520		return (0);
521	}
522	rval = 0;
523	errno = 0;
524	if (mod_ldbl)
525		*dp = strtold(*gargv, &ep);
526	else
527		*dp = strtod(*gargv, &ep);
528	if (ep == *gargv) {
529		warnx("%s: expected numeric value", *gargv);
530		rval = 1;
531	} else if (*ep != '\0') {
532		warnx("%s: not completely converted", *gargv);
533		rval = 1;
534	}
535	if (errno == ERANGE) {
536		warnx("%s: %s", *gargv, strerror(ERANGE));
537		rval = 1;
538	}
539	++gargv;
540	return (rval);
541}
542
543static int
544asciicode(void)
545{
546	int ch;
547	wchar_t wch;
548	mbstate_t mbs;
549
550	ch = (unsigned char)**gargv;
551	if (ch == '\'' || ch == '"') {
552		memset(&mbs, 0, sizeof(mbs));
553		switch (mbrtowc(&wch, *gargv + 1, MB_LEN_MAX, &mbs)) {
554		case (size_t)-2:
555		case (size_t)-1:
556			wch = (unsigned char)gargv[0][1];
557			break;
558		case 0:
559			wch = 0;
560			break;
561		}
562		ch = wch;
563	}
564	++gargv;
565	return (ch);
566}
567
568static void
569usage(void)
570{
571	(void)fprintf(stderr, "usage: printf format [arguments ...]\n");
572}
573