From 011c1d1c0766c65517ebd495465c99e86edb63ec Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <stephen.hemminger@vyatta.com>
Date: Mon, 11 Oct 2010 14:49:26 -0700
Subject: Update to bash-4.1

---
 builtins/printf.def | 203 +++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 155 insertions(+), 48 deletions(-)

(limited to 'builtins/printf.def')

diff --git a/builtins/printf.def b/builtins/printf.def
index 0e1d4aa..e447633 100644
--- a/builtins/printf.def
+++ b/builtins/printf.def
@@ -1,39 +1,49 @@
 This file is printf.def, from which is created printf.c.
 It implements the builtin "printf" in Bash.
 
-Copyright (C) 1997-2005 Free Software Foundation, Inc.
+Copyright (C) 1997-2009 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
-Bash is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
+Bash is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
-Bash is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
+Bash is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License along
-with Bash; see the file COPYING.  If not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+You should have received a copy of the GNU General Public License
+along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 
 $PRODUCES printf.c
 
 $BUILTIN printf
 $FUNCTION printf_builtin
 $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
-sequences which are converted and copied to the standard output, and
+Formats and prints ARGUMENTS under control of the FORMAT.
+
+Options:
+  -v var	assign the output to shell variable VAR rather than
+		display it on the standard output
+
+FORMAT is a character string which contains three types of objects: plain
+characters, which are simply copied to standard output; character escape
+sequences, which are converted and copied to the standard output; and
 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.
-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.
+argument.
+
+In addition to the standard format specifications described in printf(1)
+and printf(3), printf interprets:
+
+  %b	expand backslash escape sequences in the corresponding argument
+  %q	quote the argument in a way that can be reused as shell input
+
+Exit Status:
+Returns success unless an invalid option is given or a write or assignment
+error occurs.
 $END
 
 #include <config.h>
@@ -49,6 +59,12 @@ $END
 #  define INT_MIN		(-2147483647-1)
 #endif
 
+#if defined (PREFER_STDARG)
+#  include <stdarg.h>
+#else
+#  include <varargs.h>
+#endif
+
 #include <stdio.h>
 #include <chartypes.h>
 
@@ -60,10 +76,15 @@ $END
 #include "../bashintl.h"
 
 #include "../shell.h"
+#include "shmbutil.h"
 #include "stdc.h"
 #include "bashgetopt.h"
 #include "common.h"
 
+#if defined (PRI_MACROS_BROKEN)
+#  undef PRIdMAX
+#endif
+
 #if !defined (PRIdMAX)
 #  if HAVE_LONG_LONG
 #    define PRIdMAX	"lld"
@@ -89,31 +110,22 @@ extern int errno;
 
 #define PF(f, func) \
   do { \
-    char *b = 0; \
     int nw; \
     clearerr (stdout); \
     if (have_fieldwidth && have_precision) \
-      nw = asprintf(&b, f, fieldwidth, precision, func); \
+      nw = vflag ? vbprintf (f, fieldwidth, precision, func) : printf (f, fieldwidth, precision, func); \
     else if (have_fieldwidth) \
-      nw = asprintf(&b, f, fieldwidth, func); \
+      nw = vflag ? vbprintf (f, fieldwidth, func) : printf (f, fieldwidth, func); \
     else if (have_precision) \
-      nw = asprintf(&b, f, precision, func); \
+      nw = vflag ? vbprintf (f, precision, func) : printf (f, fieldwidth, func); \
     else \
-      nw = asprintf(&b, f, func); \
+      nw = vflag ? vbprintf (f, func) : printf (f, func); \
     tw += nw; \
-    if (b) \
+    if (ferror (stdout)) \
       { \
-	if (vflag) \
-	  (void)vbadd (b, nw); \
-	else \
-	  (void)fputs (b, stdout); \
-	if (ferror (stdout)) \
-	  { \
-	    sh_wrerror (); \
-	    clearerr (stdout); \
-	    return (EXECUTION_FAILURE); \
-	  } \
-	free (b); \
+	sh_wrerror (); \
+	clearerr (stdout); \
+	return (EXECUTION_FAILURE); \
       } \
   } while (0)
 
@@ -123,7 +135,7 @@ extern int errno;
     { \
       if (vflag) \
 	{ \
-	  bind_variable  (vname, vbuf, 0); \
+	  bind_printf_variable  (vname, vbuf, 0); \
 	  stupidly_hack_special_variables (vname); \
 	} \
       if (conv_bufsize > 4096 ) \
@@ -138,9 +150,13 @@ extern int errno;
 	  vbsize = 0; \
 	  vbuf = 0; \
 	} \
+      else if (vbuf) \
+	vbuf[0] = 0; \
+      terminate_immediately--; \
       fflush (stdout); \
       if (ferror (stdout)) \
 	{ \
+	  sh_wrerror (); \
 	  clearerr (stdout); \
 	  return (EXECUTION_FAILURE); \
 	} \
@@ -151,17 +167,27 @@ extern int errno;
 #define SKIP1 "#'-+ 0"
 #define LENMODS "hjlLtz"
 
+#if !HAVE_ASPRINTF
+extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
+#endif
+
+#if !HAVE_VSNPRINTF
+extern int vsnprintf __P((char *, size_t, const char *, ...)) __attribute__((__format__ (printf, 3, 4)));
+#endif
+
 static void printf_erange __P((char *));
 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 char *vbadd __P((char *, int));
+static int vbprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
 static char *mklong __P((char *, char *, size_t));
 static int getchr __P((void));
 static char *getstr __P((void));
 static int  getint __P((void));
 static intmax_t getintmax __P((void));
 static uintmax_t getuintmax __P((void));
+static SHELL_VAR *bind_printf_variable __P((char *, char *, int));
 
 #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
 typedef long double floatmax_t;
@@ -174,7 +200,7 @@ typedef double floatmax_t;
 #endif
 static floatmax_t getfloatmax __P((void));
 
-static int asciicode __P((void));
+static intmax_t asciicode __P((void));
 
 static WORD_LIST *garglist;
 static int retval;
@@ -210,10 +236,17 @@ printf_builtin (list)
       switch (ch)
 	{
 	case 'v':
-	  if (legal_identifier (vname = list_optarg))
+	  vname = list_optarg;
+#if defined (ARRAY_VARS)
+	  if (legal_identifier (vname) || valid_array_reference (vname))
+#else
+	  if (legal_identifier (vname))
+#endif
 	    {
 	      vflag = 1;
 	      vblen = 0;
+	      if (vbuf)
+		vbuf[0] = 0;
 	    }
 	  else
 	    {
@@ -245,6 +278,8 @@ printf_builtin (list)
   /* If the format string is empty after preprocessing, return immediately. */
   if (format == 0 || *format == 0)
     return (EXECUTION_SUCCESS);
+
+  terminate_immediately++;
 	  
   /* Basic algorithm is to scan the format string for conversion
      specifications -- once one is found, find out if the field
@@ -540,7 +575,7 @@ static void
 printf_erange (s)
      char *s;
 {
-  builtin_error ("warning: %s: %s", s, strerror(ERANGE));
+  builtin_error (_("warning: %s: %s"), s, strerror(ERANGE));
 }
 
 /* We duplicate a lot of what printf(3) does here. */
@@ -563,7 +598,7 @@ printstr (fmt, string, len, fieldwidth, precision)
 #else
   if (string == 0 || len == 0)
 #endif
-    return;
+    return 0;
 
 #if 0
   s = fmt;
@@ -821,7 +856,7 @@ vbadd (buf, blen)
 
   if (blen == 1)
     vbuf[vblen++] = buf[0];
-  else
+  else if (blen > 1)
     {
       FASTCOPY (buf, vbuf  + vblen, blen);
       vblen += blen;
@@ -836,6 +871,44 @@ vbadd (buf, blen)
   return vbuf;
 }
 
+static int
+#if defined (PREFER_STDARG)
+vbprintf (const char *format, ...)
+#else
+vbprintf (format, va_alist)
+  const char *format;
+  va_dcl
+#endif
+{
+  va_list args;
+  size_t nlen;
+  int blen;
+
+  SH_VA_START (args, format);
+  blen = vsnprintf (vbuf + vblen, vbsize - vblen, format, args);
+  va_end (args);
+
+  nlen = vblen + blen + 1;
+  if (nlen >= vbsize)
+    {
+      vbsize = ((nlen + 63) >> 6) << 6;
+      vbuf = (char *)xrealloc (vbuf, vbsize);
+      SH_VA_START (args, format);
+      blen = vsnprintf (vbuf + vblen, vbsize - vblen, format, args);
+      va_end (args);
+    }
+
+  vblen += blen;
+  vbuf[vblen] = '\0';
+
+#ifdef DEBUG
+  if  (strlen (vbuf) != vblen)
+    internal_error  ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf));
+#endif
+  
+  return (blen);
+}
+
 static char *
 mklong (str, modifiers, mlen)
      char *str;
@@ -931,7 +1004,9 @@ getintmax ()
 	 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;
+#if 0
+      ret = 0;		/* return partially-converted value from strtoimax */
+#endif
       conversion_error = 1;
     }
   else if (errno == ERANGE)
@@ -1000,12 +1075,44 @@ getfloatmax ()
 }
 
 /* NO check is needed for garglist here. */
-static int
+static intmax_t
 asciicode ()
 {
-  register int ch;
+  register intmax_t ch;
+#if defined (HANDLE_MULTIBYTE)
+  wchar_t wc;
+  size_t mblength, slen;
+#endif
+  DECLARE_MBSTATE;
+
+#if defined (HANDLE_MULTIBYTE)
+  slen = strlen (garglist->word->word+1);
+  mblength = MBLEN (garglist->word->word+1, slen);
+  if (mblength > 1)
+    {
+      mblength = mbtowc (&wc, garglist->word->word+1, slen);
+      ch = wc;		/* XXX */
+    }
+  else
+#endif
+    ch = (unsigned char)garglist->word->word[1];
 
-  ch = garglist->word->word[1];
   garglist = garglist->next;
   return (ch);
 }
+
+static SHELL_VAR *
+bind_printf_variable (name, value, flags)
+     char *name;
+     char *value;
+     int flags;
+{
+#if defined (ARRAY_VARS)
+  if (valid_array_reference (name) == 0)
+    return (bind_variable (name, value, flags));
+  else
+    return (assign_array_element (name, value, flags));
+#else /* !ARRAY_VARS */
+  return bind_variable (name, value, flags);
+#endif /* !ARRAY_VARS */
+}
-- 
cgit v1.2.3

