--- /dev/null
+/* ------------------------------------------------------------------------- */
+/* "errors" : Warnings, errors and fatal errors */
+/* (with error throwback code for RISC OS machines) */
+/* */
+/* Copyright (c) Graham Nelson 1993 - 2018 */
+/* */
+/* This file is part of Inform. */
+/* */
+/* Inform is free software: you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation, either version 3 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Inform is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with Inform. If not, see https://gnu.org/licenses/ */
+/* */
+/* ------------------------------------------------------------------------- */
+
+#include "header.h"
+
+#define ERROR_BUFLEN (256)
+static char error_message_buff[ERROR_BUFLEN+4]; /* room for ellipsis */
+
+/* ------------------------------------------------------------------------- */
+/* Error preamble printing. */
+/* ------------------------------------------------------------------------- */
+
+ErrorPosition ErrorReport; /* Maintained by "lexer.c" */
+
+static void print_preamble(void)
+{
+ /* Only really prints the preamble to an error or warning message:
+
+ e.g. "jigsaw.apollo", line 24:
+
+ The format is controllable (from an ICL switch) since this assists
+ the working of some development environments. */
+
+ int j, with_extension_flag = FALSE; char *p;
+
+ j = ErrorReport.file_number;
+ if (j <= 0 || j > total_files) p = ErrorReport.source;
+ else p = InputFiles[j-1].filename;
+
+ if (!p) p = "";
+
+ switch(error_format)
+ {
+ case 0: /* RISC OS error message format */
+
+ if (!(ErrorReport.main_flag)) printf("\"%s\", ", p);
+ printf("line %d: ", ErrorReport.line_number);
+ if (ErrorReport.orig_file) {
+ char *op;
+ if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
+ op = ErrorReport.orig_source;
+ else
+ op = InputFiles[ErrorReport.orig_file-1].filename;
+ printf("(\"%s\"", op);
+ if (ErrorReport.orig_line) {
+ printf(", %d", ErrorReport.orig_line);
+ if (ErrorReport.orig_char) {
+ printf(":%d", ErrorReport.orig_char);
+ }
+ }
+ printf("): ");
+ }
+ break;
+
+ case 1: /* Microsoft error message format */
+
+ for (j=0; p[j]!=0; j++)
+ { if (p[j] == FN_SEP) with_extension_flag = TRUE;
+ if (p[j] == '.') with_extension_flag = FALSE;
+ }
+ printf("%s", p);
+ if (with_extension_flag) printf("%s", Source_Extension);
+ printf("(%d): ", ErrorReport.line_number);
+ break;
+
+ case 2: /* Macintosh Programmer's Workshop error message format */
+
+ printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number);
+ break;
+ }
+}
+
+static void ellipsize_error_message_buff(void)
+{
+ /* If the error buffer was actually filled up by a message, it was
+ probably truncated too. Add an ellipsis, for which we left
+ extra room. (Yes, yes; errors that are *exactly* 255 characters
+ long will suffer an unnecessary ellipsis.) */
+ if (strlen(error_message_buff) == ERROR_BUFLEN-1)
+ strcat(error_message_buff, "...");
+}
+
+/* ------------------------------------------------------------------------- */
+/* Fatal errors (which have style 0) */
+/* ------------------------------------------------------------------------- */
+
+extern void fatalerror(char *s)
+{ print_preamble();
+
+ printf("Fatal error: %s\n",s);
+ if (no_compiler_errors > 0) print_sorry_message();
+
+#ifdef ARC_THROWBACK
+ throwback(0, s);
+ throwback_end();
+#endif
+#ifdef MAC_FACE
+ close_all_source();
+ if (temporary_files_switch) remove_temp_files();
+ abort_transcript_file();
+ free_arrays();
+ if (store_the_text)
+ my_free(&all_text,"transcription text");
+ longjmp(g_fallback, 1);
+#endif
+ exit(1);
+}
+
+extern void fatalerror_named(char *m, char *fn)
+{ snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"", m, fn);
+ ellipsize_error_message_buff();
+ fatalerror(error_message_buff);
+}
+
+extern void memory_out_error(int32 size, int32 howmany, char *name)
+{ if (howmany == 1)
+ snprintf(error_message_buff, ERROR_BUFLEN,
+ "Run out of memory allocating %d bytes for %s", size, name);
+ else
+ snprintf(error_message_buff, ERROR_BUFLEN,
+ "Run out of memory allocating array of %dx%d bytes for %s",
+ howmany, size, name);
+ ellipsize_error_message_buff();
+ fatalerror(error_message_buff);
+}
+
+extern void memoryerror(char *s, int32 size)
+{
+ snprintf(error_message_buff, ERROR_BUFLEN,
+ "The memory setting %s (which is %ld at present) has been \
+exceeded. Try running Inform again with $%s=<some-larger-number> on the \
+command line.",s,(long int) size,s);
+ ellipsize_error_message_buff();
+ fatalerror(error_message_buff);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Survivable diagnostics: */
+/* compilation errors style 1 */
+/* warnings style 2 */
+/* linkage errors style 3 */
+/* compiler errors style 4 (these should never happen and */
+/* indicate a bug in Inform) */
+/* ------------------------------------------------------------------------- */
+
+static int errors[MAX_ERRORS];
+
+int no_errors, no_warnings, no_suppressed_warnings, no_link_errors,
+ no_compiler_errors;
+
+char *forerrors_buff;
+int forerrors_pointer;
+
+static void message(int style, char *s)
+{ int throw_style = style;
+ if (hash_printed_since_newline) printf("\n");
+ hash_printed_since_newline = FALSE;
+ print_preamble();
+ switch(style)
+ { case 1: printf("Error: "); no_errors++; break;
+ case 2: printf("Warning: "); no_warnings++; break;
+ case 3: printf("Error: [linking '%s'] ", current_module_filename);
+ no_link_errors++; no_errors++; throw_style=1; break;
+ case 4: printf("*** Compiler error: ");
+ no_compiler_errors++; throw_style=1; break;
+ }
+ printf(" %s\n", s);
+#ifdef ARC_THROWBACK
+ throwback(throw_style, s);
+#endif
+#ifdef MAC_FACE
+ ProcessEvents (&g_proc);
+ if (g_proc != true)
+ { free_arrays();
+ if (store_the_text)
+ my_free(&all_text,"transcription text");
+ close_all_source ();
+ if (temporary_files_switch) remove_temp_files();
+ abort_transcript_file();
+ longjmp (g_fallback, 1);
+ }
+#endif
+ if ((!concise_switch) && (forerrors_pointer > 0) && (style <= 2))
+ { forerrors_buff[forerrors_pointer] = 0;
+ sprintf(forerrors_buff+68," ...etc");
+ printf("> %s\n",forerrors_buff);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Style 1: Error message routines */
+/* ------------------------------------------------------------------------- */
+
+extern void error(char *s)
+{ if (no_errors == MAX_ERRORS)
+ fatalerror("Too many errors: giving up");
+ errors[no_errors] = no_syntax_lines;
+ message(1,s);
+}
+
+extern void error_named(char *s1, char *s2)
+{ snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
+ ellipsize_error_message_buff();
+ error(error_message_buff);
+}
+
+extern void error_numbered(char *s1, int val)
+{
+ snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.",s1,val);
+ ellipsize_error_message_buff();
+ error(error_message_buff);
+}
+
+extern void error_named_at(char *s1, char *s2, brief_location report_line)
+{ int i;
+
+ ErrorPosition E = ErrorReport;
+ export_brief_location(report_line, &ErrorReport);
+
+ snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
+ ellipsize_error_message_buff();
+
+ i = concise_switch; concise_switch = TRUE;
+ error(error_message_buff);
+ ErrorReport = E; concise_switch = i;
+}
+
+extern void no_such_label(char *lname)
+{ error_named("No such label as",lname);
+}
+
+extern void ebf_error(char *s1, char *s2)
+{ snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s1, s2);
+ ellipsize_error_message_buff();
+ error(error_message_buff);
+}
+
+extern void char_error(char *s, int ch)
+{ int32 uni;
+
+ uni = iso_to_unicode(ch);
+
+ if (character_set_unicode)
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
+ else if (uni >= 0x100)
+ { snprintf(error_message_buff, ERROR_BUFLEN,
+ "%s (unicode) $%04x = (ISO %s) $%02x", s, uni,
+ name_of_iso_set(character_set_setting), ch);
+ }
+ else
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
+
+ /* If the character set is set to Latin-1, and the char in question
+ is a printable Latin-1 character, we print it in the error message.
+ This conflates the source-text charset with the terminal charset,
+ really, but it's not a big deal. */
+
+ if (((uni>=32) && (uni<127))
+ || (((uni >= 0xa1) && (uni <= 0xff))
+ && (character_set_setting==1) && (!character_set_unicode)))
+ { int curlen = strlen(error_message_buff);
+ snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
+ ", i.e., '%c'", uni);
+ }
+
+ ellipsize_error_message_buff();
+ error(error_message_buff);
+}
+
+extern void unicode_char_error(char *s, int32 uni)
+{
+ if (uni >= 0x100)
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
+ else
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
+
+ /* See comment above. */
+
+ if (((uni>=32) && (uni<127))
+ || (((uni >= 0xa1) && (uni <= 0xff))
+ && (character_set_setting==1) && (!character_set_unicode)))
+ { int curlen = strlen(error_message_buff);
+ snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
+ ", i.e., '%c'", uni);
+ }
+
+ ellipsize_error_message_buff();
+ error(error_message_buff);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Style 2: Warning message routines */
+/* ------------------------------------------------------------------------- */
+
+extern void warning(char *s1)
+{ if (nowarnings_switch) { no_suppressed_warnings++; return; }
+ message(2,s1);
+}
+
+extern void warning_numbered(char *s1, int val)
+{ if (nowarnings_switch) { no_suppressed_warnings++; return; }
+ snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.", s1, val);
+ ellipsize_error_message_buff();
+ message(2,error_message_buff);
+}
+
+extern void warning_named(char *s1, char *s2)
+{
+ if (nowarnings_switch) { no_suppressed_warnings++; return; }
+ snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"", s1, s2);
+ ellipsize_error_message_buff();
+ message(2,error_message_buff);
+}
+
+extern void dbnu_warning(char *type, char *name, brief_location report_line)
+{ int i;
+ ErrorPosition E = ErrorReport;
+ if (nowarnings_switch) { no_suppressed_warnings++; return; }
+ export_brief_location(report_line, &ErrorReport);
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" declared but not used", type, name);
+ ellipsize_error_message_buff();
+ i = concise_switch; concise_switch = TRUE;
+ message(2,error_message_buff);
+ concise_switch = i;
+ ErrorReport = E;
+}
+
+extern void uncalled_routine_warning(char *type, char *name, brief_location report_line)
+{ int i;
+ /* This is called for functions which have been detected by the
+ track-unused-routines module. These will often (but not always)
+ be also caught by dbnu_warning(), which tracks symbols rather
+ than routine addresses. */
+ ErrorPosition E = ErrorReport;
+ if (nowarnings_switch) { no_suppressed_warnings++; return; }
+ export_brief_location(report_line, &ErrorReport);
+ if (OMIT_UNUSED_ROUTINES)
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused and omitted", type, name);
+ else
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused (not omitted)", type, name);
+ ellipsize_error_message_buff();
+ i = concise_switch; concise_switch = TRUE;
+ message(2,error_message_buff);
+ concise_switch = i;
+ ErrorReport = E;
+}
+
+extern void obsolete_warning(char *s1)
+{ if (is_systemfile()==1) return;
+ if (obsolete_switch || nowarnings_switch)
+ { no_suppressed_warnings++; return; }
+ snprintf(error_message_buff, ERROR_BUFLEN, "Obsolete usage: %s",s1);
+ ellipsize_error_message_buff();
+ message(2,error_message_buff);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Style 3: Link error message routines */
+/* ------------------------------------------------------------------------- */
+
+extern void link_error(char *s)
+{ if (no_errors==MAX_ERRORS) fatalerror("Too many errors: giving up");
+ errors[no_errors] = no_syntax_lines;
+ message(3,s);
+}
+
+extern void link_error_named(char *s1, char *s2)
+{ snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
+ ellipsize_error_message_buff();
+ link_error(error_message_buff);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Style 4: Compiler error message routines */
+/* ------------------------------------------------------------------------- */
+
+extern void print_sorry_message(void)
+{ printf(
+"***********************************************************************\n\
+* 'Compiler errors' should never occur if Inform is working properly. *\n\
+* This is version %d.%02d of Inform, dated %20s: so *\n\
+* if that was more than six months ago, there may be a more recent *\n\
+* version available, from which the problem may have been removed. *\n\
+* If not, please report this fault to: graham@gnelson.demon.co.uk *\n\
+* and if at all possible, please include your source code, as faults *\n\
+* such as these are rare and often difficult to reproduce. Sorry. *\n\
+***********************************************************************\n",
+ (RELEASE_NUMBER/100)%10, RELEASE_NUMBER%100, RELEASE_DATE);
+}
+
+extern int compiler_error(char *s)
+{ if (no_link_errors > 0) return FALSE;
+ if (no_errors > 0) return FALSE;
+ if (no_compiler_errors==MAX_ERRORS)
+ fatalerror("Too many compiler errors: giving up");
+ message(4,s);
+ return TRUE;
+}
+
+extern int compiler_error_named(char *s1, char *s2)
+{ if (no_link_errors > 0) return FALSE;
+ if (no_errors > 0) return FALSE;
+ snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"",s1,s2);
+ ellipsize_error_message_buff();
+ compiler_error(error_message_buff);
+ return TRUE;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Code for the Acorn RISC OS operating system, donated by Robin Watts, */
+/* to provide error throwback under the DDE environment */
+/* ------------------------------------------------------------------------- */
+
+#ifdef ARC_THROWBACK
+
+#define DDEUtils_ThrowbackStart 0x42587
+#define DDEUtils_ThrowbackSend 0x42588
+#define DDEUtils_ThrowbackEnd 0x42589
+
+#include "kernel.h"
+
+extern void throwback_start(void)
+{ _kernel_swi_regs regs;
+ if (throwback_switch)
+ _kernel_swi(DDEUtils_ThrowbackStart, ®s, ®s);
+}
+
+extern void throwback_end(void)
+{ _kernel_swi_regs regs;
+ if (throwback_switch)
+ _kernel_swi(DDEUtils_ThrowbackEnd, ®s, ®s);
+}
+
+int throwback_started = FALSE;
+
+extern void throwback(int severity, char * error)
+{ _kernel_swi_regs regs;
+ if (!throwback_started)
+ { throwback_started = TRUE;
+ throwback_start();
+ }
+ if (throwback_switch)
+ { regs.r[0] = 1;
+ if ((ErrorReport.file_number == -1)
+ || (ErrorReport.file_number == 0))
+ regs.r[2] = (int) (InputFiles[0].filename);
+ else regs.r[2] = (int) (InputFiles[ErrorReport.file_number-1].filename);
+ regs.r[3] = ErrorReport.line_number;
+ regs.r[4] = (2-severity);
+ regs.r[5] = (int) error;
+ _kernel_swi(DDEUtils_ThrowbackSend, ®s, ®s);
+ }
+}
+
+#endif
+
+/* ========================================================================= */
+/* Data structure management routines */
+/* ------------------------------------------------------------------------- */
+
+extern void init_errors_vars(void)
+{ forerrors_buff = NULL;
+ no_errors = 0; no_warnings = 0; no_suppressed_warnings = 0;
+ no_compiler_errors = 0;
+}
+
+extern void errors_begin_pass(void)
+{ ErrorReport.line_number = 0;
+ ErrorReport.file_number = -1;
+ ErrorReport.source = "<no text read yet>";
+ ErrorReport.main_flag = FALSE;
+ ErrorReport.orig_source = NULL;
+ ErrorReport.orig_file = 0;
+ ErrorReport.orig_line = 0;
+ ErrorReport.orig_char = 0;
+}
+
+extern void errors_allocate_arrays(void)
+{ forerrors_buff = my_malloc(512, "errors buffer");
+}
+
+extern void errors_free_arrays(void)
+{ my_free(&forerrors_buff, "errors buffer");
+}
+
+/* ========================================================================= */