diff options
Diffstat (limited to 'builtins/printf.def')
-rw-r--r-- | builtins/printf.def | 346 |
1 files changed, 78 insertions, 268 deletions
diff --git a/builtins/printf.def b/builtins/printf.def index bcf625c..8821ecb 100644 --- a/builtins/printf.def +++ b/builtins/printf.def @@ -1,7 +1,7 @@ This file is printf.def, from which is created printf.c. It implements the builtin "printf" in Bash. -Copyright (C) 1997 Free Software Foundation, Inc. +Copyright (C) 1997-2002 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -56,18 +56,17 @@ $END #include "../bashansi.h" -#define NEED_STRTOIMAX_DECL - #include "../shell.h" #include "stdc.h" #include "bashgetopt.h" #include "common.h" -/* This should use the ISO C constant format strings; I'll do that later. */ -#if SIZEOF_LONG < SIZEOF_LONG_LONG -# define INTMAX_CONV "ll" -#else -# define INTMAX_CONV "l" +#if !defined (PRIdMAX) +# if HAVE_LONG_LONG +# define PRIdMAX "lld" +# else +# define PRIdMAX "ld" +# endif #endif #if !defined (errno) @@ -104,25 +103,28 @@ extern int errno; #define SKIP1 "#'-+ 0" #define LENMODS "hjlLtz" +static void printf_erange __P((char *)); static void printstr __P((char *, char *, int, int, int)); static int tescape __P((char *, int, char *, int *)); static char *bexpand __P((char *, int, int *, int *)); -static char *mklong __P((char *, char *)); +static char *mklong __P((char *, char *, size_t)); static int getchr __P((void)); static char *getstr __P((void)); static int getint __P((void)); -static long getlong __P((void)); -static unsigned long getulong __P((void)); -#if defined (HAVE_LONG_LONG) -static long long getllong __P((void)); -static unsigned long long getullong __P((void)); -#endif static intmax_t getintmax __P((void)); static uintmax_t getuintmax __P((void)); -static double getdouble __P((void)); + #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD -static long double getldouble __P((void)); +typedef long double floatmax_t; +# define FLOATMAX_CONV "L" +# define strtofltmax strtold +#else +typedef double floatmax_t; +# define FLOATMAX_CONV "" +# define strtofltmax strtod #endif +static floatmax_t getfloatmax __P((void)); + static int asciicode __P((void)); static WORD_LIST *garglist; @@ -138,18 +140,15 @@ printf_builtin (list) { int ch, fieldwidth, precision; int have_fieldwidth, have_precision; - long tw; + intmax_t tw; char convch, thisch, nextch, *format, *modstart, *fmt, *start; conversion_error = 0; retval = EXECUTION_SUCCESS; - reset_internal_getopt (); - if (internal_getopt (list, "") != -1) - { - builtin_usage(); - return (EX_USAGE); - } - list = loptend; + + if (no_options (list)) + return (EX_USAGE); + list = loptend; /* skip over possible `--' */ if (list == 0) { @@ -288,7 +287,7 @@ printf_builtin (list) bind_var_to_int (var, tw); else { - builtin_error ("%s: invalid variable name", var); + sh_invalidid (var); PRETURN (EXECUTION_FAILURE); } } @@ -322,7 +321,10 @@ printf_builtin (list) char *p, *xp; p = getstr (); - xp = sh_backslash_quote (p); + if (ansic_shouldquote (p)) + xp = ansic_quote (p, 0, (int *)0); + else + xp = sh_backslash_quote (p); if (xp) { /* Use printstr to get fieldwidth and precision right. */ @@ -336,32 +338,23 @@ printf_builtin (list) case 'i': { char *f; -#if defined (HAVE_LONG_LONG) - if (thisch == 'l' && nextch == 'l') - { - long long p; + long p; + intmax_t pp; - p = getllong (); - f = mklong (start, "ll"); - PF(f, p); - } - else -#endif - if (thisch == 'j') + p = pp = getintmax (); + if (p != pp) { - intmax_t p; - - p = getintmax (); - f = mklong (start, INTMAX_CONV); - PF(f, p); + f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); + PF (f, pp); } else { - long p; - - p = getlong (); - f = mklong (start, "l"); - PF(f, p); + /* Optimize the common case where the integer fits + in "long". This also works around some long + long and/or intmax_t library bugs in the common + case, e.g. glibc 2.2 x86. */ + f = mklong (start, "l", 1); + PF (f, p); } break; } @@ -372,31 +365,18 @@ printf_builtin (list) case 'X': { char *f; -#if defined (HAVE_LONG_LONG) - if (thisch == 'l' && nextch == 'l') - { - unsigned long long p; + unsigned long p; + uintmax_t pp; - p = getullong (); - f = mklong (start, "ll"); - PF(f, p); - } - else -#endif - if (thisch == 'j') + p = pp = getuintmax (); + if (p != pp) { - uintmax_t p; - - p = getuintmax (); - f = mklong (start, INTMAX_CONV); - PF(f, p); + f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); + PF (f, pp); } else { - unsigned long p; - - p = getulong (); - f = mklong (start, "l"); + f = mklong (start, "l", 1); PF (f, p); } break; @@ -414,24 +394,11 @@ printf_builtin (list) #endif { char *f; -#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD - if (thisch == 'L') - { - long double p; - - p = getldouble (); - f = mklong (start, "L"); - PF (f, p); - } - else -#endif - { - double p; + floatmax_t p; - p = getdouble (); - f = mklong (start, ""); - PF (f, p); - } + p = getfloatmax (); + f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1); + PF (f, p); break; } @@ -454,6 +421,13 @@ printf_builtin (list) PRETURN (retval); } +static void +printf_erange (s) + char *s; +{ + builtin_error ("warning: %s: %s", s, strerror(ERANGE)); +} + /* We duplicate a lot of what printf(3) does here. */ static void printstr (fmt, string, len, fieldwidth, precision) @@ -605,16 +579,11 @@ tescape (estart, trans_squote, cp, sawc) /* %b octal constants are `\0' followed by one, two, or three octal digits... */ case '0': - for (temp = 3, evalue = 0; ISOCTAL (*p) && temp--; p++) - evalue = (evalue * 8) + OCTVALUE (*p); - *cp = evalue & 0xFF; - break; - /* but, as an extension, the other echo-like octal escape sequences are supported as well. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': - for (temp = 2, evalue = c - '0'; ISOCTAL (*p) && temp--; p++) + for (temp = 2+(c=='0'), evalue = c - '0'; ISOCTAL (*p) && temp--; p++) evalue = (evalue * 8) + OCTVALUE (*p); *cp = evalue & 0xFF; break; @@ -706,14 +675,14 @@ bexpand (string, len, sawc, lenp) } static char * -mklong (str, modifiers) +mklong (str, modifiers, mlen) char *str; char *modifiers; + size_t mlen; { - size_t len, slen, mlen; + size_t len, slen; slen = strlen (str); - mlen = strlen (modifiers); len = slen + mlen + 1; if (len > conv_bufsize) @@ -759,152 +728,24 @@ getstr () static int getint () { - long ret; + intmax_t ret; - ret = getlong (); + ret = getintmax (); if (ret > INT_MAX) { - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); + printf_erange (garglist->word->word); ret = INT_MAX; } else if (ret < INT_MIN) { - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); + printf_erange (garglist->word->word); ret = INT_MIN; } return ((int)ret); } -static long -getlong () -{ - long ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtol (garglist->word->word, &ep, 0); - - if (*ep) - { - builtin_error ("%s: invalid number", garglist->word->word); - /* POSIX.2 says ``...a diagnostic message shall be written to standard - error, and the utility shall not exit with a zero exit status, but - shall continue processing any remaining operands and shall write the - value accumulated at the time the error was detected to standard - output.'' Yecch. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); - - garglist = garglist->next; - return (ret); -} - -static unsigned long -getulong () -{ - unsigned long ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoul (garglist->word->word, &ep, 0); - - if (*ep) - { - builtin_error ("%s: invalid number", garglist->word->word); - /* Same thing about POSIX.2 conversion error requirements as getlong(). */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); - - garglist = garglist->next; - return (ret); -} - -#if defined (HAVE_LONG_LONG) - -static long long -getllong () -{ - long long ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoll (garglist->word->word, &ep, 0); - - if (*ep) - { - builtin_error ("%s: invalid number", garglist->word->word); - /* POSIX.2 says ``...a diagnostic message shall be written to standard - error, and the utility shall not exit with a zero exit status, but - shall continue processing any remaining operands and shall write the - value accumulated at the time the error was detected to standard - output.'' Yecch. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); - - garglist = garglist->next; - return (ret); -} - -static unsigned long long -getullong () -{ - unsigned long long ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return asciicode (); - - errno = 0; - ret = strtoull (garglist->word->word, &ep, 0); - - if (*ep) - { - builtin_error ("%s: invalid number", garglist->word->word); - /* Same thing about POSIX.2 conversion error requirements as getlong(). */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); - - garglist = garglist->next; - return (ret); -} - -#endif /* HAVE_LONG_LONG */ - static intmax_t getintmax () { @@ -922,7 +763,7 @@ getintmax () if (*ep) { - builtin_error ("%s: invalid number", garglist->word->word); + sh_invalidnum (garglist->word->word); /* POSIX.2 says ``...a diagnostic message shall be written to standard error, and the utility shall not exit with a zero exit status, but shall continue processing any remaining operands and shall write the @@ -932,7 +773,7 @@ getintmax () conversion_error = 1; } else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); + printf_erange (garglist->word->word); garglist = garglist->next; return (ret); @@ -955,22 +796,22 @@ getuintmax () if (*ep) { - builtin_error ("%s: invalid number", garglist->word->word); - /* Same thing about POSIX.2 conversion error requirements as getlong(). */ + sh_invalidnum (garglist->word->word); + /* Same POSIX.2 conversion error requirements as getintmax(). */ ret = 0; conversion_error = 1; } else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); + printf_erange (garglist->word->word); garglist = garglist->next; return (ret); } -static double -getdouble () +static floatmax_t +getfloatmax () { - double ret; + floatmax_t ret; char *ep; if (garglist == 0) @@ -980,52 +821,21 @@ getdouble () return asciicode (); errno = 0; - ret = strtod (garglist->word->word, &ep); - - if (*ep) - { - builtin_error ("%s: invalid number", garglist->word->word); - /* Same thing about POSIX.2 conversion error requirements. */ - ret = 0; - conversion_error = 1; - } - else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); - - garglist = garglist->next; - return (ret); -} - -#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD -static long double -getldouble () -{ - long double ret; - char *ep; - - if (garglist == 0) - return (0); - - if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') - return (asciicode ()); - - errno = 0; - ret = strtold (garglist->word->word, &ep); + ret = strtofltmax (garglist->word->word, &ep); if (*ep) { - builtin_error ("%s: invalid number", garglist->word->word); + sh_invalidnum (garglist->word->word); /* Same thing about POSIX.2 conversion error requirements. */ ret = 0; conversion_error = 1; } else if (errno == ERANGE) - builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE)); + printf_erange (garglist->word->word); garglist = garglist->next; return (ret); } -#endif /* HAVE_LONG_DOUBLE && HAVE_DECL_STRTOLD */ /* NO check is needed for garglist here. */ static int |