#include "config.h"
#include "system.h"
#include "flags.h"
#include "gfortran.h"
int gfc_suppress_error = 0;
static int terminal_width, buffer_flag, errors, warnings;
static gfc_error_buf error_buffer, warning_buffer, *cur_error_buffer;
void
gfc_error_init_1 (void)
{
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 (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->message[cur_error_buffer->index++] = c;
}
else
{
if (c != 0)
{
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++);
}
#define IBUF_LEN 30
static void
error_integer (int i)
{
char *p, int_buf[IBUF_LEN];
if (i < 0)
{
i = -i;
error_char ('-');
}
p = int_buf + IBUF_LEN - 1;
*p-- = '\0';
if (i == 0)
*p-- = '0';
while (i > 0)
{
*p-- = i % 10 + '0';
i = i / 10;
}
error_string (p + 1);
}
static void error_printf (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
static void
show_locus (locus * loc, int c1, int c2)
{
gfc_linebuf *lb;
gfc_file *f;
char c, *p;
int i, m, offset, cmax;
lb = loc->lb;
f = lb->file;
error_string (f->filename);
error_char (':');
#ifdef USE_MAPPED_LOCATION
error_integer (LOCATION_LINE (lb->location));
#else
error_integer (lb->linenum);
#endif
if ((c1 > 0) || (c2 > 0))
error_char ('.');
if (c1 > 0)
error_integer (c1);
if ((c1 > 0) && (c2 > 0))
error_char ('-');
if (c2 > 0)
error_integer (c2);
error_char (':');
error_char ('\n');
for (;;)
{
i = f->inclusion_line;
f = f->included_by;
if (f == NULL) break;
error_printf (" Included at %s:%d:", f->filename, i);
}
error_char ('\n');
offset = 0;
if (c1 == 0)
c1 = 1;
if (c2 == 0)
c2 = 1;
if (c1 == c2)
c2 += 1;
cmax = (c1 < c2) ? c2 : c1;
if (cmax > terminal_width - 5)
offset = cmax - terminal_width + 5;
if (offset < 0)
offset = 0;
p = lb->line + offset;
i = strlen (p);
if (i > terminal_width)
i = terminal_width - 1;
for (; i > 0; i--)
{
c = *p++;
if (c == '\t')
c = ' ';
if (ISPRINT (c))
error_char (c);
else
{
error_char ('\\');
error_char ('x');
m = ((c >> 4) & 0x0F) + '0';
if (m > '9')
m += 'A' - '9' - 1;
error_char (m);
m = (c & 0x0F) + '0';
if (m > '9')
m += 'A' - '9' - 1;
error_char (m);
}
}
error_char ('\n');
c1 -= offset;
c2 -= offset;
for (i = 1; i <= cmax; i++)
{
if (i == c1)
error_char ('1');
else if (i == c2)
error_char ('2');
else
error_char (' ');
}
error_char ('\n');
}
static void
show_loci (locus * l1, locus * l2)
{
int m, c1, c2;
if (l1 == NULL || l1->lb == NULL)
{
error_printf ("<During initialization>\n");
return;
}
c1 = l1->nextc - l1->lb->line;
if (l2 == NULL)
{
show_locus (l1, c1, -1);
return;
}
c2 = l2->nextc - l2->lb->line;
if (c1 < c2)
m = c2 - c1;
else
m = c1 - c2;
if (l1->lb != l2->lb || m > terminal_width - 10)
{
show_locus (l1, c1, -1);
show_locus (l2, -1, c2);
return;
}
show_locus (l1, c1, c2);
return;
}
#define MAX_ARGS 10
static void ATTRIBUTE_GCC_GFC(2,0)
error_print (const char *type, const char *format0, va_list argp)
{
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];
char c;
int i, n, have_l1, pos, maxpos;
locus *l1, *l2, *loc;
const char *format;
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;
}
while (*format)
{
c = *format++;
if (c != '%')
continue;
if (*format == '%')
continue;
if (ISDIGIT (*format))
{
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)
{
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;
}
for (pos = 0; pos <= maxpos; pos++)
{
gcc_assert (arg[pos].type != NOTYPE);
switch (arg[pos].type)
{
case TYPE_CURRENTLOC:
loc = &gfc_current_locus;
case TYPE_LOCUS:
if (arg[pos].type == TYPE_LOCUS)
loc = va_arg (argp, locus *);
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;
if (have_l1)
show_loci (l1, l2);
if (*type)
{
error_string (type);
error_char (' ');
}
have_l1 = 0;
format = format0;
n = 0;
for (; *format; format++)
{
if (*format != '%')
{
error_char (*format);
continue;
}
format++;
if (ISDIGIT(*format))
{
while (ISDIGIT(*format))
format++;
format++;
}
switch (*format)
{
case '%':
error_char ('%');
break;
case 'c':
error_char (spec[n++].u.charval);
break;
case 's':
case 'C':
case 'L':
error_string (spec[n++].u.stringval);
break;
case 'd':
case 'i':
error_integer (spec[n++].u.intval);
break;
}
}
error_char ('\n');
}
static void
error_printf (const char *nocmsgid, ...)
{
va_list argp;
va_start (argp, nocmsgid);
error_print ("", _(nocmsgid), argp);
va_end (argp);
}
static void
gfc_increment_error_count (void)
{
errors++;
if ((gfc_option.max_errors != 0) && (errors >= gfc_option.max_errors))
gfc_fatal_error ("Error count reached limit of %d.", gfc_option.max_errors);
}
void
gfc_warning (const char *nocmsgid, ...)
{
va_list argp;
if (inhibit_warnings)
return;
warning_buffer.flag = 1;
warning_buffer.index = 0;
cur_error_buffer = &warning_buffer;
va_start (argp, nocmsgid);
error_print (_("Warning:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
if (buffer_flag == 0)
warnings++;
}
notification
gfc_notification_std (int std)
{
bool warning;
warning = ((gfc_option.warn_std & std) != 0) && !inhibit_warnings;
if ((gfc_option.allow_std & std) != 0 && !warning)
return SILENT;
return warning ? WARNING : ERROR;
}
try
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)
return SUCCESS;
if (gfc_suppress_error)
return warning ? SUCCESS : FAILURE;
cur_error_buffer = warning ? &warning_buffer : &error_buffer;
cur_error_buffer->flag = 1;
cur_error_buffer->index = 0;
va_start (argp, nocmsgid);
if (warning)
error_print (_("Warning:"), _(nocmsgid), argp);
else
error_print (_("Error:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
if (buffer_flag == 0)
{
if (warning)
warnings++;
else
gfc_increment_error_count();
}
return warning ? SUCCESS : FAILURE;
}
void
gfc_warning_now (const char *nocmsgid, ...)
{
va_list argp;
int i;
if (inhibit_warnings)
return;
i = buffer_flag;
buffer_flag = 0;
warnings++;
va_start (argp, nocmsgid);
error_print (_("Warning:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
buffer_flag = i;
}
void
gfc_clear_warning (void)
{
warning_buffer.flag = 0;
}
void
gfc_warning_check (void)
{
if (warning_buffer.flag)
{
warnings++;
if (warning_buffer.message != NULL)
fputs (warning_buffer.message, stderr);
warning_buffer.flag = 0;
}
}
void
gfc_error (const char *nocmsgid, ...)
{
va_list argp;
if (gfc_suppress_error)
return;
error_buffer.flag = 1;
error_buffer.index = 0;
cur_error_buffer = &error_buffer;
va_start (argp, nocmsgid);
error_print (_("Error:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
if (buffer_flag == 0)
gfc_increment_error_count();
}
void
gfc_error_now (const char *nocmsgid, ...)
{
va_list argp;
int i;
error_buffer.flag = 1;
error_buffer.index = 0;
cur_error_buffer = &error_buffer;
i = buffer_flag;
buffer_flag = 0;
va_start (argp, nocmsgid);
error_print (_("Error:"), _(nocmsgid), argp);
va_end (argp);
error_char ('\0');
gfc_increment_error_count();
buffer_flag = i;
if (flag_fatal_errors)
exit (1);
}
void
gfc_fatal_error (const char *nocmsgid, ...)
{
va_list argp;
buffer_flag = 0;
va_start (argp, nocmsgid);
error_print (_("Fatal Error:"), _(nocmsgid), argp);
va_end (argp);
exit (3);
}
void
gfc_internal_error (const char *format, ...)
{
va_list argp;
buffer_flag = 0;
va_start (argp, format);
show_loci (&gfc_current_locus, NULL);
error_printf ("Internal Error at (1):");
error_print ("", format, argp);
va_end (argp);
exit (ICE_EXIT_CODE);
}
void
gfc_clear_error (void)
{
error_buffer.flag = 0;
}
int
gfc_error_flag_test (void)
{
return error_buffer.flag;
}
int
gfc_error_check (void)
{
int rc;
rc = error_buffer.flag;
if (error_buffer.flag)
{
if (error_buffer.message != NULL)
fputs (error_buffer.message, stderr);
error_buffer.flag = 0;
gfc_increment_error_count();
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)
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)
{
size_t len = strlen (err->message) + 1;
gcc_assert (len <= error_buffer.allocated);
memcpy (error_buffer.message, err->message, len);
gfc_free (err->message);
}
}
void
gfc_free_error (gfc_error_buf * err)
{
if (err->flag)
gfc_free (err->message);
}
void
gfc_status (const char *cmsgid, ...)
{
va_list argp;
va_start (argp, cmsgid);
vprintf (_(cmsgid), argp);
va_end (argp);
}
void
gfc_status_char (char c)
{
putchar (c);
}
void
gfc_get_errors (int *w, int *e)
{
if (w != NULL)
*w = warnings;
if (e != NULL)
*e = errors;
}