1 /* ------------------------------------------------------------------------- */
2 /* "errors" : Warnings, errors and fatal errors */
3 /* (with error throwback code for RISC OS machines) */
5 /* Copyright (c) Graham Nelson 1993 - 2018 */
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 * This is version %d.%02d of Inform, dated %20s: so *\n\
402 * if that was more than six months ago, there may be a more recent *\n\
403 * version available, from which the problem may have been removed. *\n\
404 * If not, please report this fault to: graham@gnelson.demon.co.uk *\n\
405 * and if at all possible, please include your source code, as faults *\n\
406 * such as these are rare and often difficult to reproduce. Sorry. *\n\
407 ***********************************************************************\n",
408 (RELEASE_NUMBER/100)%10, RELEASE_NUMBER%100, RELEASE_DATE);
411 extern int compiler_error(char *s)
412 { if (no_link_errors > 0) return FALSE;
413 if (no_errors > 0) return FALSE;
414 if (no_compiler_errors==MAX_ERRORS)
415 fatalerror("Too many compiler errors: giving up");
420 extern int compiler_error_named(char *s1, char *s2)
421 { if (no_link_errors > 0) return FALSE;
422 if (no_errors > 0) return FALSE;
423 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"",s1,s2);
424 ellipsize_error_message_buff();
425 compiler_error(error_message_buff);
429 /* ------------------------------------------------------------------------- */
430 /* Code for the Acorn RISC OS operating system, donated by Robin Watts, */
431 /* to provide error throwback under the DDE environment */
432 /* ------------------------------------------------------------------------- */
436 #define DDEUtils_ThrowbackStart 0x42587
437 #define DDEUtils_ThrowbackSend 0x42588
438 #define DDEUtils_ThrowbackEnd 0x42589
442 extern void throwback_start(void)
443 { _kernel_swi_regs regs;
444 if (throwback_switch)
445 _kernel_swi(DDEUtils_ThrowbackStart, ®s, ®s);
448 extern void throwback_end(void)
449 { _kernel_swi_regs regs;
450 if (throwback_switch)
451 _kernel_swi(DDEUtils_ThrowbackEnd, ®s, ®s);
454 int throwback_started = FALSE;
456 extern void throwback(int severity, char * error)
457 { _kernel_swi_regs regs;
458 if (!throwback_started)
459 { throwback_started = TRUE;
462 if (throwback_switch)
464 if ((ErrorReport.file_number == -1)
465 || (ErrorReport.file_number == 0))
466 regs.r[2] = (int) (InputFiles[0].filename);
467 else regs.r[2] = (int) (InputFiles[ErrorReport.file_number-1].filename);
468 regs.r[3] = ErrorReport.line_number;
469 regs.r[4] = (2-severity);
470 regs.r[5] = (int) error;
471 _kernel_swi(DDEUtils_ThrowbackSend, ®s, ®s);
477 /* ========================================================================= */
478 /* Data structure management routines */
479 /* ------------------------------------------------------------------------- */
481 extern void init_errors_vars(void)
482 { forerrors_buff = NULL;
483 no_errors = 0; no_warnings = 0; no_suppressed_warnings = 0;
484 no_compiler_errors = 0;
487 extern void errors_begin_pass(void)
488 { ErrorReport.line_number = 0;
489 ErrorReport.file_number = -1;
490 ErrorReport.source = "<no text read yet>";
491 ErrorReport.main_flag = FALSE;
492 ErrorReport.orig_source = NULL;
493 ErrorReport.orig_file = 0;
494 ErrorReport.orig_line = 0;
495 ErrorReport.orig_char = 0;
498 extern void errors_allocate_arrays(void)
499 { forerrors_buff = my_malloc(512, "errors buffer");
502 extern void errors_free_arrays(void)
503 { my_free(&forerrors_buff, "errors buffer");
506 /* ========================================================================= */