OSDN Git Service

gcc/ada/
[pf3gnuchains/gcc-fork.git] / gcc / fortran / error.c
index 9c2d466..add23ce 100644 (file)
@@ -1,13 +1,13 @@
 /* Handle errors.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
-   Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Andy Vaught & Niels Kristian Bech Jensen
 
 This file is part of GCC.
 
 GCC 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
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ 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 GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Handle the inevitable errors.  A major catch here is that things
    flagged as errors in one match subroutine can conceivably be legal
@@ -69,12 +68,10 @@ error_char (char c)
     {
       if (cur_error_buffer->index >= cur_error_buffer->allocated)
        {
-         cur_error_buffer->allocated =
-           cur_error_buffer->allocated
-           ? cur_error_buffer->allocated * 2 : 1000;
-         cur_error_buffer->message
-           = xrealloc (cur_error_buffer->message,
-                       cur_error_buffer->allocated);
+         cur_error_buffer->allocated = cur_error_buffer->allocated
+                                     ? cur_error_buffer->allocated * 2 : 1000;
+         cur_error_buffer->message = xrealloc (cur_error_buffer->message,
+                                               cur_error_buffer->allocated);
        }
       cur_error_buffer->message[cur_error_buffer->index++] = c;
     }
@@ -116,19 +113,13 @@ error_string (const char *p)
 
 /* Print a formatted integer to the error buffer or output.  */
 
-#define IBUF_LEN 30
+#define IBUF_LEN 60
 
 static void
-error_integer (int i)
+error_uinteger (unsigned long int i)
 {
   char *p, int_buf[IBUF_LEN];
 
-  if (i < 0)
-    {
-      i = -i;
-      error_char ('-');
-    }
-
   p = int_buf + IBUF_LEN - 1;
   *p-- = '\0';
 
@@ -144,6 +135,22 @@ error_integer (int i)
   error_string (p + 1);
 }
 
+static void
+error_integer (long int i)
+{
+  unsigned long int u;
+
+  if (i < 0)
+    {
+      u = (unsigned long int) -i;
+      error_char ('-');
+    }
+  else
+    u = i;
+
+  error_uinteger (u);
+}
+
 
 /* Show the file, where it was included, and the source line, give a
    locus.  Calls error_printf() recursively, but the recursion is at
@@ -152,7 +159,7 @@ error_integer (int i)
 static void error_printf (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
 
 static void
-show_locus (locus * loc, int c1, int c2)
+show_locus (locus *loc, int c1, int c2)
 {
   gfc_linebuf *lb;
   gfc_file *f;
@@ -235,12 +242,6 @@ show_locus (locus * loc, int c1, int c2)
   if (cmax > terminal_width - 5)
     offset = cmax - terminal_width + 5;
 
-  /* TODO: Is there a good reason for the following apparently-redundant
-     check, and the similar ones in the single-locus cases below?  */
-
-  if (offset < 0)
-    offset = 0;
-
   /* Show the line itself, taking care not to print more than what can
      show up on the terminal.  Tabs are converted to spaces, and 
      nonprintable characters are converted to a "\xNN" sequence.  */
@@ -308,7 +309,7 @@ show_locus (locus * loc, int c1, int c2)
    loci may or may not be on the same source line.  */
 
 static void
-show_loci (locus * l1, locus * l2)
+show_loci (locus *l1, locus *l2)
 {
   int m, c1, c2;
 
@@ -349,7 +350,6 @@ show_loci (locus * l1, locus * l2)
   show_locus (l1, c1, c2);
 
   return;
-
 }
 
 
@@ -378,69 +378,182 @@ 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_UINTEGER,
+         TYPE_LONGINT, TYPE_ULONGINT, TYPE_CHAR, TYPE_STRING,
+        NOTYPE };
+  struct
+  {
+    int type;
+    int pos;
+    union
+    {
+      int intval;
+      unsigned int uintval;
+      long int longintval;
+      unsigned long int ulongintval;
+      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 == '%')
+       {
+         format++;
+         continue;
+       }
+
+      if (ISDIGIT (*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++;
+
+      c = *format++;
+
+      if (pos > maxpos)
+       maxpos = pos;
+
+      switch (c)
        {
-         c = *format++;
+         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 'u':
+           arg[pos].type = TYPE_UINTEGER;
+
+         case 'l':
+           c = *format++;
+           if (c == 'u')
+             arg[pos].type = TYPE_ULONGINT;
+           else if (c == 'i' || c == 'd')
+             arg[pos].type = TYPE_LONGINT;
+           else
+             gcc_unreachable ();
+           break;
+
+         case 'c':
+           arg[pos].type = TYPE_CHAR;
+           break;
+
+         case 's':
+           arg[pos].type = TYPE_STRING;
+           break;
+
+         default:
+           gcc_unreachable ();
+       }
 
-         switch (c)
-           {
-           case '%':
-             break;
+      spec[n++].pos = pos;
+    }
 
-           case 'L':
+  /* 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 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_UINTEGER:
+           arg[pos].u.uintval = va_arg (argp, unsigned int);
+           break;
+
+         case TYPE_LONGINT:
+           arg[pos].u.longintval = va_arg (argp, long int);
+           break;
+
+         case TYPE_ULONGINT:
+           arg[pos].u.ulongintval = va_arg (argp, unsigned long 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 +577,16 @@ 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))
+           format++;
+           
+         /* Skip over the dollar sign.  */
+         format++;
+       }
+       
       switch (*format)
        {
        case '%':
@@ -471,27 +594,32 @@ 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++]);
+       case 'C':               /* Current locus */
+       case 'L':               /* Specified locus */
+         error_string (spec[n++].u.stringval);
          break;
 
        case 'd':
        case 'i':
-         error_integer (i_arg[n++]);
+         error_integer (spec[n++].u.intval);
          break;
 
-       case 'C':               /* Current locus */
-       case 'L':               /* Specified locus */
-         error_string (have_l1 ? "(2)" : "(1)");
-         have_l1 = 1;
+       case 'u':
+         error_uinteger (spec[n++].u.uintval);
          break;
 
-       case '\0':
-         format--;
+       case 'l':
+         format++;
+         if (*format == 'u')
+           error_uinteger (spec[n++].u.ulongintval);
+         else
+           error_integer (spec[n++].u.longintval);
          break;
+
        }
     }
 
@@ -580,17 +708,15 @@ gfc_notify_std (int std, const char *nocmsgid, ...)
   va_list argp;
   bool warning;
 
-  warning = ((gfc_option.warn_std & std) != 0)
-           && !inhibit_warnings;
-  if ((gfc_option.allow_std & std) != 0
-      && !warning)
+  warning = ((gfc_option.warn_std & std) != 0) && !inhibit_warnings;
+  if ((gfc_option.allow_std & std) != 0 && !warning)
     return SUCCESS;
 
   if (gfc_suppress_error)
     return warning ? SUCCESS : FAILURE;
 
   cur_error_buffer = (warning && !warnings_are_errors)
-    ? &warning_buffer : &error_buffer;
+                  ? &warning_buffer : &error_buffer;
   cur_error_buffer->flag = 1;
   cur_error_buffer->index = 0;
 
@@ -806,7 +932,7 @@ gfc_error_check (void)
 /* Save the existing error state.  */
 
 void
-gfc_push_error (gfc_error_buf * err)
+gfc_push_error (gfc_error_buf *err)
 {
   err->flag = error_buffer.flag;
   if (error_buffer.flag)
@@ -819,7 +945,7 @@ gfc_push_error (gfc_error_buf * err)
 /* Restore a previous pushed error state.  */
 
 void
-gfc_pop_error (gfc_error_buf * err)
+gfc_pop_error (gfc_error_buf *err)
 {
   error_buffer.flag = err->flag;
   if (error_buffer.flag)
@@ -835,7 +961,7 @@ gfc_pop_error (gfc_error_buf * err)
 /* Free a pushed error state, but keep the current error state.  */
 
 void
-gfc_free_error (gfc_error_buf * err)
+gfc_free_error (gfc_error_buf *err)
 {
   if (err->flag)
     gfc_free (err->message);