Imported from ../bash-3.1.tar.gz.
[platform/upstream/bash.git] / builtins / printf.def
index 9b377a9..e4e3170 100644 (file)
@@ -1,7 +1,7 @@
 This file is printf.def, from which is created printf.c.
 It implements the builtin "printf" in Bash.
 
 This file is printf.def, from which is created printf.c.
 It implements the builtin "printf" in Bash.
 
-Copyright (C) 1997-2003 Free Software Foundation, Inc.
+Copyright (C) 1997-2005 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -23,7 +23,7 @@ $PRODUCES printf.c
 
 $BUILTIN printf
 $FUNCTION printf_builtin
 
 $BUILTIN printf
 $FUNCTION printf_builtin
-$SHORT_DOC printf format [arguments]
+$SHORT_DOC printf [-v var] format [arguments]
 printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
 is a character string which contains three types of objects: plain
 characters, which are simply copied to standard output, character escape
 printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
 is a character string which contains three types of objects: plain
 characters, which are simply copied to standard output, character escape
@@ -32,6 +32,8 @@ format specifications, each of which causes printing of the next successive
 argument.  In addition to the standard printf(1) formats, %b means to
 expand backslash escape sequences in the corresponding argument, and %q
 means to quote the argument in a way that can be reused as shell input.
 argument.  In addition to the standard printf(1) formats, %b means to
 expand backslash escape sequences in the corresponding argument, and %q
 means to quote the argument in a way that can be reused as shell input.
+If the -v option is supplied, the output is placed into the value of the
+shell variable VAR rather than being sent to the standard output.
 $END
 
 #include <config.h>
 $END
 
 #include <config.h>
@@ -74,28 +76,61 @@ $END
 extern int errno;
 #endif
 
 extern int errno;
 #endif
 
+#define PC(c) \
+  do { \
+    char b[2]; \
+    tw++; \
+    b[0] = c; b[1] = '\0'; \
+    if (vflag) \
+      vbadd (b, 1); \
+    else \
+      putchar (c); \
+  } while (0)
+
 #define PF(f, func) \
   do { \
 #define PF(f, func) \
   do { \
+    char *b = 0; \
+    int nw; \
     if (have_fieldwidth && have_precision) \
     if (have_fieldwidth && have_precision) \
-      tw += printf(f, fieldwidth, precision, func); \
+      nw = asprintf(&b, f, fieldwidth, precision, func); \
     else if (have_fieldwidth) \
     else if (have_fieldwidth) \
-      tw += printf(f, fieldwidth, func); \
+      nw = asprintf(&b, f, fieldwidth, func); \
     else if (have_precision) \
     else if (have_precision) \
-      tw += printf(f, precision, func); \
+      nw = asprintf(&b, f, precision, func); \
     else \
     else \
-      tw += printf(f, func); \
+      nw = asprintf(&b, f, func); \
+    tw += nw; \
+    if (b) \
+      { \
+       if (vflag) \
+         (void)vbadd (b, nw); \
+       else \
+         (void)fputs (b, stdout); \
+       free (b); \
+      } \
   } while (0)
 
 /* We free the buffer used by mklong() if it's `too big'. */
 #define PRETURN(value) \
   do \
     { \
   } while (0)
 
 /* We free the buffer used by mklong() if it's `too big'. */
 #define PRETURN(value) \
   do \
     { \
+      if (vflag) \
+       { \
+         bind_variable  (vname, vbuf, 0); \
+         stupidly_hack_special_variables (vname); \
+       } \
       if (conv_bufsize > 4096 ) \
        { \
       if (conv_bufsize > 4096 ) \
        { \
-         free(conv_buf); \
+         free (conv_buf); \
          conv_bufsize = 0; \
          conv_buf = 0; \
        } \
          conv_bufsize = 0; \
          conv_buf = 0; \
        } \
+      if (vbsize > 4096) \
+       { \
+         free (vbuf); \
+         vbsize = 0; \
+         vbuf = 0; \
+       } \
       fflush (stdout); \
       return (value); \
     } \
       fflush (stdout); \
       return (value); \
     } \
@@ -105,9 +140,10 @@ extern int errno;
 #define LENMODS "hjlLtz"
 
 static void printf_erange __P((char *));
 #define LENMODS "hjlLtz"
 
 static void printf_erange __P((char *));
-static void printstr __P((char *, char *, int, int, int));
+static int printstr __P((char *, char *, int, int, int));
 static int tescape __P((char *, char *, int *));
 static char *bexpand __P((char *, int, int *, int *));
 static int tescape __P((char *, char *, int *));
 static char *bexpand __P((char *, int, int *, int *));
+static char *vbadd __P((char *, int));
 static char *mklong __P((char *, char *, size_t));
 static int getchr __P((void));
 static char *getstr __P((void));
 static char *mklong __P((char *, char *, size_t));
 static int getchr __P((void));
 static char *getstr __P((void));
@@ -132,6 +168,14 @@ static WORD_LIST *garglist;
 static int retval;
 static int conversion_error;
 
 static int retval;
 static int conversion_error;
 
+/* printf -v var support */
+static int vflag = 0;
+static char *vbuf, *vname;
+static size_t vbsize;
+static int vblen;
+
+static intmax_t tw;
+
 static char *conv_buf;
 static size_t conv_bufsize;
 
 static char *conv_buf;
 static size_t conv_bufsize;
 
@@ -141,14 +185,35 @@ printf_builtin (list)
 {
   int ch, fieldwidth, precision;
   int have_fieldwidth, have_precision;
 {
   int ch, fieldwidth, precision;
   int have_fieldwidth, have_precision;
-  intmax_t tw;
   char convch, thisch, nextch, *format, *modstart, *fmt, *start;
 
   conversion_error = 0;
   retval = EXECUTION_SUCCESS;
 
   char convch, thisch, nextch, *format, *modstart, *fmt, *start;
 
   conversion_error = 0;
   retval = EXECUTION_SUCCESS;
 
-  if (no_options (list))
-    return (EX_USAGE);
+  vflag = 0;
+
+  reset_internal_getopt ();
+  while ((ch = internal_getopt (list, "v:")) != -1)
+    {
+      switch (ch)
+       {
+       case 'v':
+         if (legal_identifier (vname = list_optarg))
+           {
+             vflag = 1;
+             vblen = 0;
+           }
+         else
+           {
+             sh_invalidid (vname);
+             return (EX_USAGE);
+           }
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
   list = loptend;      /* skip over possible `--' */
 
   if (list == 0)
   list = loptend;      /* skip over possible `--' */
 
   if (list == 0)
@@ -161,6 +226,7 @@ printf_builtin (list)
     return (EXECUTION_SUCCESS);
 
   format = list->word->word;
     return (EXECUTION_SUCCESS);
 
   format = list->word->word;
+  tw = 0;
 
   garglist = list->next;
 
 
   garglist = list->next;
 
@@ -189,14 +255,14 @@ printf_builtin (list)
              /* A NULL third argument to tescape means to bypass the
                 special processing for arguments to %b. */
              fmt += tescape (fmt, &nextch, (int *)NULL);
              /* A NULL third argument to tescape means to bypass the
                 special processing for arguments to %b. */
              fmt += tescape (fmt, &nextch, (int *)NULL);
-             putchar (nextch);
+             PC (nextch);
              fmt--;    /* for loop will increment it for us again */
              continue;
            }
 
          if (*fmt != '%')
            {
              fmt--;    /* for loop will increment it for us again */
              continue;
            }
 
          if (*fmt != '%')
            {
-             putchar (*fmt);
+             PC (*fmt);
              continue;
            }
 
              continue;
            }
 
@@ -205,7 +271,7 @@ printf_builtin (list)
 
          if (*fmt == '%')              /* %% prints a % */
            {
 
          if (*fmt == '%')              /* %% prints a % */
            {
-             putchar ('%');
+             PC ('%');
              continue;
            }
 
              continue;
            }
 
@@ -235,8 +301,20 @@ printf_builtin (list)
                  precision = getint ();
                }
              else
                  precision = getint ();
                }
              else
-               while (DIGIT (*fmt))
-                 fmt++;
+               {
+                 /* Negative precisions are allowed but treated as if the
+                    precision were missing; I would like to allow a leading
+                    `+' in the precision number as an extension, but lots
+                    of asprintf/fprintf implementations get this wrong. */
+#if 0
+                 if (*fmt == '-' || *fmt == '+')
+#else
+                 if (*fmt == '-')
+#endif
+                   fmt++;
+                 while (DIGIT (*fmt))
+                   fmt++;
+               }
            }
 
          /* skip possible format modifiers */
            }
 
          /* skip possible format modifiers */
@@ -297,21 +375,27 @@ printf_builtin (list)
            case 'b':           /* expand escapes in argument */
              {
                char *p, *xp;
            case 'b':           /* expand escapes in argument */
              {
                char *p, *xp;
-               int rlen;
+               int rlen, r;
 
                p = getstr ();
 
                p = getstr ();
-               ch = rlen = 0;
+               ch = rlen = r = 0;
                xp = bexpand (p, strlen (p), &ch, &rlen);
 
                if (xp)
                  {
                    /* Have to use printstr because of possible NUL bytes
                       in XP -- printf does not handle that well. */
                xp = bexpand (p, strlen (p), &ch, &rlen);
 
                if (xp)
                  {
                    /* Have to use printstr because of possible NUL bytes
                       in XP -- printf does not handle that well. */
-                   printstr (start, xp, rlen, fieldwidth, precision);
+                   r = printstr (start, xp, rlen, fieldwidth, precision);
+                   if (r < 0)
+                     {
+                       sh_wrerror ();
+                       clearerr (stdout);
+                       retval = EXECUTION_FAILURE;
+                     }
                    free (xp);
                  }
 
                    free (xp);
                  }
 
-               if (ch)
+               if (ch || r < 0)
                  PRETURN (retval);
                break;
              }
                  PRETURN (retval);
                break;
              }
@@ -319,7 +403,9 @@ printf_builtin (list)
            case 'q':           /* print with shell quoting */
              {
                char *p, *xp;
            case 'q':           /* print with shell quoting */
              {
                char *p, *xp;
+               int r;
 
 
+               r = 0;
                p = getstr ();
                if (ansic_shouldquote (p))
                  xp = ansic_quote (p, 0, (int *)0);
                p = getstr ();
                if (ansic_shouldquote (p))
                  xp = ansic_quote (p, 0, (int *)0);
@@ -328,9 +414,17 @@ printf_builtin (list)
                if (xp)
                  {
                    /* Use printstr to get fieldwidth and precision right. */
                if (xp)
                  {
                    /* Use printstr to get fieldwidth and precision right. */
-                   printstr (start, xp, strlen (xp), fieldwidth, precision);
+                   r = printstr (start, xp, strlen (xp), fieldwidth, precision);
+                   if (r < 0)
+                     {
+                       sh_wrerror ();
+                       clearerr (stdout);
+                     }
                    free (xp);
                  }
                    free (xp);
                  }
+
+               if (r < 0)
+                 PRETURN (EXECUTION_FAILURE);
                break;
              }
 
                break;
              }
 
@@ -412,6 +506,13 @@ printf_builtin (list)
          modstart[0] = thisch;
          modstart[1] = nextch;
        }
          modstart[0] = thisch;
          modstart[1] = nextch;
        }
+
+      if (ferror (stdout))
+       {
+         sh_wrerror ();
+         clearerr (stdout);
+         PRETURN (EXECUTION_FAILURE);
+       }
     }
   while (garglist && garglist != list->next);
 
     }
   while (garglist && garglist != list->next);
 
@@ -429,7 +530,7 @@ printf_erange (s)
 }
 
 /* We duplicate a lot of what printf(3) does here. */
 }
 
 /* We duplicate a lot of what printf(3) does here. */
-static void
+static int
 printstr (fmt, string, len, fieldwidth, precision)
      char *fmt;                        /* format */
      char *string;             /* expanded string argument */
 printstr (fmt, string, len, fieldwidth, precision)
      char *fmt;                        /* format */
      char *string;             /* expanded string argument */
@@ -443,7 +544,11 @@ printstr (fmt, string, len, fieldwidth, precision)
   int padlen, nc, ljust, i;
   int fw, pr;                  /* fieldwidth and precision */
 
   int padlen, nc, ljust, i;
   int fw, pr;                  /* fieldwidth and precision */
 
+#if 0
   if (string == 0 || *string == '\0')
   if (string == 0 || *string == '\0')
+#else
+  if (string == 0 || len == 0)
+#endif
     return;
 
 #if 0
     return;
 
 #if 0
@@ -518,15 +623,17 @@ printstr (fmt, string, len, fieldwidth, precision)
 
   /* leading pad characters */
   for (; padlen > 0; padlen--)
 
   /* leading pad characters */
   for (; padlen > 0; padlen--)
-    putchar (' ');
+    PC (' ');
 
   /* output NC characters from STRING */
   for (i = 0; i < nc; i++)
 
   /* output NC characters from STRING */
   for (i = 0; i < nc; i++)
-    putchar (string[i]);
+    PC (string[i]);
 
   /* output any necessary trailing padding */
   for (; padlen < 0; padlen++)
 
   /* output any necessary trailing padding */
   for (; padlen < 0; padlen++)
-    putchar (' ');
+    PC (' ');
+
+  return (ferror (stdout) ? -1 : 0);
 }
   
 /* Convert STRING by expanding the escape sequences specified by the
 }
   
 /* Convert STRING by expanding the escape sequences specified by the
@@ -644,7 +751,11 @@ bexpand (string, len, sawc, lenp)
   int temp;
   char *ret, *r, *s, c;
 
   int temp;
   char *ret, *r, *s, c;
 
+#if 0
   if (string == 0 || *string == '\0')
   if (string == 0 || *string == '\0')
+#else
+  if (string == 0 || len == 0)
+#endif
     {
       if (sawc)
        *sawc = 0;
     {
       if (sawc)
        *sawc = 0;
@@ -681,6 +792,37 @@ bexpand (string, len, sawc, lenp)
 }
 
 static char *
 }
 
 static char *
+vbadd (buf, blen)
+     char *buf;
+     int blen;
+{
+  size_t nlen;
+
+  nlen = vblen + blen + 1;
+  if (nlen >= vbsize)
+    {
+      vbsize = ((nlen + 63) >> 6) << 6;
+      vbuf = (char *)xrealloc (vbuf, vbsize);
+    }
+
+  if (blen == 1)
+    vbuf[vblen++] = buf[0];
+  else
+    {
+      FASTCOPY (buf, vbuf  + vblen, blen);
+      vblen += blen;
+    }
+  vbuf[vblen] = '\0';
+
+#ifdef DEBUG
+  if  (strlen (vbuf) != vblen)
+    internal_error  ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, strlen (vbuf));
+#endif
+
+  return vbuf;
+}
+
+static char *
 mklong (str, modifiers, mlen)
      char *str;
      char *modifiers;
 mklong (str, modifiers, mlen)
      char *str;
      char *modifiers;