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;
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, (int *)NULL);
130 garglist = list->next;
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. */
141 /* find next format specification */
142 for (fmt = format; *fmt; fmt++)
144 precision = fieldwidth = foundmod = 0;
152 /* ASSERT(*fmt == '%') */
155 if (*fmt == '%') /* %% prints a % */
161 /* found format specification, skip to field width */
162 for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
164 fieldwidth = (*fmt == '*') ? getint () : 0;
166 /* skip to possible '.', get following precision */
167 for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
172 precision = (*fmt == '*') ? getint () : 0;
175 /* skip to conversion char */
176 for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
180 builtin_error ("`%s': missing format character", start);
181 PRETURN (EXECUTION_FAILURE);
184 /* skip possible format modifiers */
185 if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
214 case 'b': /* expand escapes in argument */
221 xp = bexpand (p, strlen (p), &ch, &rlen);
225 /* Have to use printstr because of possible NUL bytes
226 in XP -- printf does not handle that well. */
227 printstr (start, xp, rlen, fieldwidth, precision);
236 case 'q': /* print with shell quoting */
241 xp = backslash_quote (p);
244 /* Use printstr to get fieldwidth and precision right. */
245 printstr (start, xp, strlen (xp), fieldwidth, precision);
257 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
258 PRETURN (EXECUTION_FAILURE);
262 PRETURN (EXECUTION_FAILURE);
275 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
276 PRETURN (EXECUTION_FAILURE);
280 PRETURN (EXECUTION_FAILURE);
298 /* We output unrecognized format characters, but we print a
299 warning message and return a failure exit status. */
301 builtin_error ("`%c': illegal format character", convch);
302 PRETURN (EXECUTION_FAILURE);
313 /* We duplicate a lot of what printf(3) does here. */
315 printstr (fmt, string, len, fieldwidth, precision)
316 char *fmt; /* format */
317 char *string; /* expanded string argument */
318 int len; /* length of expanded string */
319 int fieldwidth; /* argument for width of `*' */
320 int precision; /* argument for precision of `*' */
325 int padlen, nc, ljust, i;
326 int fw, pr; /* fieldwidth and precision */
328 if (string == 0 || *string == '\0')
340 while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
347 /* get fieldwidth, if present */
353 else if (isdigit (*fmt))
356 while (isdigit (*fmt))
357 fw = (fw * 10) + (*fmt++ - '0');
360 /* get precision, if present */
369 else if (isdigit (*fmt))
372 while (isdigit (*fmt))
373 pr = (pr * 10) + (*fmt++ - '0');
378 /* If we remove this, get rid of `s'. */
379 if (*fmt != 'b' && *fmt != 'q')
381 internal_error ("format parsing problem: %s", s);
386 /* chars from string to print */
387 nc = (pr > 0 && pr <= len) ? pr : len;
395 /* leading pad characters */
396 for (; padlen > 0; padlen--)
399 /* output NC characters from STRING */
400 for (i = 0; i < nc; i++)
403 /* output any necessary trailing padding */
404 for (; padlen < 0; padlen++)
408 /* Convert STRING by expanding the escape sequences specified by the
409 POSIX standard for printf's `%b' format string. If SAWC is non-null,
410 recognize `\c' and use that as a string terminator. If we see \c, set
411 *SAWC to 1 before returning. LEN is the length of STRING. */
417 #define isoctal(c) ((c) >= '0' && (c) <= '7')
419 #define OCTVALUE(c) ((c) - '0')
422 # define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
425 #define HEXVALUE(c) \
426 ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
429 bexpand (string, len, sawc, lenp)
431 int len, *sawc, *lenp;
436 if (string == 0 || *string == '\0')
442 return ((char *)NULL);
445 ret = xmalloc (len + 1);
446 for (r = ret, s = string; s && *s; )
449 if (c != '\\' || *s == '\0')
457 #if defined (__STDC__)
458 case 'a': c = '\a'; break;
460 case 'a': c = '\007'; break;
463 case 'b': c = '\b'; break;
465 case 'e': c = '\033'; break; /* ESC -- non-ANSI */
467 case 'f': c = '\f'; break;
469 case 'n': c = '\n'; break;
471 case 'r': c = '\r'; break;
473 case 't': c = '\t'; break;
475 case 'v': c = '\v'; break;
477 /* %b octal constants are `\0' followed by one, two, or three
480 for (temp = 3, c = 0; isoctal (*s) && temp--; s++)
481 c = (c * 8) + OCTVALUE (*s);
484 /* but, as an extension, the other echo-like octal escape
485 sequences are supported as well. */
486 case '1': case '2': case '3': case '4':
487 case '5': case '6': case '7':
488 for (temp = 2, c -= '0'; isoctal (*s) && temp--; s++)
489 c = (c * 8) + OCTVALUE (*s);
492 /* And, as another extension, we allow \xNNN, where each N is a
495 for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
496 c = (c * 16) + HEXVALUE (*s);
499 builtin_error ("missing hex digit for \\x");
520 /* other backslash escapes are passed through unaltered */
521 default: *r++ = '\\'; break;
538 static char copy[64];
541 len = strlen (str) + 2;
542 FASTCOPY (str, copy, len - 3);
545 copy[len - 1] = '\0';
557 ret = (int)garglist->word->word[0];
558 garglist = garglist->next;
570 ret = garglist->word->word;
571 garglist = garglist->next;
585 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
604 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
606 *lp = (long)asciicode ();
611 /* legal_number does not currently detect overflow, but it should.
613 if (legal_number (garglist->word->word, &ret) == 0)
615 builtin_error ("%s: illegal number", garglist->word->word);
618 else if (errno == ERANGE)
620 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
625 garglist = garglist->next;
638 *ulp = (unsigned long)0;
642 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
644 *ulp = (unsigned long)asciicode ();
649 ret = strtoul (garglist->word->word, &ep, 0);
653 builtin_error ("%s: illegal number", garglist->word->word);
656 else if (errno == ERANGE)
658 builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
663 garglist = garglist->next;
675 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
676 return ((double)asciicode ());
678 /* This should use strtod if it is available. */
679 ret = atof (garglist->word->word);
680 garglist = garglist->next;
684 /* NO check is needed for garglist here. */
690 ch = garglist->word->word[1];
691 garglist = garglist->next;