2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
30 * Important: This file is used both as a standalone program /usr/bin/printf
31 * and as a builtin for /bin/sh (#define SHELL).
36 static char const copyright[] =
37 "@(#) Copyright (c) 1989, 1993\n\
38 The Regents of the University of California. All rights reserved.\n";
44 static char const sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
46 static const char rcsid[] =
50 #include <sys/types.h>
64 #define main printfcmd
65 #include "bltin/bltin.h"
69 #define PF(f, func) do { \
73 (void)asprintf(&b, f, fieldwidth, precision, func); \
75 (void)asprintf(&b, f, fieldwidth, func); \
77 (void)asprintf(&b, f, precision, func); \
79 (void)asprintf(&b, f, func); \
81 (void)fputs(b, stdout); \
86 static int asciicode(void);
87 static char *printf_doformat(char *, int *);
88 static int escape(char *, int, size_t *);
89 static int getchr(void);
90 static int getfloating(long double *, int);
91 static int getint(int *);
92 static int getnum(intmax_t *, uintmax_t *, int);
95 static char *mknum(char *, char);
96 static void usage(void);
101 main(int argc, char *argv[])
104 int ch, chopped, end, rval;
105 char *format, *fmt, *start;
108 (void) setlocale(LC_ALL, "");
111 optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
113 while ((ch = getopt(argc, argv, "")) != -1)
132 * Basic algorithm is to scan the format string for conversion
133 * specifications -- once one is found, find out if the field
134 * width or precision is a '*'; if it is, gather up value. Note,
135 * format strings are reused as necessary to use up the provided
136 * arguments, arguments of zero/null string are provided to use
137 * up the format string.
139 fmt = format = *argv;
140 chopped = escape(fmt, 1, &len); /* backslash interpretation */
145 while (fmt < format + len) {
147 fwrite(start, 1, fmt - start, stdout);
153 fmt = printf_doformat(fmt, &rval);
168 warnx("missing format character");
174 fwrite(start, 1, fmt - start, stdout);
175 if (chopped || !*gargv) {
181 /* Restart at the beginning of the format string. */
190 printf_doformat(char *start, int *rval)
192 static const char skip1[] = "#'-+ 0";
193 static const char skip2[] = "0123456789";
195 int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
199 /* skip to field width */
200 fmt += strspn(fmt, skip1);
202 if (getint(&fieldwidth))
209 /* skip to possible '.', get following precision */
210 fmt += strspn(fmt, skip2);
213 /* precision present? */
216 if (getint(&precision))
223 /* skip to conversion char */
224 fmt += strspn(fmt, skip2);
229 warnx("missing format character");
234 * Look for a length modifier. POSIX doesn't have these, so
235 * we only support them for floating-point conversions, which
236 * are extensions. This is useful because the L modifier can
237 * be used to gain extra range and precision, while omitting
238 * it is more likely to produce consistent results on different
239 * architectures. This is not so important for integers
240 * because overflow is the only bad thing that can happen to
241 * them, but consider the command printf %a 1.1
246 if (!strchr("aAeEfFgG", *fmt)) {
247 warnx("bad modifier L for %%%c", *fmt);
263 p = strdup(getstr());
265 warnx("%s", strerror(ENOMEM));
268 getout = escape(p, 0, &len);
291 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
297 signedconv = (convch == 'd' || convch == 'i');
298 if ((f = mknum(start, convch)) == NULL)
300 if (getnum(&val, &uval, signedconv))
311 case 'a': case 'A': {
314 if (getfloating(&p, mod_ldbl))
319 PF(start, (double)p);
323 warnx("illegal format character %c", convch);
331 mknum(char *str, char ch)
334 static size_t copy_size;
338 len = strlen(str) + 2;
339 if (len > copy_size) {
340 newlen = ((len + 1023) >> 10) << 10;
341 if ((newcopy = realloc(copy, newlen)) == NULL)
343 warnx("%s", strerror(ENOMEM));
350 memmove(copy, str, len - 3);
353 copy[len - 1] = '\0';
358 escape(char *fmt, int percent, size_t *len)
360 char *save, *store, c;
363 for (save = store = fmt; ((c = *fmt) != 0); ++fmt, ++store) {
369 case '\0': /* EOS, user error */
374 case '\\': /* backslash */
375 case '\'': /* single quote */
378 case 'a': /* bell/alert */
381 case 'b': /* backspace */
388 case 'f': /* form-feed */
391 case 'n': /* newline */
394 case 'r': /* carriage-return */
397 case 't': /* horizontal tab */
400 case 'v': /* vertical tab */
404 case '0': case '1': case '2': case '3':
405 case '4': case '5': case '6': case '7':
406 c = (!percent && *fmt == '0') ? 4 : 3;
408 c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
413 if (percent && value == '%') {
417 *store = (char)value;
434 return ((int)**gargv++);
452 if (getnum(&val, &uval, 1))
455 if (val < INT_MIN || val > INT_MAX) {
456 warnx("%s: %s", *gargv, strerror(ERANGE));
464 getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
473 if (**gargv == '"' || **gargv == '\'') {
483 *ip = strtoimax(*gargv, &ep, 0);
485 *uip = strtoumax(*gargv, &ep, 0);
487 warnx("%s: expected numeric value", *gargv);
490 else if (*ep != '\0') {
491 warnx("%s: not completely converted", *gargv);
494 if (errno == ERANGE) {
495 warnx("%s: %s", *gargv, strerror(ERANGE));
503 getfloating(long double *dp, int mod_ldbl)
512 if (**gargv == '"' || **gargv == '\'') {
519 *dp = strtold(*gargv, &ep);
521 *dp = strtod(*gargv, &ep);
523 warnx("%s: expected numeric value", *gargv);
525 } else if (*ep != '\0') {
526 warnx("%s: not completely converted", *gargv);
529 if (errno == ERANGE) {
530 warnx("%s: %s", *gargv, strerror(ERANGE));
544 ch = (unsigned char)**gargv;
545 if (ch == '\'' || ch == '"') {
546 memset(&mbs, 0, sizeof(mbs));
547 switch (mbrtowc(&wch, *gargv + 1, MB_LEN_MAX, &mbs)) {
550 wch = (unsigned char)gargv[0][1];
565 (void)fprintf(stderr, "usage: printf format [arguments ...]\n");