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