1 /* ------------------------------------------------------------------------- */
2 /* "errors" : Warnings, errors and fatal errors */
3 /* (with error throwback code for RISC OS machines) */
5 /* Copyright (c) Graham Nelson 1993 - 2016 */
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 > input_file) 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);
60 case 1: /* Microsoft error message format */
62 for (j=0; p[j]!=0; j++)
63 { if (p[j] == FN_SEP) with_extension_flag = TRUE;
64 if (p[j] == '.') with_extension_flag = FALSE;
67 if (with_extension_flag) printf("%s", Source_Extension);
68 printf("(%d): ", ErrorReport.line_number);
71 case 2: /* Macintosh Programmer's Workshop error message format */
73 printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number);
78 static void ellipsize_error_message_buff(void)
80 /* If the error buffer was actually filled up by a message, it was
81 probably truncated too. Add an ellipsis, for which we left
82 extra room. (Yes, yes; errors that are *exactly* 255 characters
83 long will suffer an unnecessary ellipsis.) */
84 if (strlen(error_message_buff) == ERROR_BUFLEN-1)
85 strcat(error_message_buff, "...");
88 /* ------------------------------------------------------------------------- */
89 /* Fatal errors (which have style 0) */
90 /* ------------------------------------------------------------------------- */
92 extern void fatalerror(char *s)
95 printf("Fatal error: %s\n",s);
96 if (no_compiler_errors > 0) print_sorry_message();
104 if (temporary_files_switch) remove_temp_files();
105 abort_transcript_file();
108 my_free(&all_text,"transcription text");
109 longjmp(g_fallback, 1);
114 extern void fatalerror_named(char *m, char *fn)
115 { snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"", m, fn);
116 ellipsize_error_message_buff();
117 fatalerror(error_message_buff);
120 extern void memory_out_error(int32 size, int32 howmany, char *name)
122 snprintf(error_message_buff, ERROR_BUFLEN,
123 "Run out of memory allocating %d bytes for %s", size, name);
125 snprintf(error_message_buff, ERROR_BUFLEN,
126 "Run out of memory allocating array of %dx%d bytes for %s",
127 howmany, size, name);
128 ellipsize_error_message_buff();
129 fatalerror(error_message_buff);
132 extern void memoryerror(char *s, int32 size)
134 snprintf(error_message_buff, ERROR_BUFLEN,
135 "The memory setting %s (which is %ld at present) has been \
136 exceeded. Try running Inform again with $%s=<some-larger-number> on the \
137 command line.",s,(long int) size,s);
138 ellipsize_error_message_buff();
139 fatalerror(error_message_buff);
142 /* ------------------------------------------------------------------------- */
143 /* Survivable diagnostics: */
144 /* compilation errors style 1 */
145 /* warnings style 2 */
146 /* linkage errors style 3 */
147 /* compiler errors style 4 (these should never happen and */
148 /* indicate a bug in Inform) */
149 /* ------------------------------------------------------------------------- */
151 static int errors[MAX_ERRORS];
153 int no_errors, no_warnings, no_suppressed_warnings, no_link_errors,
156 char *forerrors_buff;
157 int forerrors_pointer;
159 static void message(int style, char *s)
160 { int throw_style = style;
161 if (hash_printed_since_newline) printf("\n");
162 hash_printed_since_newline = FALSE;
165 { case 1: printf("Error: "); no_errors++; break;
166 case 2: printf("Warning: "); no_warnings++; break;
167 case 3: printf("Error: [linking '%s'] ", current_module_filename);
168 no_link_errors++; no_errors++; throw_style=1; break;
169 case 4: printf("*** Compiler error: ");
170 no_compiler_errors++; throw_style=1; break;
174 throwback(throw_style, s);
177 ProcessEvents (&g_proc);
181 my_free(&all_text,"transcription text");
183 if (temporary_files_switch) remove_temp_files();
184 abort_transcript_file();
185 longjmp (g_fallback, 1);
188 if ((!concise_switch) && (forerrors_pointer > 0) && (style <= 2))
189 { forerrors_buff[forerrors_pointer] = 0;
190 sprintf(forerrors_buff+68," ...etc");
191 printf("> %s\n",forerrors_buff);
195 /* ------------------------------------------------------------------------- */
196 /* Style 1: Error message routines */
197 /* ------------------------------------------------------------------------- */
199 extern void error(char *s)
200 { if (no_errors == MAX_ERRORS)
201 fatalerror("Too many errors: giving up");
202 errors[no_errors] = no_syntax_lines;
206 extern void error_named(char *s1, char *s2)
207 { snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
208 ellipsize_error_message_buff();
209 error(error_message_buff);
212 extern void error_numbered(char *s1, int val)
214 snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.",s1,val);
215 ellipsize_error_message_buff();
216 error(error_message_buff);
219 extern void error_named_at(char *s1, char *s2, int32 report_line)
222 ErrorPosition E = ErrorReport;
223 if (report_line != -1)
224 { ErrorReport.file_number = report_line/FILE_LINE_SCALE_FACTOR;
225 ErrorReport.line_number = report_line%FILE_LINE_SCALE_FACTOR;
226 ErrorReport.main_flag = (ErrorReport.file_number == 1);
229 snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
230 ellipsize_error_message_buff();
232 i = concise_switch; concise_switch = TRUE;
233 error(error_message_buff);
234 ErrorReport = E; concise_switch = i;
237 extern void no_such_label(char *lname)
238 { error_named("No such label as",lname);
241 extern void ebf_error(char *s1, char *s2)
242 { snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s1, s2);
243 ellipsize_error_message_buff();
244 error(error_message_buff);
247 extern void char_error(char *s, int ch)
250 uni = iso_to_unicode(ch);
252 if (character_set_unicode)
253 snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
254 else if (uni >= 0x100)
255 { snprintf(error_message_buff, ERROR_BUFLEN,
256 "%s (unicode) $%04x = (ISO %s) $%02x", s, uni,
257 name_of_iso_set(character_set_setting), ch);
260 snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
262 /* If the character set is set to Latin-1, and the char in question
263 is a printable Latin-1 character, we print it in the error message.
264 This conflates the source-text charset with the terminal charset,
265 really, but it's not a big deal. */
267 if (((uni>=32) && (uni<127))
268 || (((uni >= 0xa1) && (uni <= 0xff))
269 && (character_set_setting==1) && (!character_set_unicode)))
270 { int curlen = strlen(error_message_buff);
271 snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
272 ", i.e., '%c'", uni);
275 ellipsize_error_message_buff();
276 error(error_message_buff);
279 extern void unicode_char_error(char *s, int32 uni)
282 snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
284 snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
286 /* See comment above. */
288 if (((uni>=32) && (uni<127))
289 || (((uni >= 0xa1) && (uni <= 0xff))
290 && (character_set_setting==1) && (!character_set_unicode)))
291 { int curlen = strlen(error_message_buff);
292 snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
293 ", i.e., '%c'", uni);
296 ellipsize_error_message_buff();
297 error(error_message_buff);
300 /* ------------------------------------------------------------------------- */
301 /* Style 2: Warning message routines */
302 /* ------------------------------------------------------------------------- */
304 extern void warning(char *s1)
305 { if (nowarnings_switch) { no_suppressed_warnings++; return; }
309 extern void warning_numbered(char *s1, int val)
310 { if (nowarnings_switch) { no_suppressed_warnings++; return; }
311 snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.", s1, val);
312 ellipsize_error_message_buff();
313 message(2,error_message_buff);
316 extern void warning_named(char *s1, char *s2)
318 if (nowarnings_switch) { no_suppressed_warnings++; return; }
319 snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"", s1, s2);
320 ellipsize_error_message_buff();
321 message(2,error_message_buff);
324 extern void dbnu_warning(char *type, char *name, int32 report_line)
326 ErrorPosition E = ErrorReport;
327 if (nowarnings_switch) { no_suppressed_warnings++; return; }
328 if (report_line != -1)
329 { ErrorReport.file_number = report_line/FILE_LINE_SCALE_FACTOR;
330 ErrorReport.line_number = report_line%FILE_LINE_SCALE_FACTOR;
331 ErrorReport.main_flag = (ErrorReport.file_number == 1);
333 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" declared but not used", type, name);
334 ellipsize_error_message_buff();
335 i = concise_switch; concise_switch = TRUE;
336 message(2,error_message_buff);
341 extern void uncalled_routine_warning(char *type, char *name, int32 report_line)
343 /* This is called for functions which have been detected by the
344 track-unused-routines module. These will often (but not always)
345 be also caught by dbnu_warning(), which tracks symbols rather
346 than routine addresses. */
347 ErrorPosition E = ErrorReport;
348 if (nowarnings_switch) { no_suppressed_warnings++; return; }
349 if (report_line != -1)
350 { ErrorReport.file_number = report_line/FILE_LINE_SCALE_FACTOR;
351 ErrorReport.line_number = report_line%FILE_LINE_SCALE_FACTOR;
352 ErrorReport.main_flag = (ErrorReport.file_number == 1);
354 if (OMIT_UNUSED_ROUTINES)
355 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused and omitted", type, name);
357 snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused (not omitted)", type, name);
358 ellipsize_error_message_buff();
359 i = concise_switch; concise_switch = TRUE;
360 message(2,error_message_buff);
365 extern void obsolete_warning(char *s1)
366 { if (is_systemfile()==1) return;
367 if (obsolete_switch || nowarnings_switch)
368 { no_suppressed_warnings++; return; }
369 snprintf(error_message_buff, ERROR_BUFLEN, "Obsolete usage: %s",s1);
370 ellipsize_error_message_buff();
371 message(2,error_message_buff);
374 /* ------------------------------------------------------------------------- */
375 /* Style 3: Link error message routines */
376 /* ------------------------------------------------------------------------- */
378 extern void link_error(char *s)
379 { if (no_errors==MAX_ERRORS) fatalerror("Too many errors: giving up");
380 errors[no_errors] = no_syntax_lines;
384 extern void link_error_named(char *s1, char *s2)
385 { snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
386 ellipsize_error_message_buff();
387 link_error(error_message_buff);
390 /* ------------------------------------------------------------------------- */
391 /* Style 4: Compiler error message routines */
392 /* ------------------------------------------------------------------------- */
394 extern void print_sorry_message(void)
396 "***********************************************************************\n\
397 * 'Compiler errors' should never occur if Inform is working properly. *\n\
398 * This is version %d.%02d of Inform, dated %20s: so *\n\
399 * if that was more than six months ago, there may be a more recent *\n\
400 * version available, from which the problem may have been removed. *\n\
401 * If not, please report this fault to: graham@gnelson.demon.co.uk *\n\
402 * and if at all possible, please include your source code, as faults *\n\
403 * such as these are rare and often difficult to reproduce. Sorry. *\n\
404 ***********************************************************************\n",
405 (RELEASE_NUMBER/100)%10, RELEASE_NUMBER%100, RELEASE_DATE);
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;
491 extern void errors_allocate_arrays(void)
492 { forerrors_buff = my_malloc(512, "errors buffer");
495 extern void errors_free_arrays(void)
496 { my_free(&forerrors_buff, "errors buffer");
499 /* ========================================================================= */