538 lines
14 KiB
C
538 lines
14 KiB
C
/* bad.c -- Implementation File (module.c template V1.0)
|
||
Copyright (C) 1995, 2002, 2003 Free Software Foundation, Inc.
|
||
Contributed by James Craig Burley.
|
||
|
||
This file is part of GNU Fortran.
|
||
|
||
GNU Fortran 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 Fortran 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 Fortran; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||
02111-1307, USA.
|
||
|
||
Related Modules:
|
||
None
|
||
|
||
Description:
|
||
Handles the displaying of diagnostic messages regarding the user's source
|
||
files.
|
||
|
||
Modifications:
|
||
*/
|
||
|
||
/* If there's a %E or %4 in the messages, set this to at least 5,
|
||
for example. */
|
||
|
||
#define FFEBAD_MAX_ 6
|
||
|
||
/* Include files. */
|
||
|
||
#include "proj.h"
|
||
#include "bad.h"
|
||
#include "flags.h"
|
||
#include "com.h"
|
||
#include "toplev.h"
|
||
#include "where.h"
|
||
#include "intl.h"
|
||
#include "diagnostic.h"
|
||
|
||
/* Externals defined here. */
|
||
|
||
bool ffebad_is_inhibited_ = FALSE;
|
||
|
||
/* Simple definitions and enumerations. */
|
||
|
||
#define FFEBAD_LONG_MSGS_ 1 /* 0 to use short (or same) messages. */
|
||
|
||
/* Internal typedefs. */
|
||
|
||
|
||
/* Private include files. */
|
||
|
||
|
||
/* Internal structure definitions. */
|
||
|
||
struct _ffebad_message_
|
||
{
|
||
const ffebadSeverity severity;
|
||
const char *const message;
|
||
};
|
||
|
||
/* Static objects accessed by functions in this module. */
|
||
|
||
static const struct _ffebad_message_ ffebad_messages_[]
|
||
=
|
||
{
|
||
#define FFEBAD_MSG(kwd,sev,msgid) { sev, msgid },
|
||
#if FFEBAD_LONG_MSGS_ == 0
|
||
#define LONG(m)
|
||
#define SHORT(m) m
|
||
#else
|
||
#define LONG(m) m
|
||
#define SHORT(m)
|
||
#endif
|
||
#include "bad.def"
|
||
#undef FFEBAD_MSG
|
||
#undef LONG
|
||
#undef SHORT
|
||
};
|
||
|
||
static struct
|
||
{
|
||
ffewhereLine line;
|
||
ffewhereColumn col;
|
||
ffebadIndex tag;
|
||
}
|
||
|
||
ffebad_here_[FFEBAD_MAX_];
|
||
static const char *ffebad_string_[FFEBAD_MAX_];
|
||
static ffebadIndex ffebad_order_[FFEBAD_MAX_];
|
||
static ffebad ffebad_errnum_;
|
||
static ffebadSeverity ffebad_severity_;
|
||
static const char *ffebad_message_;
|
||
static unsigned char ffebad_index_;
|
||
static ffebadIndex ffebad_places_;
|
||
static bool ffebad_is_temp_inhibited_; /* Effective setting of
|
||
_is_inhibited_ for this
|
||
_start/_finish invocation. */
|
||
|
||
/* Static functions (internal). */
|
||
|
||
static int ffebad_bufputs_ (char buf[], int bufi, const char *s);
|
||
|
||
/* Internal macros. */
|
||
|
||
#define ffebad_bufflush_(buf, bufi) \
|
||
(((buf)[bufi] = '\0'), fputs ((buf), stderr), 0)
|
||
#define ffebad_bufputc_(buf, bufi, c) \
|
||
(((bufi) == ARRAY_SIZE (buf)) \
|
||
? (ffebad_bufflush_ ((buf), (bufi)), ((buf)[0] = (c)), 1) \
|
||
: (((buf)[bufi] = (c)), (bufi) + 1))
|
||
|
||
|
||
static int
|
||
ffebad_bufputs_ (char buf[], int bufi, const char *s)
|
||
{
|
||
for (; *s != '\0'; ++s)
|
||
bufi = ffebad_bufputc_ (buf, bufi, *s);
|
||
return bufi;
|
||
}
|
||
|
||
/* ffebad_init_0 -- Initialize
|
||
|
||
ffebad_init_0(); */
|
||
|
||
void
|
||
ffebad_init_0 (void)
|
||
{
|
||
assert (FFEBAD == ARRAY_SIZE (ffebad_messages_));
|
||
}
|
||
|
||
ffebadSeverity
|
||
ffebad_severity (ffebad errnum)
|
||
{
|
||
return ffebad_messages_[errnum].severity;
|
||
}
|
||
|
||
/* ffebad_start_ -- Start displaying an error message
|
||
|
||
ffebad_start(FFEBAD_SOME_ERROR_CODE);
|
||
|
||
Call ffebad_start to establish the message, ffebad_here and ffebad_string
|
||
to send run-time data to it as necessary, then ffebad_finish when through
|
||
to actually get it to print (to stderr).
|
||
|
||
Note: ffebad_start(errnum) turns into ffebad_start_(FALSE,errnum). No
|
||
outside caller should call ffebad_start_ directly (as indicated by the
|
||
trailing underscore).
|
||
|
||
Call ffebad_start to start a normal message, one that might be inhibited
|
||
by the current state of statement guessing. Call ffebad_start_lex
|
||
instead to start a message that is global to all statement guesses and
|
||
happens only once for all guesses (i.e. the lexer).
|
||
|
||
sev and message are overrides for the severity and messages when errnum
|
||
is FFEBAD, meaning the caller didn't want to have to put a message in
|
||
bad.def to produce a diagnostic. */
|
||
|
||
bool
|
||
ffebad_start_ (bool lex_override, ffebad errnum, ffebadSeverity sev,
|
||
const char *msgid)
|
||
{
|
||
unsigned char i;
|
||
|
||
if (ffebad_is_inhibited_ && !lex_override)
|
||
{
|
||
ffebad_is_temp_inhibited_ = TRUE;
|
||
return FALSE;
|
||
}
|
||
|
||
if (errnum != FFEBAD)
|
||
{
|
||
ffebad_severity_ = ffebad_messages_[errnum].severity;
|
||
ffebad_message_ = gettext (ffebad_messages_[errnum].message);
|
||
}
|
||
else
|
||
{
|
||
ffebad_severity_ = sev;
|
||
ffebad_message_ = gettext (msgid);
|
||
}
|
||
|
||
switch (ffebad_severity_)
|
||
{ /* Tell toplev.c about this message. */
|
||
case FFEBAD_severityINFORMATIONAL:
|
||
case FFEBAD_severityTRIVIAL:
|
||
if (inhibit_warnings)
|
||
{ /* User wants no warnings. */
|
||
ffebad_is_temp_inhibited_ = TRUE;
|
||
return FALSE;
|
||
}
|
||
/* Fall through. */
|
||
case FFEBAD_severityWARNING:
|
||
case FFEBAD_severityPECULIAR:
|
||
case FFEBAD_severityPEDANTIC:
|
||
if ((ffebad_severity_ != FFEBAD_severityPEDANTIC)
|
||
|| !flag_pedantic_errors)
|
||
{
|
||
if (!diagnostic_report_warnings_p ())
|
||
{ /* User wants no warnings. */
|
||
ffebad_is_temp_inhibited_ = TRUE;
|
||
return FALSE;
|
||
}
|
||
diagnostic_kind_count (global_dc, DK_WARNING)++;
|
||
break;
|
||
}
|
||
/* Fall through (PEDANTIC && flag_pedantic_errors). */
|
||
case FFEBAD_severityFATAL:
|
||
case FFEBAD_severityWEIRD:
|
||
case FFEBAD_severitySEVERE:
|
||
case FFEBAD_severityDISASTER:
|
||
diagnostic_kind_count (global_dc, DK_ERROR)++;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
ffebad_is_temp_inhibited_ = FALSE;
|
||
ffebad_errnum_ = errnum;
|
||
ffebad_index_ = 0;
|
||
ffebad_places_ = 0;
|
||
for (i = 0; i < FFEBAD_MAX_; ++i)
|
||
{
|
||
ffebad_string_[i] = NULL;
|
||
ffebad_here_[i].line = ffewhere_line_unknown ();
|
||
ffebad_here_[i].col = ffewhere_column_unknown ();
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/* ffebad_here -- Establish source location of some diagnostic concern
|
||
|
||
ffebad_here(ffebadIndex i,ffewhereLine line,ffewhereColumn col);
|
||
|
||
Call ffebad_start to establish the message, ffebad_here and ffebad_string
|
||
to send run-time data to it as necessary, then ffebad_finish when through
|
||
to actually get it to print (to stderr). */
|
||
|
||
void
|
||
ffebad_here (ffebadIndex index, ffewhereLine line, ffewhereColumn col)
|
||
{
|
||
ffewhereLineNumber line_num;
|
||
ffewhereLineNumber ln;
|
||
ffewhereColumnNumber col_num;
|
||
ffewhereColumnNumber cn;
|
||
ffebadIndex i;
|
||
ffebadIndex j;
|
||
|
||
if (ffebad_is_temp_inhibited_)
|
||
return;
|
||
|
||
assert (index < FFEBAD_MAX_);
|
||
ffebad_here_[index].line = ffewhere_line_use (line);
|
||
ffebad_here_[index].col = ffewhere_column_use (col);
|
||
if (ffewhere_line_is_unknown (line)
|
||
|| ffewhere_column_is_unknown (col))
|
||
{
|
||
ffebad_here_[index].tag = FFEBAD_MAX_;
|
||
return;
|
||
}
|
||
ffebad_here_[index].tag = 0; /* For now, though it shouldn't matter. */
|
||
|
||
/* Sort the source line/col points into the order they occur in the source
|
||
file. Deal with duplicates appropriately. */
|
||
|
||
line_num = ffewhere_line_number (line);
|
||
col_num = ffewhere_column_number (col);
|
||
|
||
/* Determine where in the ffebad_order_ array this new place should go. */
|
||
|
||
for (i = 0; i < ffebad_places_; ++i)
|
||
{
|
||
ln = ffewhere_line_number (ffebad_here_[ffebad_order_[i]].line);
|
||
cn = ffewhere_column_number (ffebad_here_[ffebad_order_[i]].col);
|
||
if (line_num < ln)
|
||
break;
|
||
if (line_num == ln)
|
||
{
|
||
if (col_num == cn)
|
||
{
|
||
ffebad_here_[index].tag = i;
|
||
return; /* Shouldn't go in, has equivalent. */
|
||
}
|
||
else if (col_num < cn)
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Before putting new place in ffebad_order_[i], first increment all tags
|
||
that are i or greater. */
|
||
|
||
if (i != ffebad_places_)
|
||
{
|
||
for (j = 0; j < FFEBAD_MAX_; ++j)
|
||
{
|
||
if (ffebad_here_[j].tag >= i)
|
||
++ffebad_here_[j].tag;
|
||
}
|
||
}
|
||
|
||
/* Then slide all ffebad_order_[] entries at and above i up one entry. */
|
||
|
||
for (j = ffebad_places_; j > i; --j)
|
||
ffebad_order_[j] = ffebad_order_[j - 1];
|
||
|
||
/* Finally can put new info in ffebad_order_[i]. */
|
||
|
||
ffebad_order_[i] = index;
|
||
ffebad_here_[index].tag = i;
|
||
++ffebad_places_;
|
||
}
|
||
|
||
/* Establish string for next index (always in order) of message
|
||
|
||
ffebad_string(const char *string);
|
||
|
||
Call ffebad_start to establish the message, ffebad_here and ffebad_string
|
||
to send run-time data to it as necessary, then ffebad_finish when through
|
||
to actually get it to print (to stderr). Note: don't trash the string
|
||
until after calling ffebad_finish, since we just maintain a pointer to
|
||
the argument passed in until then. */
|
||
|
||
void
|
||
ffebad_string (const char *string)
|
||
{
|
||
if (ffebad_is_temp_inhibited_)
|
||
return;
|
||
|
||
assert (ffebad_index_ != FFEBAD_MAX_);
|
||
ffebad_string_[ffebad_index_++] = string;
|
||
}
|
||
|
||
/* ffebad_finish -- Display error message with where & run-time info
|
||
|
||
ffebad_finish();
|
||
|
||
Call ffebad_start to establish the message, ffebad_here and ffebad_string
|
||
to send run-time data to it as necessary, then ffebad_finish when through
|
||
to actually get it to print (to stderr). */
|
||
|
||
void
|
||
ffebad_finish (void)
|
||
{
|
||
#define MAX_SPACES 132
|
||
static const char *const spaces
|
||
= "...>\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
|
||
\040\040\040"; /* MAX_SPACES - 1 spaces. */
|
||
ffewhereLineNumber last_line_num;
|
||
ffewhereLineNumber ln;
|
||
ffewhereLineNumber rn;
|
||
ffewhereColumnNumber last_col_num;
|
||
ffewhereColumnNumber cn;
|
||
ffewhereColumnNumber cnt;
|
||
ffewhereLine l;
|
||
ffebadIndex bi;
|
||
unsigned short i;
|
||
char pointer;
|
||
unsigned char c;
|
||
unsigned const char *s;
|
||
const char *fn;
|
||
static char buf[1024];
|
||
int bufi;
|
||
int index;
|
||
|
||
if (ffebad_is_temp_inhibited_)
|
||
return;
|
||
|
||
switch (ffebad_severity_)
|
||
{
|
||
case FFEBAD_severityINFORMATIONAL:
|
||
s = _("note:");
|
||
break;
|
||
|
||
case FFEBAD_severityWARNING:
|
||
s = _("warning:");
|
||
break;
|
||
|
||
case FFEBAD_severitySEVERE:
|
||
s = _("fatal:");
|
||
break;
|
||
|
||
default:
|
||
s = "";
|
||
break;
|
||
}
|
||
|
||
/* Display the annoying source references. */
|
||
|
||
last_line_num = 0;
|
||
last_col_num = 0;
|
||
|
||
for (bi = 0; bi < ffebad_places_; ++bi)
|
||
{
|
||
if (ffebad_places_ == 1)
|
||
pointer = '^';
|
||
else
|
||
pointer = '1' + bi;
|
||
|
||
l = ffebad_here_[ffebad_order_[bi]].line;
|
||
ln = ffewhere_line_number (l);
|
||
rn = ffewhere_line_filelinenum (l);
|
||
cn = ffewhere_column_number (ffebad_here_[ffebad_order_[bi]].col);
|
||
fn = ffewhere_line_filename (l);
|
||
if (ln != last_line_num)
|
||
{
|
||
if (bi != 0)
|
||
fputc ('\n', stderr);
|
||
diagnostic_report_current_function (global_dc);
|
||
fprintf (stderr,
|
||
/* the trailing space on the <file>:<line>: line
|
||
fools emacs19 compilation mode into finding the
|
||
report */
|
||
"%s:%" ffewhereLineNumber_f "u: %s\n %s\n %s%c",
|
||
fn, rn,
|
||
s,
|
||
ffewhere_line_content (l),
|
||
&spaces[cn > MAX_SPACES ? 0 : MAX_SPACES - cn + 4],
|
||
pointer);
|
||
last_line_num = ln;
|
||
last_col_num = cn;
|
||
s = _("(continued):");
|
||
}
|
||
else
|
||
{
|
||
cnt = cn - last_col_num;
|
||
fprintf (stderr,
|
||
"%s%c", &spaces[cnt > MAX_SPACES
|
||
? 0 : MAX_SPACES - cnt + 4],
|
||
pointer);
|
||
last_col_num = cn;
|
||
}
|
||
}
|
||
if (ffebad_places_ == 0)
|
||
{
|
||
/* Didn't output "warning:" string, capitalize it for message. */
|
||
if (s[0] != '\0')
|
||
{
|
||
char c;
|
||
|
||
c = TOUPPER (s[0]);
|
||
fprintf (stderr, "%c%s ", c, &s[1]);
|
||
}
|
||
else if (s[0] != '\0')
|
||
fprintf (stderr, "%s ", s);
|
||
}
|
||
else
|
||
fputc ('\n', stderr);
|
||
|
||
/* Release the ffewhere info. */
|
||
|
||
for (bi = 0; bi < FFEBAD_MAX_; ++bi)
|
||
{
|
||
ffewhere_line_kill (ffebad_here_[bi].line);
|
||
ffewhere_column_kill (ffebad_here_[bi].col);
|
||
}
|
||
|
||
/* Now display the message. */
|
||
|
||
bufi = 0;
|
||
for (i = 0; (c = ffebad_message_[i]) != '\0'; ++i)
|
||
{
|
||
if (c == '%')
|
||
{
|
||
c = ffebad_message_[++i];
|
||
if (ISUPPER (c))
|
||
{
|
||
index = c - 'A';
|
||
|
||
if ((index < 0) || (index >= FFEBAD_MAX_))
|
||
{
|
||
bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!] %"));
|
||
bufi = ffebad_bufputc_ (buf, bufi, c);
|
||
}
|
||
else
|
||
{
|
||
s = ffebad_string_[index];
|
||
if (s == NULL)
|
||
bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!]"));
|
||
else
|
||
bufi = ffebad_bufputs_ (buf, bufi, s);
|
||
}
|
||
}
|
||
else if (ISDIGIT (c))
|
||
{
|
||
index = c - '0';
|
||
|
||
if ((index < 0) || (index >= FFEBAD_MAX_))
|
||
{
|
||
bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!] %"));
|
||
bufi = ffebad_bufputc_ (buf, bufi, c);
|
||
}
|
||
else
|
||
{
|
||
pointer = ffebad_here_[index].tag + '1';
|
||
if (pointer == FFEBAD_MAX_ + '1')
|
||
pointer = '?';
|
||
else if (ffebad_places_ == 1)
|
||
pointer = '^';
|
||
bufi = ffebad_bufputc_ (buf, bufi, '(');
|
||
bufi = ffebad_bufputc_ (buf, bufi, pointer);
|
||
bufi = ffebad_bufputc_ (buf, bufi, ')');
|
||
}
|
||
}
|
||
else if (c == '\0')
|
||
break;
|
||
else if (c == '%')
|
||
bufi = ffebad_bufputc_ (buf, bufi, '%');
|
||
else
|
||
{
|
||
bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!]"));
|
||
bufi = ffebad_bufputc_ (buf, bufi, '%');
|
||
bufi = ffebad_bufputc_ (buf, bufi, c);
|
||
}
|
||
}
|
||
else
|
||
bufi = ffebad_bufputc_ (buf, bufi, c);
|
||
}
|
||
bufi = ffebad_bufputc_ (buf, bufi, '\n');
|
||
bufi = ffebad_bufflush_ (buf, bufi);
|
||
}
|