xref: /openbsd/gnu/usr.bin/gcc/gcc/f/bad.c (revision c87b03e5)
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