3d4a866bdde19bc34bd6ef82bc80ca84e37599a0
[inform.git] / errors.c
1 /* ------------------------------------------------------------------------- */
2 /*   "errors" : Warnings, errors and fatal errors                            */
3 /*              (with error throwback code for RISC OS machines)             */
4 /*                                                                           */
5 /* Copyright (c) Graham Nelson 1993 - 2016                                   */
6 /*                                                                           */
7 /* This file is part of Inform.                                              */
8 /*                                                                           */
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.                                       */
13 /*                                                                           */
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.                              */
18 /*                                                                           */
19 /* You should have received a copy of the GNU General Public License         */
20 /* along with Inform. If not, see https://gnu.org/licenses/                  */
21 /*                                                                           */
22 /* ------------------------------------------------------------------------- */
23
24 #include "header.h"
25
26 #define ERROR_BUFLEN (256)
27 static char error_message_buff[ERROR_BUFLEN+4]; /* room for ellipsis */
28
29 /* ------------------------------------------------------------------------- */
30 /*   Error preamble printing.                                                */
31 /* ------------------------------------------------------------------------- */
32
33 ErrorPosition ErrorReport;             /*  Maintained by "lexer.c"           */
34
35 static void print_preamble(void)
36 {
37     /*  Only really prints the preamble to an error or warning message:
38
39         e.g.  "jigsaw.apollo", line 24:
40
41         The format is controllable (from an ICL switch) since this assists
42         the working of some development environments.                        */
43
44     int j, with_extension_flag = FALSE; char *p;
45
46     j = ErrorReport.file_number;
47     if (j <= 0 || j > input_file) p = ErrorReport.source;
48     else p = InputFiles[j-1].filename;
49
50     if (!p) p = "";
51     
52     switch(error_format)
53     {
54         case 0:  /* RISC OS error message format */
55
56             if (!(ErrorReport.main_flag)) printf("\"%s\", ", p);
57             printf("line %d: ", ErrorReport.line_number);
58             break;
59
60         case 1:  /* Microsoft error message format */
61
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;
65             }
66             printf("%s", p);
67             if (with_extension_flag) printf("%s", Source_Extension);
68             printf("(%d): ", ErrorReport.line_number);
69             break;
70
71         case 2:  /* Macintosh Programmer's Workshop error message format */
72
73             printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number);
74             break;
75     }
76 }
77
78 static void ellipsize_error_message_buff(void)
79 {
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, "...");
86 }
87
88 /* ------------------------------------------------------------------------- */
89 /*   Fatal errors (which have style 0)                                       */
90 /* ------------------------------------------------------------------------- */
91
92 extern void fatalerror(char *s)
93 {   print_preamble();
94
95     printf("Fatal error: %s\n",s);
96     if (no_compiler_errors > 0) print_sorry_message();
97
98 #ifdef ARC_THROWBACK
99     throwback(0, s);
100     throwback_end();
101 #endif
102 #ifdef MAC_FACE
103     close_all_source();
104     if (temporary_files_switch) remove_temp_files();
105     abort_transcript_file();
106     free_arrays();
107     if (store_the_text)
108         my_free(&all_text,"transcription text");
109     longjmp(g_fallback, 1);
110 #endif
111     exit(1);
112 }
113
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);
118 }
119
120 extern void memory_out_error(int32 size, int32 howmany, char *name)
121 {   if (howmany == 1)
122         snprintf(error_message_buff, ERROR_BUFLEN,
123             "Run out of memory allocating %d bytes for %s", size, name);
124     else
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);
130 }
131
132 extern void memoryerror(char *s, int32 size)
133 {
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);
140 }
141
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 /* ------------------------------------------------------------------------- */
150
151 static int errors[MAX_ERRORS];
152
153 int no_errors, no_warnings, no_suppressed_warnings, no_link_errors,
154     no_compiler_errors;
155
156 char *forerrors_buff;
157 int  forerrors_pointer;
158
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;
163     print_preamble();
164     switch(style)
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;
171     }
172     printf(" %s\n", s);
173 #ifdef ARC_THROWBACK
174     throwback(throw_style, s);
175 #endif
176 #ifdef MAC_FACE
177     ProcessEvents (&g_proc);
178     if (g_proc != true)
179     {   free_arrays();
180         if (store_the_text)
181             my_free(&all_text,"transcription text");
182         close_all_source ();
183         if (temporary_files_switch) remove_temp_files();
184         abort_transcript_file();
185         longjmp (g_fallback, 1);
186     }
187 #endif
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);
192     }
193 }
194
195 /* ------------------------------------------------------------------------- */
196 /*   Style 1: Error message routines                                         */
197 /* ------------------------------------------------------------------------- */
198
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;
203     message(1,s);
204 }
205
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);
210 }
211
212 extern void error_numbered(char *s1, int val)
213 {
214     snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.",s1,val);
215     ellipsize_error_message_buff();
216     error(error_message_buff);
217 }
218
219 extern void error_named_at(char *s1, char *s2, int32 report_line)
220 {   int i;
221
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);
227     }
228
229     snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
230     ellipsize_error_message_buff();
231
232     i = concise_switch; concise_switch = TRUE;
233     error(error_message_buff);
234     ErrorReport = E; concise_switch = i;
235 }
236
237 extern void no_such_label(char *lname)
238 {   error_named("No such label as",lname);
239 }
240
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);
245 }
246
247 extern void char_error(char *s, int ch)
248 {   int32 uni;
249
250     uni = iso_to_unicode(ch);
251
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);
258     }
259     else
260         snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
261
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. */
266
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);
273     }
274
275     ellipsize_error_message_buff();
276     error(error_message_buff);
277 }
278
279 extern void unicode_char_error(char *s, int32 uni)
280 {
281     if (uni >= 0x100)
282         snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
283     else
284         snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
285
286     /* See comment above. */
287
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);
294     }
295
296     ellipsize_error_message_buff();
297     error(error_message_buff);
298 }
299
300 /* ------------------------------------------------------------------------- */
301 /*   Style 2: Warning message routines                                       */
302 /* ------------------------------------------------------------------------- */
303
304 extern void warning(char *s1)
305 {   if (nowarnings_switch) { no_suppressed_warnings++; return; }
306     message(2,s1);
307 }
308
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);
314 }
315
316 extern void warning_named(char *s1, char *s2)
317 {
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);
322 }
323
324 extern void dbnu_warning(char *type, char *name, int32 report_line)
325 {   int i;
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);
332     }
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);
337     concise_switch = i;
338     ErrorReport = E;
339 }
340
341 extern void uncalled_routine_warning(char *type, char *name, int32 report_line)
342 {   int i;
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);
353     }
354     if (OMIT_UNUSED_ROUTINES)
355         snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused and omitted", type, name);
356     else
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);
361     concise_switch = i;
362     ErrorReport = E;
363 }
364
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);
372 }
373
374 /* ------------------------------------------------------------------------- */
375 /*   Style 3: Link error message routines                                    */
376 /* ------------------------------------------------------------------------- */
377
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;
381     message(3,s);
382 }
383
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);
388 }
389
390 /* ------------------------------------------------------------------------- */
391 /*   Style 4: Compiler error message routines                                */
392 /* ------------------------------------------------------------------------- */
393
394 extern void print_sorry_message(void)
395 {   printf(
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);
406 }
407
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");
413     message(4,s);
414     return TRUE;
415 }
416
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);
423     return TRUE;
424 }
425
426 /* ------------------------------------------------------------------------- */
427 /*   Code for the Acorn RISC OS operating system, donated by Robin Watts,    */
428 /*   to provide error throwback under the DDE environment                    */
429 /* ------------------------------------------------------------------------- */
430
431 #ifdef ARC_THROWBACK
432
433 #define DDEUtils_ThrowbackStart 0x42587
434 #define DDEUtils_ThrowbackSend  0x42588
435 #define DDEUtils_ThrowbackEnd   0x42589
436
437 #include "kernel.h"
438
439 extern void throwback_start(void)
440 {    _kernel_swi_regs regs;
441      if (throwback_switch)
442          _kernel_swi(DDEUtils_ThrowbackStart, &regs, &regs);
443 }
444
445 extern void throwback_end(void)
446 {   _kernel_swi_regs regs;
447     if (throwback_switch)
448         _kernel_swi(DDEUtils_ThrowbackEnd, &regs, &regs);
449 }
450
451 int throwback_started = FALSE;
452
453 extern void throwback(int severity, char * error)
454 {   _kernel_swi_regs regs;
455     if (!throwback_started)
456     {   throwback_started = TRUE;
457         throwback_start();
458     }
459     if (throwback_switch)
460     {   regs.r[0] = 1;
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, &regs, &regs);
469     }
470 }
471
472 #endif
473
474 /* ========================================================================= */
475 /*   Data structure management routines                                      */
476 /* ------------------------------------------------------------------------- */
477
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;
482 }
483
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 }
490
491 extern void errors_allocate_arrays(void)
492 {   forerrors_buff = my_malloc(512, "errors buffer");
493 }
494
495 extern void errors_free_arrays(void)
496 {   my_free(&forerrors_buff, "errors buffer");
497 }
498
499 /* ========================================================================= */