OSDN Git Service

PR fortran/29711
authorfxcoudert <fxcoudert@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 25 Nov 2006 16:57:25 +0000 (16:57 +0000)
committerfxcoudert <fxcoudert@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 25 Nov 2006 16:57:25 +0000 (16:57 +0000)
* 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
gcc/fortran/error.c

index aa1b037..86710de 100644 (file)
@@ -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
index 9c2d466..d92fd82 100644 (file)
@@ -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;
        }
     }