/* Handle errors.
- Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation,
+ Inc.
Contributed by Andy Vaught & Niels Kristian Bech Jensen
-This file is part of GNU G95.
+This file is part of GCC.
-GNU G95 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.
+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
+version.
-GNU G95 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.
+GCC 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 GNU G95; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+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. */
/* Handle the inevitable errors. A major catch here is that things
flagged as errors in one match subroutine can conceivably be legal
#include "config.h"
#include "system.h"
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
#include "flags.h"
#include "gfortran.h"
int gfc_suppress_error = 0;
-static int terminal_width, buffer_flag, errors,
- use_warning_buffer, warnings;
+static int terminal_width, buffer_flag, errors, warnings;
-static char *error_ptr, *warning_ptr;
-
-static gfc_error_buf error_buffer, warning_buffer;
+static gfc_error_buf error_buffer, warning_buffer, *cur_error_buffer;
/* Per-file error initialization. */
void
gfc_error_init_1 (void)
{
-
- terminal_width = gfc_terminal_width();
+ terminal_width = gfc_terminal_width ();
errors = 0;
warnings = 0;
buffer_flag = 0;
void
gfc_buffer_error (int flag)
{
-
buffer_flag = flag;
}
static void
error_char (char c)
{
-
if (buffer_flag)
{
- if (use_warning_buffer)
+ if (cur_error_buffer->index >= cur_error_buffer->allocated)
{
- *warning_ptr++ = c;
- if (warning_ptr - warning_buffer.message >= MAX_ERROR_MESSAGE)
- gfc_internal_error ("error_char(): Warning buffer overflow");
- }
- else
- {
- *error_ptr++ = c;
- if (error_ptr - error_buffer.message >= MAX_ERROR_MESSAGE)
- gfc_internal_error ("error_char(): Error buffer overflow");
+ 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;
}
else
{
if (c != 0)
- fputc (c, stderr);
+ {
+ /* We build up complete lines before handing things
+ over to the library in order to speed up error printing. */
+ static char *line;
+ static size_t allocated = 0, index = 0;
+
+ if (index + 1 >= allocated)
+ {
+ allocated = allocated ? allocated * 2 : 1000;
+ line = xrealloc (line, allocated);
+ }
+ line[index++] = c;
+ if (c == '\n')
+ {
+ line[index] = '\0';
+ fputs (line, stderr);
+ index = 0;
+ }
+ }
}
}
static void
error_string (const char *p)
{
-
while (*p)
error_char (*p++);
}
-/* Show the file, where it was included and the source line give a
+/* Show the file, where it was included and the source line, give a
locus. Calls error_printf() recursively, but the recursion is at
most one level deep. */
-static void error_printf (const char *, ...) ATTRIBUTE_PRINTF_1;
+static void error_printf (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
static void
-show_locus (int offset, locus * l)
+show_locus (int offset, locus * loc)
{
+ gfc_linebuf *lb;
gfc_file *f;
char c, *p;
int i, m;
/* TODO: Either limit the total length and number of included files
displayed or add buffering of arbitrary number of characters in
error messages. */
- f = l->file;
- error_printf ("In file %s:%d\n", f->filename, l->lp->start_line + l->line);
- f = f->included_by;
- while (f != NULL)
+ lb = loc->lb;
+ f = lb->file;
+ error_printf ("In file %s:%d\n", f->filename,
+#ifdef USE_MAPPED_LOCATION
+ LOCATION_LINE (lb->location)
+#else
+ lb->linenum
+#endif
+ );
+
+ for (;;)
{
- error_printf (" Included at %s:%d\n", f->filename,
- f->loc.lp->start_line + f->loc.line);
+ i = f->inclusion_line;
+
f = f->included_by;
+ if (f == NULL) break;
+
+ error_printf (" Included at %s:%d\n", f->filename, i);
}
/* Show the line itself, taking care not to print more than what can
show up on the terminal. Tabs are converted to spaces. */
- p = l->lp->line[l->line] + offset;
+
+ p = lb->line + offset;
i = strlen (p);
if (i > terminal_width)
i = terminal_width - 1;
return;
}
- c1 = l1->nextc - l1->lp->line[l1->line];
+ c1 = l1->nextc - l1->lb->line;
c2 = 0;
if (l2 == NULL)
goto separate;
- c2 = l2->nextc - l2->lp->line[l2->line];
+ c2 = l2->nextc - l2->lb->line;
if (c1 < c2)
m = c2 - c1;
m = c1 - c2;
- if (l1->lp != l2->lp || l1->line != l2->line || m > terminal_width - 10)
+ if (l1->lb != l2->lb || m > terminal_width - 10)
goto separate;
offset = 0;
#define IBUF_LEN 30
#define MAX_ARGS 10
-static void
+static void ATTRIBUTE_GCC_GFC(2,0)
error_print (const char *type, const char *format0, va_list argp)
{
char c, *p, int_buf[IBUF_LEN], c_arg[MAX_ARGS], *cp_arg[MAX_ARGS];
case 'C':
if (c == 'C')
- loc = gfc_current_locus ();
+ loc = &gfc_current_locus;
if (have_l1)
{
/* Wrapper for error_print(). */
static void
-error_printf (const char *format, ...)
+error_printf (const char *nocmsgid, ...)
{
va_list argp;
- va_start (argp, format);
- error_print ("", format, argp);
+ va_start (argp, nocmsgid);
+ error_print ("", _(nocmsgid), argp);
va_end (argp);
}
/* Issue a warning. */
void
-gfc_warning (const char *format, ...)
+gfc_warning (const char *nocmsgid, ...)
{
va_list argp;
return;
warning_buffer.flag = 1;
- warning_ptr = warning_buffer.message;
- use_warning_buffer = 1;
+ warning_buffer.index = 0;
+ cur_error_buffer = &warning_buffer;
- va_start (argp, format);
+ va_start (argp, nocmsgid);
if (buffer_flag == 0)
warnings++;
- error_print ("Warning:", format, argp);
+ error_print (_("Warning:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
/* Possibly issue a warning/error about use of a nonstandard (or deleted)
feature. An error/warning will be issued if the currently selected
standard does not contain the requested bits. Return FAILURE if
- and error is generated. */
+ an error is generated. */
try
-gfc_notify_std (int std, const char *format, ...)
+gfc_notify_std (int std, const char *nocmsgid, ...)
{
va_list argp;
bool warning;
if (gfc_suppress_error)
return warning ? SUCCESS : FAILURE;
- if (warning)
- {
- warning_buffer.flag = 1;
- warning_ptr = warning_buffer.message;
- use_warning_buffer = 1;
- }
- else
- {
- error_buffer.flag = 1;
- error_ptr = error_buffer.message;
- use_warning_buffer = 0;
- }
+ cur_error_buffer = warning ? &warning_buffer : &error_buffer;
+ cur_error_buffer->flag = 1;
+ cur_error_buffer->index = 0;
if (buffer_flag == 0)
{
else
errors++;
}
- va_start (argp, format);
+ va_start (argp, nocmsgid);
if (warning)
- error_print ("Warning:", format, argp);
+ error_print (_("Warning:"), _(nocmsgid), argp);
else
- error_print ("Error:", format, argp);
+ error_print (_("Error:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
/* Immediate warning (i.e. do not buffer the warning). */
void
-gfc_warning_now (const char *format, ...)
+gfc_warning_now (const char *nocmsgid, ...)
{
va_list argp;
int i;
buffer_flag = 0;
warnings++;
- va_start (argp, format);
- error_print ("Warning:", format, argp);
+ va_start (argp, nocmsgid);
+ error_print (_("Warning:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
void
gfc_clear_warning (void)
{
-
warning_buffer.flag = 0;
}
void
gfc_warning_check (void)
{
-
if (warning_buffer.flag)
{
warnings++;
- fputs (warning_buffer.message, stderr);
+ if (warning_buffer.message != NULL)
+ fputs (warning_buffer.message, stderr);
warning_buffer.flag = 0;
}
}
/* Issue an error. */
void
-gfc_error (const char *format, ...)
+gfc_error (const char *nocmsgid, ...)
{
va_list argp;
return;
error_buffer.flag = 1;
- error_ptr = error_buffer.message;
- use_warning_buffer = 0;
+ error_buffer.index = 0;
+ cur_error_buffer = &error_buffer;
- va_start (argp, format);
+ va_start (argp, nocmsgid);
if (buffer_flag == 0)
errors++;
- error_print ("Error:", format, argp);
+ error_print (_("Error:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
/* Immediate error. */
void
-gfc_error_now (const char *format, ...)
+gfc_error_now (const char *nocmsgid, ...)
{
va_list argp;
int i;
error_buffer.flag = 1;
- error_ptr = error_buffer.message;
+ error_buffer.index = 0;
+ cur_error_buffer = &error_buffer;
i = buffer_flag;
buffer_flag = 0;
errors++;
- va_start (argp, format);
- error_print ("Error:", format, argp);
+ va_start (argp, nocmsgid);
+ error_print (_("Error:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
buffer_flag = i;
+
+ if (flag_fatal_errors)
+ exit (1);
}
/* Fatal error, never returns. */
void
-gfc_fatal_error (const char *format, ...)
+gfc_fatal_error (const char *nocmsgid, ...)
{
va_list argp;
buffer_flag = 0;
- va_start (argp, format);
- error_print ("Fatal Error:", format, argp);
+ va_start (argp, nocmsgid);
+ error_print (_("Fatal Error:"), _(nocmsgid), argp);
va_end (argp);
exit (3);
va_start (argp, format);
- show_loci (gfc_current_locus (), NULL);
+ show_loci (&gfc_current_locus, NULL);
error_printf ("Internal Error at (1):");
error_print ("", format, argp);
void
gfc_clear_error (void)
{
-
error_buffer.flag = 0;
}
if (error_buffer.flag)
{
errors++;
- fputs (error_buffer.message, stderr);
+ if (error_buffer.message != NULL)
+ fputs (error_buffer.message, stderr);
error_buffer.flag = 0;
+
+ if (flag_fatal_errors)
+ exit (1);
}
return rc;
void
gfc_push_error (gfc_error_buf * err)
{
-
err->flag = error_buffer.flag;
if (error_buffer.flag)
- strcpy (err->message, error_buffer.message);
+ err->message = xstrdup (error_buffer.message);
error_buffer.flag = 0;
}
void
gfc_pop_error (gfc_error_buf * err)
{
-
error_buffer.flag = err->flag;
if (error_buffer.flag)
- strcpy (error_buffer.message, err->message);
+ {
+ size_t len = strlen (err->message) + 1;
+ gcc_assert (len <= error_buffer.allocated);
+ memcpy (error_buffer.message, err->message, len);
+ gfc_free (err->message);
+ }
+}
+
+
+/* Free a pushed error state, but keep the current error state. */
+
+void
+gfc_free_error (gfc_error_buf * err)
+{
+ if (err->flag)
+ gfc_free (err->message);
}
/* Debug wrapper for printf. */
void
-gfc_status (const char *format, ...)
+gfc_status (const char *cmsgid, ...)
{
va_list argp;
- va_start (argp, format);
+ va_start (argp, cmsgid);
- vprintf (format, argp);
+ vprintf (_(cmsgid), argp);
va_end (argp);
}
}
-/* Report the number of warnings and errors that occored to the caller. */
+/* Report the number of warnings and errors that occurred to the caller. */
void
gfc_get_errors (int *w, int *e)
{
-
if (w != NULL)
*w = warnings;
if (e != NULL)