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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #if !defined(BUILTIN) && !defined(SHELL)
36 static char copyright[] =
37 "@(#) Copyright (c) 1989, 1993\n\
38 The Regents of the University of California. All rights reserved.\n";
43 static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
46 #include <sys/types.h>
61 static char sbuf[1024];
64 /* Gee, I wish sprintf could be reliably counted upon to return the
65 number of characters written :-( */
70 sprintf(sbuf, f, fieldwidth, precision, func); \
72 sprintf(sbuf, f, fieldwidth, func); \
74 sprintf(sbuf, f, precision, func); \
76 sprintf(sbuf, f, func); \
77 spaddstr (sbuf, strlen (sbuf)); \
80 static int asciicode __P((void));
81 static void escape __P((char *));
82 static int getchr __P((void));
83 static double getdouble __P((void));
84 static int getint __P((int *));
85 static int getlong __P((long *));
86 static char *getstr __P((void));
87 static char *mklong __P((char *, int));
88 static void usage __P((void));
96 int sprintf_builtin ();
97 static int sprintf_main ();
98 static void spaddstr ();
100 extern char *this_command_name;
101 extern char *single_quote ();
102 extern char **make_builtin_argv ();
104 static char *sprintf_doc[] = {
105 "sprintf formats and outputs its arguments, after the second, under control",
106 "of the format and assigns the result to the variable named by its first",
107 "argument. The format is a character string which contains three types",
108 "of objects: plain characters, which are simply copied to the output string,",
109 "character escape sequences which are converted and copied to the output",
110 "string, and format specifications, each of which causes printing of the",
111 "next successive argument. In addition to the standard sprintf(3) formats,",
112 "%b means to expand escapes in the corresponding argument, and %q means",
113 "to quote the argument in a way that can be reused as shell input. Each",
114 "one of the format specifications must not expand to more than 1024",
115 "characters, though there is no limit on the total size of the output",
120 struct builtin sprintf_struct = {
125 "sprintf var format [arguments]",
130 sprintf_builtin (list)
141 return (EXECUTION_FAILURE);
144 varname = list->word->word;
147 if (legal_identifier (varname) == 0)
149 builtin_error ("%s: not a legal variable name", varname);
150 return (EXECUTION_FAILURE);
155 outstr = xmalloc (outsize = 64);
158 v = make_builtin_argv (list, &c);
159 r = sprintf_main (c, v);
162 var = bind_variable (varname, outstr);
163 if (readonly_p (var))
165 builtin_error ("%s: readonly variable", varname);
166 return (EXECUTION_FAILURE);
177 RESIZE_MALLOCED_BUFFER (outstr, outind, len, outsize, 64);
178 strcpy (outstr + outind, str);
183 sprintf_main(argc, argv)
188 static char *skip1, *skip2;
189 int ch, end, fieldwidth, precision;
190 char convch, nextch, *format, *fmt, *start;
192 while ((ch = getopt(argc, argv, "")) != EOF)
208 * Basic algorithm is to scan the format string for conversion
209 * specifications -- once one is found, find out if the field
210 * width or precision is a '*'; if it is, gather up value. Note,
211 * format strings are reused as necessary to use up the provided
212 * arguments, arguments of zero/null string are provided to use
213 * up the format string.
216 skip2 = "*0123456789";
218 escape(fmt = format = *argv); /* backslash interpretation */
222 /* find next format specification */
223 next: for (start = fmt;; ++fmt) {
225 /* avoid infinite loop */
227 warnx("missing format character",
233 (void)printf("%s", start);
244 (void)printf("%s", start);
249 /* skip to field width */
250 for (; strchr(skip1, *fmt); ++fmt);
252 if (getint(&fieldwidth))
257 /* skip to possible '.', get following precision */
258 for (; strchr(skip2, *fmt); ++fmt);
262 if (getint(&precision))
267 /* skip to conversion char */
268 for (; strchr(skip2, *fmt); ++fmt);
270 warnx("missing format character", NULL, NULL);
292 case 'b': { /* expand escapes in argument */
300 case 'q': { /* print with shell single quoting */
304 p2 = single_quote(p);
309 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
313 if ((f = mklong(start, convch)) == NULL)
320 case 'e': case 'E': case 'f': case 'g': case 'G': {
328 warnx("illegal format character", NULL, NULL);
341 static char copy[64];
344 len = strlen(str) + 2;
345 memmove(copy, str, len - 3);
348 copy[len - 1] = '\0';
356 register char *store;
357 register int value, c;
359 for (store = fmt; c = *fmt; ++fmt, ++store) {
365 case '\0': /* EOS, user error */
369 case '\\': /* backslash */
370 case '\'': /* single quote */
373 case 'a': /* bell/alert */
376 case 'b': /* backspace */
385 case 'f': /* form-feed */
388 case 'n': /* newline */
391 case 'r': /* carriage-return */
394 case 't': /* horizontal tab */
397 case 'v': /* vertical tab */
401 case '0': case '1': case '2': case '3':
402 case '4': case '5': case '6': case '7':
403 for (c = 3, value = 0;
404 c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
424 return ((int)**gargv++);
435 static char *Number = "+-.0123456789";
445 warnx("%s: %s", *gargv, strerror(ERANGE));
463 if (strchr(Number, **gargv)) {
465 val = strtol(*gargv, &ep, 0);
467 warnx("%s: illegal number", *gargv, NULL);
471 if (val == LONG_MAX) {
472 warnx("%s: %s", *gargv, strerror(ERANGE));
475 if (val == LONG_MIN) {
476 warnx("%s: %s", *gargv, strerror(ERANGE));
484 *lp = (long)asciicode();
493 if (strchr(Number, **gargv))
494 return (atof(*gargv++));
495 return ((double)asciicode());
504 if (ch == '\'' || ch == '"')
513 (void)fprintf(stderr, "usage: printf format [arg ...]\n");