OSDN Git Service

2002-02-06 Toon Moene <toon@moene.indiv.nluug.nl>
[pf3gnuchains/gcc-fork.git] / gcc / f / bad.c
1 /* bad.c -- Implementation File (module.c template V1.0)
2    Copyright (C) 1995, 2002 Free Software Foundation, Inc.
3    Contributed by James Craig Burley.
4
5 This file is part of GNU Fortran.
6
7 GNU Fortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Fortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Fortran; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21
22    Related Modules:
23       None
24
25    Description:
26       Handles the displaying of diagnostic messages regarding the user's source
27       files.
28
29    Modifications:
30 */
31
32 /* If there's a %E or %4 in the messages, set this to at least 5,
33    for example.  */
34
35 #define FFEBAD_MAX_ 6
36
37 /* Include files. */
38
39 #include "proj.h"
40 #include "bad.h"
41 #include "flags.h"
42 #include "com.h"
43 #include "toplev.h"
44 #include "where.h"
45 #include "intl.h"
46
47 /* Externals defined here. */
48
49 bool ffebad_is_inhibited_ = FALSE;
50
51 /* Simple definitions and enumerations. */
52
53 #define FFEBAD_LONG_MSGS_ 1     /* 0 to use short (or same) messages. */
54
55 /* Internal typedefs. */
56
57
58 /* Private include files. */
59
60
61 /* Internal structure definitions. */
62
63 struct _ffebad_message_
64   {
65     const ffebadSeverity severity;
66     const char *const message;
67   };
68
69 /* Static objects accessed by functions in this module.  */
70
71 static const struct _ffebad_message_ ffebad_messages_[]
72 =
73 {
74 #define FFEBAD_MSG(kwd,sev,msgid) { sev, msgid },
75 #if FFEBAD_LONG_MSGS_ == 0
76 #define LONG(m)
77 #define SHORT(m) m
78 #else
79 #define LONG(m) m
80 #define SHORT(m)
81 #endif
82 #include "bad.def"
83 #undef FFEBAD_MSG
84 #undef LONG
85 #undef SHORT
86 };
87
88 static struct
89   {
90     ffewhereLine line;
91     ffewhereColumn col;
92     ffebadIndex tag;
93   }
94
95 ffebad_here_[FFEBAD_MAX_];
96 static const char *ffebad_string_[FFEBAD_MAX_];
97 static ffebadIndex ffebad_order_[FFEBAD_MAX_];
98 static ffebad ffebad_errnum_;
99 static ffebadSeverity ffebad_severity_;
100 static const char *ffebad_message_;
101 static unsigned char ffebad_index_;
102 static ffebadIndex ffebad_places_;
103 static bool ffebad_is_temp_inhibited_;  /* Effective setting of
104                                            _is_inhibited_ for this
105                                            _start/_finish invocation. */
106
107 /* Static functions (internal). */
108
109 static int ffebad_bufputs_ (char buf[], int bufi, const char *s);
110
111 /* Internal macros. */
112
113 #define ffebad_bufflush_(buf, bufi) \
114   (((buf)[bufi] = '\0'), fputs ((buf), stderr), 0)
115 #define ffebad_bufputc_(buf, bufi, c) \
116   (((bufi) == ARRAY_SIZE (buf)) \
117    ? (ffebad_bufflush_ ((buf), (bufi)), ((buf)[0] = (c)), 1) \
118    : (((buf)[bufi] = (c)), (bufi) + 1))
119 \f
120
121 static int
122 ffebad_bufputs_ (char buf[], int bufi, const char *s)
123 {
124   for (; *s != '\0'; ++s)
125     bufi = ffebad_bufputc_ (buf, bufi, *s);
126   return bufi;
127 }
128
129 /* ffebad_init_0 -- Initialize
130
131    ffebad_init_0();  */
132
133 void
134 ffebad_init_0 ()
135 {
136   assert (FFEBAD == ARRAY_SIZE (ffebad_messages_));
137 }
138
139 ffebadSeverity
140 ffebad_severity (ffebad errnum)
141 {
142   return ffebad_messages_[errnum].severity;
143 }
144
145 /* ffebad_start_ -- Start displaying an error message
146
147    ffebad_start(FFEBAD_SOME_ERROR_CODE);
148
149    Call ffebad_start to establish the message, ffebad_here and ffebad_string
150    to send run-time data to it as necessary, then ffebad_finish when through
151    to actually get it to print (to stderr).
152
153    Note: ffebad_start(errnum) turns into ffebad_start_(FALSE,errnum).  No
154    outside caller should call ffebad_start_ directly (as indicated by the
155    trailing underscore).
156
157    Call ffebad_start to start a normal message, one that might be inhibited
158    by the current state of statement guessing.  Call ffebad_start_lex
159    instead to start a message that is global to all statement guesses and
160    happens only once for all guesses (i.e. the lexer).
161
162    sev and message are overrides for the severity and messages when errnum
163    is FFEBAD, meaning the caller didn't want to have to put a message in
164    bad.def to produce a diagnostic.  */
165
166 bool
167 ffebad_start_ (bool lex_override, ffebad errnum, ffebadSeverity sev,
168                const char *msgid)
169 {
170   unsigned char i;
171
172   if (ffebad_is_inhibited_ && !lex_override)
173     {
174       ffebad_is_temp_inhibited_ = TRUE;
175       return FALSE;
176     }
177
178   if (errnum != FFEBAD)
179     {
180       ffebad_severity_ = ffebad_messages_[errnum].severity;
181       ffebad_message_ = gettext (ffebad_messages_[errnum].message);
182     }
183   else
184     {
185       ffebad_severity_ = sev;
186       ffebad_message_ = gettext (msgid);
187     }
188
189   switch (ffebad_severity_)
190     {                           /* Tell toplev.c about this message. */
191     case FFEBAD_severityINFORMATIONAL:
192     case FFEBAD_severityTRIVIAL:
193       if (inhibit_warnings)
194         {                       /* User wants no warnings. */
195           ffebad_is_temp_inhibited_ = TRUE;
196           return FALSE;
197         }
198       /* Fall through.  */
199     case FFEBAD_severityWARNING:
200     case FFEBAD_severityPECULIAR:
201     case FFEBAD_severityPEDANTIC:
202       if ((ffebad_severity_ != FFEBAD_severityPEDANTIC)
203           || !flag_pedantic_errors)
204         {
205           if (count_error (1) == 0)
206             {                   /* User wants no warnings. */
207               ffebad_is_temp_inhibited_ = TRUE;
208               return FALSE;
209             }
210           break;
211         }
212       /* Fall through (PEDANTIC && flag_pedantic_errors).  */
213     case FFEBAD_severityFATAL:
214     case FFEBAD_severityWEIRD:
215     case FFEBAD_severitySEVERE:
216     case FFEBAD_severityDISASTER:
217       count_error (0);
218       break;
219
220     default:
221       break;
222     }
223
224   ffebad_is_temp_inhibited_ = FALSE;
225   ffebad_errnum_ = errnum;
226   ffebad_index_ = 0;
227   ffebad_places_ = 0;
228   for (i = 0; i < FFEBAD_MAX_; ++i)
229     {
230       ffebad_string_[i] = NULL;
231       ffebad_here_[i].line = ffewhere_line_unknown ();
232       ffebad_here_[i].col = ffewhere_column_unknown ();
233     }
234
235   return TRUE;
236 }
237
238 /* ffebad_here -- Establish source location of some diagnostic concern
239
240    ffebad_here(ffebadIndex i,ffewhereLine line,ffewhereColumn col);
241
242    Call ffebad_start to establish the message, ffebad_here and ffebad_string
243    to send run-time data to it as necessary, then ffebad_finish when through
244    to actually get it to print (to stderr).  */
245
246 void
247 ffebad_here (ffebadIndex index, ffewhereLine line, ffewhereColumn col)
248 {
249   ffewhereLineNumber line_num;
250   ffewhereLineNumber ln;
251   ffewhereColumnNumber col_num;
252   ffewhereColumnNumber cn;
253   ffebadIndex i;
254   ffebadIndex j;
255
256   if (ffebad_is_temp_inhibited_)
257     return;
258
259   assert (index < FFEBAD_MAX_);
260   ffebad_here_[index].line = ffewhere_line_use (line);
261   ffebad_here_[index].col = ffewhere_column_use (col);
262   if (ffewhere_line_is_unknown (line)
263       || ffewhere_column_is_unknown (col))
264     {
265       ffebad_here_[index].tag = FFEBAD_MAX_;
266       return;
267     }
268   ffebad_here_[index].tag = 0;  /* For now, though it shouldn't matter. */
269
270   /* Sort the source line/col points into the order they occur in the source
271      file.  Deal with duplicates appropriately. */
272
273   line_num = ffewhere_line_number (line);
274   col_num = ffewhere_column_number (col);
275
276   /* Determine where in the ffebad_order_ array this new place should go. */
277
278   for (i = 0; i < ffebad_places_; ++i)
279     {
280       ln = ffewhere_line_number (ffebad_here_[ffebad_order_[i]].line);
281       cn = ffewhere_column_number (ffebad_here_[ffebad_order_[i]].col);
282       if (line_num < ln)
283         break;
284       if (line_num == ln)
285         {
286           if (col_num == cn)
287             {
288               ffebad_here_[index].tag = i;
289               return;           /* Shouldn't go in, has equivalent. */
290             }
291           else if (col_num < cn)
292             break;
293         }
294     }
295
296   /* Before putting new place in ffebad_order_[i], first increment all tags
297      that are i or greater. */
298
299   if (i != ffebad_places_)
300     {
301       for (j = 0; j < FFEBAD_MAX_; ++j)
302         {
303           if (ffebad_here_[j].tag >= i)
304             ++ffebad_here_[j].tag;
305         }
306     }
307
308   /* Then slide all ffebad_order_[] entries at and above i up one entry. */
309
310   for (j = ffebad_places_; j > i; --j)
311     ffebad_order_[j] = ffebad_order_[j - 1];
312
313   /* Finally can put new info in ffebad_order_[i]. */
314
315   ffebad_order_[i] = index;
316   ffebad_here_[index].tag = i;
317   ++ffebad_places_;
318 }
319
320 /* Establish string for next index (always in order) of message
321
322    ffebad_string(const char *string);
323
324    Call ffebad_start to establish the message, ffebad_here and ffebad_string
325    to send run-time data to it as necessary, then ffebad_finish when through
326    to actually get it to print (to stderr).  Note: don't trash the string
327    until after calling ffebad_finish, since we just maintain a pointer to
328    the argument passed in until then.  */
329
330 void
331 ffebad_string (const char *string)
332 {
333   if (ffebad_is_temp_inhibited_)
334     return;
335
336   assert (ffebad_index_ != FFEBAD_MAX_);
337   ffebad_string_[ffebad_index_++] = string;
338 }
339
340 /* ffebad_finish -- Display error message with where & run-time info
341
342    ffebad_finish();
343
344    Call ffebad_start to establish the message, ffebad_here and ffebad_string
345    to send run-time data to it as necessary, then ffebad_finish when through
346    to actually get it to print (to stderr).  */
347
348 void
349 ffebad_finish ()
350 {
351 #define MAX_SPACES 132
352   static const char *const spaces
353   = "...>\
354 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
355 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
356 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
357 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
358 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
359 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
360 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
361 \040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
362 \040\040\040";                  /* MAX_SPACES - 1 spaces. */
363   ffewhereLineNumber last_line_num;
364   ffewhereLineNumber ln;
365   ffewhereLineNumber rn;
366   ffewhereColumnNumber last_col_num;
367   ffewhereColumnNumber cn;
368   ffewhereColumnNumber cnt;
369   ffewhereLine l;
370   ffebadIndex bi;
371   unsigned short i;
372   char pointer;
373   unsigned char c;
374   unsigned const char *s;
375   const char *fn;
376   static char buf[1024];
377   int bufi;
378   int index;
379
380   if (ffebad_is_temp_inhibited_)
381     return;
382
383   switch (ffebad_severity_)
384     {
385     case FFEBAD_severityINFORMATIONAL:
386       s = _("note:");
387       break;
388
389     case FFEBAD_severityWARNING:
390       s = _("warning:");
391       break;
392
393     case FFEBAD_severitySEVERE:
394       s = _("fatal:");
395       break;
396
397     default:
398       s = "";
399       break;
400     }
401
402   /* Display the annoying source references. */
403
404   last_line_num = 0;
405   last_col_num = 0;
406
407   for (bi = 0; bi < ffebad_places_; ++bi)
408     {
409       if (ffebad_places_ == 1)
410         pointer = '^';
411       else
412         pointer = '1' + bi;
413
414       l = ffebad_here_[ffebad_order_[bi]].line;
415       ln = ffewhere_line_number (l);
416       rn = ffewhere_line_filelinenum (l);
417       cn = ffewhere_column_number (ffebad_here_[ffebad_order_[bi]].col);
418       fn = ffewhere_line_filename (l);
419       if (ln != last_line_num)
420         {
421           if (bi != 0)
422             fputc ('\n', stderr);
423           report_error_function (fn);
424           fprintf (stderr,
425                    /* the trailing space on the <file>:<line>: line
426                       fools emacs19 compilation mode into finding the
427                       report */
428                    "%s:%" ffewhereLineNumber_f "u: %s\n   %s\n   %s%c",
429                    fn, rn,
430                    s,
431                    ffewhere_line_content (l),
432                    &spaces[cn > MAX_SPACES ? 0 : MAX_SPACES - cn + 4],
433                    pointer);
434           last_line_num = ln;
435           last_col_num = cn;
436           s = _("(continued):");
437         }
438       else
439         {
440           cnt = cn - last_col_num;
441           fprintf (stderr,
442                    "%s%c", &spaces[cnt > MAX_SPACES
443                                    ? 0 : MAX_SPACES - cnt + 4],
444                    pointer);
445           last_col_num = cn;
446         }
447     }
448   if (ffebad_places_ == 0)
449     {
450       /* Didn't output "warning:" string, capitalize it for message.  */
451       if (s[0] != '\0')
452         {
453           char c;
454
455           c = TOUPPER (s[0]);
456           fprintf (stderr, "%c%s ", c, &s[1]);
457         }
458       else if (s[0] != '\0')
459         fprintf (stderr, "%s ", s);
460     }
461   else
462     fputc ('\n', stderr);
463
464   /* Release the ffewhere info. */
465
466   for (bi = 0; bi < FFEBAD_MAX_; ++bi)
467     {
468       ffewhere_line_kill (ffebad_here_[bi].line);
469       ffewhere_column_kill (ffebad_here_[bi].col);
470     }
471
472   /* Now display the message. */
473
474   bufi = 0;
475   for (i = 0; (c = ffebad_message_[i]) != '\0'; ++i)
476     {
477       if (c == '%')
478         {
479           c = ffebad_message_[++i];
480           if (ISUPPER (c))
481             {
482               index = c - 'A';
483
484               if ((index < 0) || (index >= FFEBAD_MAX_))
485                 {
486                   bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!] %"));
487                   bufi = ffebad_bufputc_ (buf, bufi, c);
488                 }
489               else
490                 {
491                   s = ffebad_string_[index];
492                   if (s == NULL)
493                     bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!]"));
494                   else
495                     bufi = ffebad_bufputs_ (buf, bufi, s);
496                 }
497             }
498           else if (ISDIGIT (c))
499             {
500               index = c - '0';
501
502               if ((index < 0) || (index >= FFEBAD_MAX_))
503                 {
504                   bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!] %"));
505                   bufi = ffebad_bufputc_ (buf, bufi, c);
506                 }
507               else
508                 {
509                   pointer = ffebad_here_[index].tag + '1';
510                   if (pointer == FFEBAD_MAX_ + '1')
511                     pointer = '?';
512                   else if (ffebad_places_ == 1)
513                     pointer = '^';
514                   bufi = ffebad_bufputc_ (buf, bufi, '(');
515                   bufi = ffebad_bufputc_ (buf, bufi, pointer);
516                   bufi = ffebad_bufputc_ (buf, bufi, ')');
517                 }
518             }
519           else if (c == '\0')
520             break;
521           else if (c == '%')
522             bufi = ffebad_bufputc_ (buf, bufi, '%');
523           else
524             {
525               bufi = ffebad_bufputs_ (buf, bufi, _("[REPORT BUG!!]"));
526               bufi = ffebad_bufputc_ (buf, bufi, '%');
527               bufi = ffebad_bufputc_ (buf, bufi, c);
528             }
529         }
530       else
531         bufi = ffebad_bufputc_ (buf, bufi, c);
532     }
533   bufi = ffebad_bufputc_ (buf, bufi, '\n');
534   bufi = ffebad_bufflush_ (buf, bufi);
535 }