1 This file is printf.def, from which is created printf.c.
2 It implements the builtin "printf" in Bash.
4 Copyright (C) 1997 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 1, or (at your option) any later
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
25 $FUNCTION printf_builtin
26 $SHORT_DOC printf format [arguments]
27 printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
28 is a character string which contains three types of objects: plain
29 characters, which are simply copied to standard output, character escape
30 sequences which are converted and copied to the standard output, and
31 format specifications, each of which causes printing of the next successive
32 argument. In addition to the standard printf(1) formats, %b means to
33 expand backslash escape sequences in the corresponding argument, and %q
34 means to quote the argument in a way that can be reused as shell input.
39 #include "../bashtypes.h"
42 #if defined (HAVE_LIMITS_H)
45 /* Assume 32-bit ints and longs. */
46 # define LONG_MAX 2147483647L
47 # define LONG_MIN (-2147483647L-1)
48 # define INT_MAX 2147483647
49 # define INT_MIN (-2147483647-1)
55 #include "../bashansi.h"
58 #include "bashgetopt.h"
66 if (fieldwidth && precision) \
67 (void)printf(f, fieldwidth, precision, func); \
68 else if (fieldwidth && precision == 0) \
69 (void)printf(f, fieldwidth, func); \
71 (void)printf(f, precision, func); \
73 (void)printf(f, func); \
76 #define PRETURN(value) \
77 do { free (format); fflush (stdout); return (value); } while (0)
80 #define SKIP2 "*0123456789"
82 static void printstr __P((char *, char *, int, int, int));
83 static char *bexpand __P((char *, int, int *, int *));
84 static char *mklong __P((char *, int));
85 static int getchr __P((void));
86 static char *getstr __P((void));
87 static int getint __P((void));
88 static int getlong __P((long *));
89 static int getulong __P((unsigned long *));
90 static double getdouble __P((void));
91 static int asciicode __P((void));
93 static WORD_LIST *garglist;
96 extern char *backslash_quote ();
102 int ch, end, fieldwidth, precision, foundmod, fmtlen;
103 char convch, nextch, *format, *fmt, *start;
105 retval = EXECUTION_SUCCESS;
106 reset_internal_getopt ();
107 while ((ch = internal_getopt (list, "")) != -1)
125 if (list->word->word == 0 || list->word->word[0] == '\0')
126 return (EXECUTION_SUCCESS);
128 format = ansicstr (list->word->word, strlen (list->word->word), (int *)NULL, &fmtlen);
130 garglist = list->next;
132 /* If the format string is empty after preprocessing, return immediately. */
133 if ((format == 0 || *format == 0) && fmtlen == 0)
134 return (EXECUTION_SUCCESS);
136 /* Basic algorithm is to scan the format string for conversion
137 specifications -- once one is found, find out if the field
138 width or precision is a '*'; if it is, gather up value. Note,
139 format strings are reused as necessary to use up the provided
140 arguments, arguments of zero/null string are provided to use
141 up the format string. */
142 #define FMTIND (fmt - format)
146 /* find next format specification */
147 for (fmt = format; FMTIND < fmtlen; fmt++)
149 precision = fieldwidth = foundmod = 0;
157 /* ASSERT(*fmt == '%') */
160 if (*fmt == '%') /* %% prints a % */
166 /* found format specification, skip to field width */
167 for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
169 fieldwidth = (*fmt == '*') ? getint () : 0;
171 /* skip to possible '.', get following precision */
172 for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
177 precision = (*fmt == '*') ? getint () : 0;
180 /* skip to conversion char */
181 for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
184 /* skip possible format modifiers */
185 if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
193 builtin_error ("`%s': missing format character", start);
194 PRETURN (EXECUTION_FAILURE);
220 case 'b': /* expand escapes in argument */
227 xp = bexpand (p, strlen (p), &ch, &rlen);
231 /* Have to use printstr because of possible NUL bytes
232 in XP -- printf does not handle that well. */
233 printstr (start, xp, rlen, fieldwidth, precision);
242 case 'q': /* print with shell quoting */
247 xp = backslash_quote (p);
250 /* Use printstr to get fieldwidth and precision right. */
251 printstr (start, xp, strlen (xp), fieldwidth, precision);
263 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
264 PRETURN (EXECUTION_FAILURE);
268 PRETURN (EXECUTION_FAILURE);
281 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
282 PRETURN (EXECUTION_FAILURE);
286 PRETURN (EXECUTION_FAILURE);
304 /* We output unrecognized format characters, but we print a
305 warning message and return a failure exit status. */
307 builtin_error ("`%c': illegal format character", convch);
308 PRETURN (EXECUTION_FAILURE);
314 while (garglist && garglist != list->next);
319 /* We duplicate a lot of what printf(3) does here. */
321 printstr (fmt, string, len, fieldwidth, precision)
322 char *fmt; /* format */
323 char *string; /* expanded string argument */
324 int len; /* length of expanded string */
325 int fieldwidth; /* argument for width of `*' */
326 int precision; /* argument for precision of `*' */
331 int padlen, nc, ljust, i;
332 int fw, pr; /* fieldwidth and precision */
334 if (string == 0 || *string == '\0')
346 while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
353 /* get fieldwidth, if present */
359 else if (isdigit (*fmt))
362 while (isdigit (*fmt))
363 fw = (fw * 10) + (*fmt++ - '0');
366 /* get precision, if present */
375 else if (isdigit (*fmt))
378 while (isdigit (*fmt))
379 pr = (pr * 10) + (*fmt++ - '0');
384 /* If we remove this, get rid of `s'. */
385 if (*fmt != 'b' && *fmt != 'q')
387 internal_error ("format parsing problem: %s", s);
392 /* chars from string to print */
393 nc = (pr > 0 && pr <= len) ? pr : len;
401 /* leading pad characters */
402 for (; padlen > 0; padlen--)
405 /* output NC characters from STRING */
406 for (i = 0; i < nc; i++)
409 /* output any necessary trailing padding */
410 for (; padlen < 0; padlen++)
414 /* Convert STRING by expanding the escape sequences specified by the
415 POSIX standard for printf's `%b' format string. If SAWC is non-null,
416 recognize `\c' and use that as a string terminator. If we see \c, set
417 *SAWC to 1 before returning. LEN is the length of STRING. */
423 #define isoctal(c) ((c) >= '0' && (c) <= '7')
425 #define OCTVALUE(c) ((c) - '0')
428 # define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
431 #define HEXVALUE(c) \
432 ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
435 bexpand (string, len, sawc, lenp)
437 int len, *sawc, *lenp;
442 if (string == 0 || *string == '\0')
448 return ((char *)NULL);
451 ret = xmalloc (len + 1);
452 for (r = ret, s = string; s && *s; )
455 if (c != '\\' || *s == '\0')
463 #if defined (__STDC__)
464 case 'a': c = '\a'; break;
466 case 'a': c = '\007'; break;
469 case 'b': c = '\b'; break;
471 case 'e': c = '\033'; break; /* ESC -- non-ANSI */
473 case 'f': c = '\f'; break;
475 case 'n': c = '\n'; break;
477 case 'r': c = '\r'; break;
479 case 't': c = '\t'; break;
481 case 'v': c = '\v'; break;
483 /* %b octal constants are `\0' followed by one, two, or three
486 for (temp = 3, c = 0; isoctal (*s) && temp--; s++)
487 c = (c * 8) + OCTVALUE (*s);
490 /* but, as an extension, the other echo-like octal escape
491 sequences are supported as well. */
492 case '1': case '2': case '3': case '4':
493 case '5': case '6': case '7':
494 for (temp = 2, c -= '0'; isoctal (*s) && temp--; s++)
495 c = (c * 8) + OCTVALUE (*s);
498 /* And, as another extension, we allow \xNNN, where each N is a
501 for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
502 c = (c * 16) + HEXVALUE (*s);
505 builtin_error ("missing hex digit for \\x");
526 /* other backslash escapes are passed through unaltered */
527 default: *r++ = '\\'; break;
544 static char copy[64];
547 len = strlen (str) + 2;
548 FASTCOPY (str, copy, len - 3);
551 copy[len - 1] = '\0';
563 ret = (int)garglist->word->word[0];
564 garglist = garglist->next;
576 ret = garglist->word->word;
577 garglist = garglist->next;
591 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
610 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
612 *lp = (long)asciicode ();
617 /* legal_number does not currently detect overflow, but it should.
619 if (legal_number (garglist->word->word, &ret) == 0)
621 builtin_error ("%s: illegal number", garglist->word->word);
624 else if (errno == ERANGE)
626 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
631 garglist = garglist->next;
644 *ulp = (unsigned long)0;
648 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
650 *ulp = (unsigned long)asciicode ();
655 ret = strtoul (garglist->word->word, &ep, 0);
659 builtin_error ("%s: illegal number", garglist->word->word);
662 else if (errno == ERANGE)
664 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
669 garglist = garglist->next;
681 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
682 return ((double)asciicode ());
684 /* This should use strtod if it is available. */
685 ret = atof (garglist->word->word);
686 garglist = garglist->next;
690 /* NO check is needed for garglist here. */
696 ch = garglist->word->word[1];
697 garglist = garglist->next;