/* 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
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
{
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;
}
/* 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';
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
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;
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. */
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;
show_locus (l1, c1, c2);
return;
-
}
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);
}
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 '%':
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;
+
}
}
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;
/* 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)
/* 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)
/* 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);