From dd8d8ca9f6a731d0ce0a7bd367dd1c21119b43b6 Mon Sep 17 00:00:00 2001
From: fxcoudert <fxcoudert@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Sat, 25 Nov 2006 16:57:25 +0000
Subject: [PATCH] 	PR fortran/29711 	* error.c (error_print):
 Handle printf-style position specifiers, 	of the form "%3$d".

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@119203 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/fortran/ChangeLog |   6 ++
 gcc/fortran/error.c   | 196 ++++++++++++++++++++++++++++++------------
 2 files changed, 145 insertions(+), 57 deletions(-)

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index aa1b03718769..86710de22486 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,9 @@
+2006-11-25  Francois-Xavier Coudert  <coudert@clipper.ens.fr>
+
+	PR fortran/29711
+	* error.c (error_print): Handle printf-style position specifiers,
+	of the form "%3$d".
+
 2006-11-24  Paul Thomas  <pault@gcc.gnu.org>
 
 	PR fortran/20880
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index 9c2d466d285c..d92fd82004b1 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -378,69 +378,150 @@ show_loci (locus * l1, locus * l2)
 static void ATTRIBUTE_GCC_GFC(2,0)
 error_print (const char *type, const char *format0, va_list argp)
 {
-  char c, c_arg[MAX_ARGS], *cp_arg[MAX_ARGS];
-  int n, have_l1, i_arg[MAX_ARGS];
+  enum { TYPE_CURRENTLOC, TYPE_LOCUS, TYPE_INTEGER, TYPE_CHAR, TYPE_STRING,
+	 NOTYPE };
+  struct
+  {
+    int type;
+    int pos;
+    union
+    {
+      int intval;
+      char charval;
+      const char * stringval;
+    } u;
+  } arg[MAX_ARGS], spec[MAX_ARGS];
+  /* spec is the array of specifiers, in the same order as they
+     appear in the format string.  arg is the array of arguments,
+     in the same order as they appear in the va_list.  */
+
+  char c;
+  int i, n, have_l1, pos, maxpos;
   locus *l1, *l2, *loc;
   const char *format;
 
-  l1 = l2 = loc = NULL;
+  l1 = l2 = NULL;
 
   have_l1 = 0;
+  pos = -1;
+  maxpos = -1;
 
   n = 0;
   format = format0;
 
+  for (i = 0; i < MAX_ARGS; i++)
+    {
+      arg[i].type = NOTYPE;
+      spec[i].pos = -1;
+    }
+
+  /* First parse the format string for position specifiers.  */
   while (*format)
     {
       c = *format++;
-      if (c == '%')
+      if (c != '%')
+	continue;
+
+      if (*format == '%')
+	continue;
+
+      if (ISDIGIT (*format))
 	{
-	  c = *format++;
+	  /* This is a position specifier.  For example, the number
+	     12 in the format string "%12$d", which specifies the third
+	     argument of the va_list, formatted in %d format.
+	     For details, see "man 3 printf".  */
+	  pos = atoi(format) - 1;
+	  gcc_assert (pos >= 0);
+	  while (ISDIGIT(*format))
+	    format++;
+	  gcc_assert (*format++ == '$');
+	}
+      else
+	pos++;
 
-	  switch (c)
-	    {
-	    case '%':
-	      break;
+      c = *format++;
+
+      if (pos > maxpos)
+	maxpos = pos;
+
+      switch (c)
+	{
+	  case 'C':
+	    arg[pos].type = TYPE_CURRENTLOC;
+	    break;
+
+	  case 'L':
+	    arg[pos].type = TYPE_LOCUS;
+	    break;
+
+	  case 'd':
+	  case 'i':
+	    arg[pos].type = TYPE_INTEGER;
+	    break;
+
+	  case 'c':
+	    arg[pos].type = TYPE_CHAR;
+	    break;
+
+	  case 's':
+	    arg[pos].type = TYPE_STRING;
+	    break;
+
+	  default:
+	    gcc_unreachable ();
+	}
+
+      spec[n++].pos = pos;
+    }
+
+  /* Then convert the values for each %-style argument.  */
+  for (pos = 0; pos <= maxpos; pos++)
+    {
+      gcc_assert (arg[pos].type != NOTYPE);
+      switch (arg[pos].type)
+	{
+	  case TYPE_CURRENTLOC:
+	    loc = &gfc_current_locus;
+	    /* Fall through.  */
 
-	    case 'L':
+	  case TYPE_LOCUS:
+	    if (arg[pos].type == TYPE_LOCUS)
 	      loc = va_arg (argp, locus *);
-	      /* Fall through */
-
-	    case 'C':
-	      if (c == 'C')
-		loc = &gfc_current_locus;
-
-	      if (have_l1)
-		{
-		  l2 = loc;
-		}
-	      else
-		{
-		  l1 = loc;
-		  have_l1 = 1;
-		}
-	      break;
-
-	    case 'd':
-	    case 'i':
-	      i_arg[n++] = va_arg (argp, int);
-	      break;
-
-	    case 'c':
-	      c_arg[n++] = va_arg (argp, int);
-	      break;
-
-	    case 's':
-	      cp_arg[n++] = va_arg (argp, char *);
-	      break;
-
-	    case '\0':
-	      format--;
-	      break;
-	    }
+
+	    if (have_l1)
+	      {
+		l2 = loc;
+		arg[pos].u.stringval = "(2)";
+	      }
+	    else
+	      {
+		l1 = loc;
+		have_l1 = 1;
+		arg[pos].u.stringval = "(1)";
+	      }
+	    break;
+
+	  case TYPE_INTEGER:
+	    arg[pos].u.intval = va_arg (argp, int);
+	    break;
+
+	  case TYPE_CHAR:
+	    arg[pos].u.charval = (char) va_arg (argp, int);
+	    break;
+
+	  case TYPE_STRING:
+	    arg[pos].u.stringval = (const char *) va_arg (argp, char *);
+	    break;
+
+	  default:
+	    gcc_unreachable ();
 	}
     }
 
+  for (n = 0; spec[n].pos >= 0; n++)
+    spec[n].u = arg[spec[n].pos].u;
+
   /* Show the current loci if we have to.  */
   if (have_l1)
     show_loci (l1, l2);
@@ -464,6 +545,15 @@ error_print (const char *type, const char *format0, va_list argp)
 	}
 
       format++;
+      if (ISDIGIT(*format))
+	{
+	  /* This is a position specifier.  See comment above.  */
+	  while (ISDIGIT(*format))
+	    
+	  /* Skip over the dollar sign.  */
+	  format++;
+	}
+	
       switch (*format)
 	{
 	case '%':
@@ -471,26 +561,18 @@ error_print (const char *type, const char *format0, va_list argp)
 	  break;
 
 	case 'c':
-	  error_char (c_arg[n++]);
+	  error_char (spec[n++].u.charval);
 	  break;
 
 	case 's':
-	  error_string (cp_arg[n++]);
-	  break;
-
-	case 'd':
-	case 'i':
-	  error_integer (i_arg[n++]);
-	  break;
-
 	case 'C':		/* Current locus */
 	case 'L':		/* Specified locus */
-	  error_string (have_l1 ? "(2)" : "(1)");
-	  have_l1 = 1;
+	  error_string (spec[n++].u.stringval);
 	  break;
 
-	case '\0':
-	  format--;
+	case 'd':
+	case 'i':
+	  error_integer (spec[n++].u.intval);
 	  break;
 	}
     }
-- 
GitLab