1 /* ------------------------------------------------------------------------- */
2 /* "errors" : Warnings, errors and fatal errors */
3 /* (with error throwback code for RISC OS machines) */
5 /* Copyright (c) Graham Nelson 1993 - 2020 */
7 /* This file is part of Inform. */
9 /* Inform is free software: you can redistribute it and/or modify */
10 /* it under the terms of the GNU General Public License as published by */
11 /* the Free Software Foundation, either version 3 of the License, or */
12 /* (at your option) any later version. */
14 /* Inform is distributed in the hope that it will be useful, */
15 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
17 /* GNU General Public License for more details. */
19 /* You should have received a copy of the GNU General Public License */
20 /* along with Inform. If not, see https://gnu.org/licenses/ */
22 /* ------------------------------------------------------------------------- */
26 #define ERROR_BUFLEN (256)
27 static char error_message_buff[ERROR_BUFLEN+4]; /* room for ellipsis */
29 /* ------------------------------------------------------------------------- */
30 /* Error preamble printing. */
31 /* ------------------------------------------------------------------------- */
33 ErrorPosition ErrorReport; /* Maintained by "lexer.c" */
35 static void print_preamble(void)
37 /* Only really prints the preamble to an error or warning message:
39 e.g. "jigsaw.apollo", line 24:
41 The format is controllable (from an ICL switch) since this assists
42 the working of some development environments. */
44 int j, with_extension_flag = FALSE; char *p;
46 j = ErrorReport.file_number;
47 if (j <= 0 || j > total_files) p = ErrorReport.source;
48 else p = InputFiles[j-1].filename;
54 case 0: /* RISC OS error message format */
56 if (!(ErrorReport.main_flag)) printf("\"%s\", ", p);
57 printf("line %d: ", ErrorReport.line_number);
58 if (ErrorReport.orig_file) {
60 if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
61 op = ErrorReport.orig_source;
63 op = InputFiles[ErrorReport.orig_file-1].filename;
64 printf("(\"%s\"", op);
65 if (ErrorReport.orig_line) {
66 printf(", %d", ErrorReport.orig_line);
67 if (ErrorReport.orig_char) {
68 printf(":%d", ErrorReport.orig_char);
75 case 1: /* Microsoft error message format */
77 for (j=0; p[j]!=0; j++)
78 { if (p[j] == FN_SEP) with_extension_flag = TRUE;
79 if (p[j] == '.') with_extension_flag = FALSE;
82 if (with_extension_flag) printf("%s", Source_Extension);
83 printf("(%d): ", ErrorReport.line_number);
86 case 2: /* Macintosh Programmer's Workshop error message format */
88 printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number);
93 static void ellipsize_error_message_buff(void)
95 /* If the error buffer was actually filled up by a message, it was
96 probably truncated too. Add an ellipsis, for which we left
97 extra room. (Yes, yes; errors that are *exactly* 255 characters
98 long will suffer an unnecessary ellipsis.) */
99 if (strlen(error_message_buff) == ERROR_BUFLEN-1)
100 strcat(error_message_buff, "...");
103 /* ------------------------------------------------------------------------- */
104 /* Fatal errors (which have style 0) */
105 /* ------------------------------------------------------------------------- */
107 extern void fatalerror(char *s)
110 printf("Fatal error: %s\n",s);
111 if (no_compiler_errors > 0) print_sorry_message();
119 if (temporary_files_switch) remove_temp_files();
120 abort_transcript_file();
123 my_free(&all_text,"transcription text");
124 longjmp(g_fallback, 1);
129 extern void fatalerror_named(char *m, char *fn)
130 { snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"", m, fn);
131 ellipsize_error_message_buff();
132 fatalerror(error_message_buff);
135 extern void memory_out_error(int32 size, int32 howmany, char *name)
137 snprintf(error_message_buff, ERROR_BUFLEN,
138 "Run out of memory allocating %d bytes for %s", size, name);
140 snprintf(error_message_buff, ERROR_BUFLEN,
141 "Run out of memory allocating array of %dx%d bytes for %s",
142 howmany, size, name);
143 ellipsize_error_message_buff();
144 fatalerror(error_message_buff);
147 extern void memoryerror(char *s, int32 size)
149 snprintf(error_message_buff, ERROR_BUFLEN,
150 "The memory setting %s (which is %ld at present) has been \
151 exceeded. Try running Inform again with $%s=<some-larger-number> on the \
152 command line.",s,(long int) size,s);
153 ellipsize_error_message_buff();
154 fatalerror(error_message_buff);
157 /* ------------------------------------------------------------------------- */
158 /* Survivable diagnostics: */
159 /* compilation errors style 1 */
160 /* warnings style 2 */
161 /* linkage errors style 3 */
162 /* compiler errors style 4 (these should never happen and */
163 /* indicate a bug in Inform) */
164 /* ------------------------------------------------------------------------- */
166 static int errors[MAX_ERRORS];
168 int no_errors, no_warnings, no_suppressed_warnings, no_link_errors,
171 char *forerrors_buff;
172 int forerrors_pointer;
174 static void message(int style, char *s)
175 { int throw_style = style;
176 if (hash_printed_since_newline) printf("\n");
177 hash_printed_since_newline = FALSE;
180 { case 1: printf("Error: "); no_errors++; break;
181 case 2: printf("Warning: "); no_warnings++; break;
182 case 3: printf("Error: [linking '%s'] ", current_module_filename);
183 no_link_errors++; no_errors++; throw_style=1; break;
184 case 4: printf("*** Compiler error: ");
185 no_compiler_errors++; throw_style=1; break;
189 throwback(throw_style, s);
192 ProcessEvents (&g_proc);
196 my_free(&all_text,"transcription text");
198 if (temporary_files_switch) remove_temp_files();
199 abort_transcript_file();
200 longjmp (g_fallback, 1);
203 if ((!concise_switch) && (forerrors_pointer > 0) && (style <= 2))
204 { forerrors_buff[forerrors_pointer] = 0;
205 sprintf(forerrors_buff+68," ...etc");
206 printf("> %s\n",forerrors_buff);
210 /* ------------------------------------------------------------------------- */
211 /* Style 1: Error message routines */
212 /* ------------------------------------------------------------------------- */
214 extern void error(char *s)
215 { if (no_errors == MAX_ERRORS)
216 fatalerror("Too many errors: giving up");
217 errors[no_errors] = no_syntax_lines;
221 extern void error_named(char *s1, char *s2)
222 { snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
223 ellipsize_error_message_buff();
224 error(error_message_buff);
227 extern void error_numbered(char *s1, int val)
229 snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.",s1,val);
230 ellipsize_error_message_buff();
231 error(error_message_buff);
234 extern void error_named_at(char *s1, char *s2, brief_location report_line)
237 ErrorPosition E = ErrorReport;
238 export_brief_location(report_line, &ErrorReport);
240 snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
241 ellipsize_error_message_buff();
243 i = concise_switch; concise_switch = TRUE;
244 error(error_message_buff);
245 ErrorReport = E; concise_switch = i;
248 extern void no_such_label(char *lname)
249 { error_named("No such label as",lname);
252 extern void ebf_error(char *s1, char *s2)
253 { snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s1, s2);
254 ellipsize_error_message_buff();
255 error(error_message_buff);
258 extern void char_error(char *s, int ch)
261 uni = iso_to_unicode(ch);
263 if (character_set_unicode)
264 snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
265 else if (uni >= 0x100)
266 { snprintf(error_message_buff, ERROR_BUFLEN,
267 "%s (unicode) $%04x = (ISO %s) $%02x", s, uni,
268 name_of_iso_set(character_set_setting), ch);
271 snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
273 /* If the character set is set to Latin-1, and the char in question
274 is a printable Latin-1 character, we print it in the error message.
275 This conflates the source-text charset with the terminal charset,
276 really, but it's not a big deal. */
278 if (((uni>=32) && (uni<127))
279 || (((uni >= 0xa1) && (uni <= 0xff))
280 && (character_set_setting==1) && (!character_set_unicode)))
281 { int curlen = strlen(error_message_buff);
282 snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
283 ", i.e., '%c'", uni);
286 ellipsize_error_message_buff();
287 error(error_message_buff);
290 extern void unicode_char_error(char *s, int32 uni)
293 snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
295 snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
297 /* See comment above. */
299 if (((uni>=32) && (uni<127))
300 || (((uni >= 0xa1) && (uni <= 0xff))
301 && (character_set_setting==1) && (!character_set_unicode)))
302 { int curlen = strlen(error_message_buff);
303 snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
304 ", i.e., '%c'", uni);
307 ellipsize_error_message_buff();
308 error(error_message_buff);
311 /* ------------------------------------------------------------------------- */
312 /* Style 2: Warning message routines */
313 /* ------------------------------------------------------------------------- */
315 extern void warning(char *s1)
316 { if (nowarnings_switch) { no_suppressed_warnings++; return; }
320 extern void warning_numbered(char *s1, int val)
321 { if (nowarnings_switch) { no_suppressed_warnings++; return; }
322 snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.", s1, val);
323 ellipsize_error_message_buff();
324 message(2,error_message_buff);
327 extern void warning_named(char *s1, char *s2)
329 if (nowarnings_switch) { no_suppressed_warnings++; return; }
330 snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"", s1, s2);
331 ellipsize_error_message_buff();
332 message(2,error_message_buff);
335 extern void dbnu_warning(char *type, char *name, brief_location report_line)
337 ErrorPosition E = ErrorReport;
338 if (nowarnings_switch) { no_suppressed_warnings++; return; }
339 export_brief_location(report_line, &ErrorReport);
340 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" declared but not used", type, name);
341 ellipsize_error_message_buff();
342 i = concise_switch; concise_switch = TRUE;
343 message(2,error_message_buff);
348 extern void uncalled_routine_warning(char *type, char *name, brief_location report_line)
350 /* This is called for functions which have been detected by the
351 track-unused-routines module. These will often (but not always)
352 be also caught by dbnu_warning(), which tracks symbols rather
353 than routine addresses. */
354 ErrorPosition E = ErrorReport;
355 if (nowarnings_switch) { no_suppressed_warnings++; return; }
356 export_brief_location(report_line, &ErrorReport);
357 if (OMIT_UNUSED_ROUTINES)
358 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused and omitted", type, name);
360 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused (not omitted)", type, name);
361 ellipsize_error_message_buff();
362 i = concise_switch; concise_switch = TRUE;
363 message(2,error_message_buff);
368 extern void obsolete_warning(char *s1)
369 { if (is_systemfile()==1) return;
370 if (obsolete_switch || nowarnings_switch)
371 { no_suppressed_warnings++; return; }
372 snprintf(error_message_buff, ERROR_BUFLEN, "Obsolete usage: %s",s1);
373 ellipsize_error_message_buff();
374 message(2,error_message_buff);
377 /* ------------------------------------------------------------------------- */
378 /* Style 3: Link error message routines */
379 /* ------------------------------------------------------------------------- */
381 extern void link_error(char *s)
382 { if (no_errors==MAX_ERRORS) fatalerror("Too many errors: giving up");
383 errors[no_errors] = no_syntax_lines;
387 extern void link_error_named(char *s1, char *s2)
388 { snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
389 ellipsize_error_message_buff();
390 link_error(error_message_buff);
393 /* ------------------------------------------------------------------------- */
394 /* Style 4: Compiler error message routines */
395 /* ------------------------------------------------------------------------- */
397 extern void print_sorry_message(void)
399 "***********************************************************************\n\
400 Compiler errors should never occur if Inform is working properly.\n\
401 Check to see if there is a more recent version available, from which\n\
402 the problem may have been removed. If not, please report this fault\n\
403 and if at all possible, please include your source code, as faults\n\
404 such as these are rare and often difficult to reproduce. Sorry.\n\
405 ***********************************************************************\n");
408 extern int compiler_error(char *s)
409 { if (no_link_errors > 0) return FALSE;
410 if (no_errors > 0) return FALSE;
411 if (no_compiler_errors==MAX_ERRORS)
412 fatalerror("Too many compiler errors: giving up");
417 extern int compiler_error_named(char *s1, char *s2)
418 { if (no_link_errors > 0) return FALSE;
419 if (no_errors > 0) return FALSE;
420 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"",s1,s2);
421 ellipsize_error_message_buff();
422 compiler_error(error_message_buff);
426 /* ------------------------------------------------------------------------- */
427 /* Code for the Acorn RISC OS operating system, donated by Robin Watts, */
428 /* to provide error throwback under the DDE environment */
429 /* ------------------------------------------------------------------------- */
433 #define DDEUtils_ThrowbackStart 0x42587
434 #define DDEUtils_ThrowbackSend 0x42588
435 #define DDEUtils_ThrowbackEnd 0x42589
439 extern void throwback_start(void)
440 { _kernel_swi_regs regs;
441 if (throwback_switch)
442 _kernel_swi(DDEUtils_ThrowbackStart, ®s, ®s);
445 extern void throwback_end(void)
446 { _kernel_swi_regs regs;
447 if (throwback_switch)
448 _kernel_swi(DDEUtils_ThrowbackEnd, ®s, ®s);
451 int throwback_started = FALSE;
453 extern void throwback(int severity, char * error)
454 { _kernel_swi_regs regs;
455 if (!throwback_started)
456 { throwback_started = TRUE;
459 if (throwback_switch)
461 if ((ErrorReport.file_number == -1)
462 || (ErrorReport.file_number == 0))
463 regs.r[2] = (int) (InputFiles[0].filename);
464 else regs.r[2] = (int) (InputFiles[ErrorReport.file_number-1].filename);
465 regs.r[3] = ErrorReport.line_number;
466 regs.r[4] = (2-severity);
467 regs.r[5] = (int) error;
468 _kernel_swi(DDEUtils_ThrowbackSend, ®s, ®s);
474 /* ========================================================================= */
475 /* Data structure management routines */
476 /* ------------------------------------------------------------------------- */
478 extern void init_errors_vars(void)
479 { forerrors_buff = NULL;
480 no_errors = 0; no_warnings = 0; no_suppressed_warnings = 0;
481 no_compiler_errors = 0;
484 extern void errors_begin_pass(void)
485 { ErrorReport.line_number = 0;
486 ErrorReport.file_number = -1;
487 ErrorReport.source = "<no text read yet>";
488 ErrorReport.main_flag = FALSE;
489 ErrorReport.orig_source = NULL;
490 ErrorReport.orig_file = 0;
491 ErrorReport.orig_line = 0;
492 ErrorReport.orig_char = 0;
495 extern void errors_allocate_arrays(void)
496 { forerrors_buff = my_malloc(512, "errors buffer");
499 extern void errors_free_arrays(void)
500 { my_free(&forerrors_buff, "errors buffer");
503 /* ========================================================================= */