Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / builtins / printf.def
index bcf625c..8821ecb 100644 (file)
@@ -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