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 2, 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 int tescape __P((char *, int, char *, int *));
84 static char *bexpand __P((char *, int, int *, int *));
85 static char *mklong __P((char *, int));
86 static int getchr __P((void));
87 static char *getstr __P((void));
88 static int getint __P((void));
89 static int getlong __P((long *));
90 static int getulong __P((unsigned long *));
91 static double getdouble __P((void));
92 static int asciicode __P((void));
94 static WORD_LIST *garglist;
97 extern char *backslash_quote ();
100 printf_builtin (list)
103 int ch, end, fieldwidth, precision, foundmod, fmtlen;
104 char convch, nextch, *format, *fmt, *start;
106 retval = EXECUTION_SUCCESS;
107 reset_internal_getopt ();
108 while ((ch = internal_getopt (list, "")) != -1)
126 if (list->word->word == 0 || list->word->word[0] == '\0')
127 return (EXECUTION_SUCCESS);
129 format = list->word->word;
131 garglist = list->next;
133 /* If the format string is empty after preprocessing, return immediately. */
134 if (format == 0 || *format == 0)
135 return (EXECUTION_SUCCESS);
137 /* Basic algorithm is to scan the format string for conversion
138 specifications -- once one is found, find out if the field
139 width or precision is a '*'; if it is, gather up value. Note,
140 format strings are reused as necessary to use up the provided
141 arguments, arguments of zero/null string are provided to use
142 up the format string. */
146 /* find next format specification */
147 for (fmt = format; *fmt; fmt++)
149 precision = fieldwidth = foundmod = 0;
154 /* A NULL third argument to tescape means to not do special
155 processing for \c. */
156 fmt += tescape (fmt, 1, &nextch, (int *)NULL);
158 fmt--; /* for loop will increment it for us again */
168 /* ASSERT(*fmt == '%') */
171 if (*fmt == '%') /* %% prints a % */
177 /* found format specification, skip to field width */
178 for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
180 fieldwidth = (*fmt == '*') ? getint () : 0;
182 /* skip to possible '.', get following precision */
183 for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
188 precision = (*fmt == '*') ? getint () : 0;
191 /* skip to conversion char */
192 for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
195 /* skip possible format modifiers */
196 if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
204 builtin_error ("`%s': missing format character", start);
205 PRETURN (EXECUTION_FAILURE);
231 case 'b': /* expand escapes in argument */
238 xp = bexpand (p, strlen (p), &ch, &rlen);
242 /* Have to use printstr because of possible NUL bytes
243 in XP -- printf does not handle that well. */
244 printstr (start, xp, rlen, fieldwidth, precision);
253 case 'q': /* print with shell quoting */
258 xp = backslash_quote (p);
261 /* Use printstr to get fieldwidth and precision right. */
262 printstr (start, xp, strlen (xp), fieldwidth, precision);
274 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
275 PRETURN (EXECUTION_FAILURE);
279 PRETURN (EXECUTION_FAILURE);
292 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
293 PRETURN (EXECUTION_FAILURE);
297 PRETURN (EXECUTION_FAILURE);
315 /* We don't output unrecognized format characters; we print an
316 error message and return a failure exit status. */
318 builtin_error ("`%c': invalid format character", convch);
319 PRETURN (EXECUTION_FAILURE);
325 while (garglist && garglist != list->next);
330 /* We duplicate a lot of what printf(3) does here. */
332 printstr (fmt, string, len, fieldwidth, precision)
333 char *fmt; /* format */
334 char *string; /* expanded string argument */
335 int len; /* length of expanded string */
336 int fieldwidth; /* argument for width of `*' */
337 int precision; /* argument for precision of `*' */
342 int padlen, nc, ljust, i;
343 int fw, pr; /* fieldwidth and precision */
345 if (string == 0 || *string == '\0')
357 while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
364 /* get fieldwidth, if present */
370 else if (isdigit (*fmt))
373 while (isdigit (*fmt))
374 fw = (fw * 10) + (*fmt++ - '0');
377 /* get precision, if present */
386 else if (isdigit (*fmt))
389 while (isdigit (*fmt))
390 pr = (pr * 10) + (*fmt++ - '0');
395 /* If we remove this, get rid of `s'. */
396 if (*fmt != 'b' && *fmt != 'q')
398 internal_error ("format parsing problem: %s", s);
403 /* chars from string to print */
404 nc = (pr > 0 && pr <= len) ? pr : len;
412 /* leading pad characters */
413 for (; padlen > 0; padlen--)
416 /* output NC characters from STRING */
417 for (i = 0; i < nc; i++)
420 /* output any necessary trailing padding */
421 for (; padlen < 0; padlen++)
425 /* Convert STRING by expanding the escape sequences specified by the
426 POSIX standard for printf's `%b' format string. If SAWC is non-null,
427 recognize `\c' and use that as a string terminator. If we see \c, set
428 *SAWC to 1 before returning. LEN is the length of STRING. */
434 #define isoctal(c) ((c) >= '0' && (c) <= '7')
436 #define OCTVALUE(c) ((c) - '0')
439 # define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
442 #define HEXVALUE(c) \
443 ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
445 /* Translate a single backslash-escape sequence starting at ESTART (the
446 character after the backslash) and return the number of characters
447 consumed by the sequence. CP is the place to return the translated
448 value. *SAWC is set to 1 if the escape sequence was \c, since that means
449 to short-circuit the rest of the processing. If SAWC is null, we don't
450 do the \c short-circuiting, and \c is treated as an unrecognized escape
453 tescape (estart, trans_squote, cp, sawc)
466 #if defined (__STDC__)
467 case 'a': *cp = '\a'; break;
469 case 'a': *cp = '\007'; break;
472 case 'b': *cp = '\b'; break;
474 case 'e': *cp = '\033'; break; /* ESC -- non-ANSI */
476 case 'f': *cp = '\f'; break;
478 case 'n': *cp = '\n'; break;
480 case 'r': *cp = '\r'; break;
482 case 't': *cp = '\t'; break;
484 case 'v': *cp = '\v'; break;
486 /* %b octal constants are `\0' followed by one, two, or three
489 for (temp = 3, evalue = 0; isoctal (*p) && temp--; p++)
490 evalue = (evalue * 8) + OCTVALUE (*p);
494 /* but, as an extension, the other echo-like octal escape
495 sequences are supported as well. */
496 case '1': case '2': case '3': case '4':
497 case '5': case '6': case '7':
498 for (temp = 2, evalue = c - '0'; isoctal (*p) && temp--; p++)
499 evalue = (evalue * 8) + OCTVALUE (*p);
503 /* And, as another extension, we allow \xNNN, where each N is a
506 for (temp = 3, evalue = 0; isxdigit (*p) && temp--; p++)
507 evalue = (evalue * 16) + HEXVALUE (*p);
510 builtin_error ("missing hex digit for \\x");
517 case '\\': /* \\ -> \ */
521 case '\'': /* TRANS_SQUOTE != 0 means \' -> ' */
537 /* other backslash escapes are passed through unaltered */
546 bexpand (string, len, sawc, lenp)
548 int len, *sawc, *lenp;
551 char *ret, *r, *s, c;
553 if (string == 0 || *string == '\0')
559 return ((char *)NULL);
562 ret = xmalloc (len + 1);
563 for (r = ret, s = string; s && *s; )
566 if (c != '\\' || *s == '\0')
572 s += tescape (s, 0, &c, &temp);
594 static char copy[64];
597 len = strlen (str) + 2;
598 FASTCOPY (str, copy, len - 3);
601 copy[len - 1] = '\0';
613 ret = (int)garglist->word->word[0];
614 garglist = garglist->next;
626 ret = garglist->word->word;
627 garglist = garglist->next;
641 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
661 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
663 *lp = (long)asciicode ();
668 /* If we use 0 as the third argument, we can handle octal and hex, which
669 legal_number does not. (This was
670 if (legal_number (garglist->word->word, &ret) == 0)
672 ret = strtol (garglist->word->word, &ep, 0);
675 builtin_error ("%s: invalid number", garglist->word->word);
678 else if (errno == ERANGE)
680 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
685 garglist = garglist->next;
698 *ulp = (unsigned long)0;
702 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
704 *ulp = (unsigned long)asciicode ();
709 ret = strtoul (garglist->word->word, &ep, 0);
713 builtin_error ("%s: invalid number", garglist->word->word);
716 else if (errno == ERANGE)
718 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
723 garglist = garglist->next;
735 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
736 return ((double)asciicode ());
738 /* This should use strtod if it is available. */
739 ret = atof (garglist->word->word);
740 garglist = garglist->next;
744 /* NO check is needed for garglist here. */
750 ch = garglist->word->word[1];
751 garglist = garglist->next;