Update to Inform v6.42
[inform.git] / src / errors.c
1 /* ------------------------------------------------------------------------- */
2 /*   "errors" : Warnings, errors and fatal errors                            */
3 /*              (with error throwback code for RISC OS machines)             */
4 /*                                                                           */
5 /*   Part of Inform 6.42                                                     */
6 /*   copyright (c) Graham Nelson 1993 - 2024                                 */
7 /*                                                                           */
8 /* Inform is free software: you can redistribute it and/or modify            */
9 /* it under the terms of the GNU General Public License as published by      */
10 /* the Free Software Foundation, either version 3 of the License, or         */
11 /* (at your option) any later version.                                       */
12 /*                                                                           */
13 /* Inform is distributed in the hope that it will be useful,                 */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
16 /* GNU General Public License for more details.                              */
17 /*                                                                           */
18 /* You should have received a copy of the GNU General Public License         */
19 /* along with Inform. If not, see https://gnu.org/licenses/                  */
20 /*                                                                           */
21 /* ------------------------------------------------------------------------- */
22
23 #include "header.h"
24
25 #define ERROR_BUFLEN (256)
26 static char error_message_buff[ERROR_BUFLEN+4]; /* room for ellipsis */
27
28 /* ------------------------------------------------------------------------- */
29 /*   Error preamble printing.                                                */
30 /* ------------------------------------------------------------------------- */
31
32 ErrorPosition ErrorReport;             /*  Maintained by "lexer.c"           */
33
34 static char other_pos_buff[ERROR_BUFLEN+1];       /* Used by location_text() */
35
36 static void print_preamble(void)
37 {
38     /*  Only really prints the preamble to an error or warning message:
39
40         e.g.  "jigsaw.apollo", line 24:
41
42         The format is controllable (from an ICL switch) since this assists
43         the working of some development environments.                        */
44
45     int j, with_extension_flag = FALSE; char *p;
46
47     j = ErrorReport.file_number;
48     if (j <= 0 || j > total_files) p = ErrorReport.source;
49     else p = InputFiles[j-1].filename;
50
51     if (!p) p = "";
52     
53     switch(error_format)
54     {
55         case 0:  /* RISC OS error message format */
56
57             if (!(ErrorReport.main_flag)) printf("\"%s\", ", p);
58             printf("line %d: ", ErrorReport.line_number);
59             
60             if (ErrorReport.orig_file) {
61                 char *op;
62                 if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
63                     op = ErrorReport.orig_source;
64                 else
65                     op = InputFiles[ErrorReport.orig_file-1].filename;
66                 printf("(\"%s\"", op);
67                 if (ErrorReport.orig_line) {
68                     printf(", %d", ErrorReport.orig_line);
69                     if (ErrorReport.orig_char) {
70                         printf(":%d", ErrorReport.orig_char);
71                     }
72                 }
73                 printf("): ");
74             }
75             break;
76
77         case 1:  /* Microsoft error message format */
78
79             for (j=0; p[j]!=0; j++)
80             {   if (p[j] == FN_SEP) with_extension_flag = TRUE;
81                 if (p[j] == '.') with_extension_flag = FALSE;
82             }
83             printf("%s", p);
84             if (with_extension_flag) printf("%s", Source_Extension);
85             printf("(%d)", ErrorReport.line_number);
86             
87             if (ErrorReport.orig_file) {
88                 char *op;
89                 if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
90                     op = ErrorReport.orig_source;
91                 else
92                     op = InputFiles[ErrorReport.orig_file-1].filename;
93                 printf("|%s", op);
94                 if (ErrorReport.orig_line) {
95                     printf("(%d", ErrorReport.orig_line);
96                     if (ErrorReport.orig_char) {
97                         printf(":%d", ErrorReport.orig_char);
98                     }
99                     printf(")");
100                 }
101             }
102             
103             printf(": ");
104             break;
105
106         case 2:  /* Macintosh Programmer's Workshop error message format */
107
108             printf("File \"%s\"; Line %d", p, ErrorReport.line_number);
109             
110             if (ErrorReport.orig_file) {
111                 char *op;
112                 if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
113                     op = ErrorReport.orig_source;
114                 else
115                     op = InputFiles[ErrorReport.orig_file-1].filename;
116                 printf(": (\"%s\"", op);
117                 if (ErrorReport.orig_line) {
118                     printf("; Line %d", ErrorReport.orig_line);
119                     if (ErrorReport.orig_char) {
120                         printf("; Char %d", ErrorReport.orig_char);
121                     }
122                 }
123                 printf(")");
124             }
125
126             printf("\t# ");
127             break;
128     }
129 }
130
131 static char *location_text(brief_location report_line)
132 {
133     int j;
134     char *p;
135     int len;
136
137     /* Convert the location to a brief string. 
138        (Some error messages need to report a secondary location.)
139        This uses the static buffer other_pos_buff. */
140     
141     ErrorPosition errpos;
142     errpos.file_number = -1;
143     errpos.source = NULL;
144     errpos.line_number = 0;
145     errpos.main_flag = 0;
146     errpos.orig_source = NULL;
147     export_brief_location(report_line, &errpos);
148     
149     j = errpos.file_number;
150     if (j <= 0 || j > total_files) p = errpos.source;
151     else p = InputFiles[j-1].filename;
152     
153     if (!p && errpos.line_number == 0) {
154         /* Special case */
155         strcpy(other_pos_buff, "compiler setup");
156         return other_pos_buff;
157     }
158     
159     if (!p) p = "";
160
161     len = 0;
162     
163     if (!(errpos.main_flag)) {
164         snprintf(other_pos_buff+len, ERROR_BUFLEN-len,
165                  "\"%s\", ", p);
166         len = strlen(other_pos_buff);
167     }
168     snprintf(other_pos_buff+len, ERROR_BUFLEN-len,
169              "line %d", errpos.line_number);
170
171     return other_pos_buff;
172 }
173
174 char *current_location_text(void)
175 {
176     /* Convert the current lexer location to a brief string.
177        (Called by some trace messages.)
178        This uses the static buffer other_pos_buff. */
179     return location_text(get_brief_location(&ErrorReport));
180 }
181
182 static void ellipsize_error_message_buff(void)
183 {
184     /* If the error buffer was actually filled up by a message, it was
185        probably truncated too. Add an ellipsis, for which we left
186        extra room. (Yes, yes; errors that are *exactly* 255 characters
187        long will suffer an unnecessary ellipsis.) */
188     if (strlen(error_message_buff) == ERROR_BUFLEN-1)
189         strcat(error_message_buff, "...");
190 }
191
192 /* ------------------------------------------------------------------------- */
193 /*   Fatal errors (which have style 0)                                       */
194 /* ------------------------------------------------------------------------- */
195
196 extern void fatalerror(char *s)
197 {   print_preamble();
198
199     printf("Fatal error: %s\n",s);
200     if (no_compiler_errors > 0) print_sorry_message();
201
202 #ifdef ARC_THROWBACK
203     throwback(0, s);
204     throwback_end();
205 #endif
206 #ifdef MAC_FACE
207     close_all_source();
208     abort_transcript_file();
209     free_arrays();
210     longjmp(g_fallback, 1);
211 #endif
212     exit(1);
213 }
214
215 extern void fatalerror_fmt(const char *format, ...)
216 {
217     va_list argument_pointer;
218     va_start(argument_pointer, format);
219     vsnprintf(error_message_buff, ERROR_BUFLEN, format, argument_pointer);
220     va_end(argument_pointer);
221     ellipsize_error_message_buff();
222     fatalerror(error_message_buff);
223 }
224
225 extern void fatalerror_named(char *m, char *fn)
226 {   snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"", m, fn);
227     ellipsize_error_message_buff();
228     fatalerror(error_message_buff);
229 }
230
231 extern void fatalerror_memory_out(int32 size, int32 howmany, char *name)
232 {   if (howmany == 1)
233         snprintf(error_message_buff, ERROR_BUFLEN,
234             "Run out of memory allocating %d bytes for %s", size, name);
235     else
236         snprintf(error_message_buff, ERROR_BUFLEN,
237             "Run out of memory allocating array of %dx%d bytes for %s",
238                 howmany, size, name);
239     ellipsize_error_message_buff();
240     fatalerror(error_message_buff);
241 }
242
243 /* ------------------------------------------------------------------------- */
244 /*   Survivable diagnostics:                                                 */
245 /*      compilation errors   style 1                                         */
246 /*      warnings             style 2                                         */
247 /*      linkage errors       style 3 (no longer used)                        */
248 /*      compiler errors      style 4 (these should never happen and          */
249 /*                                    indicate a bug in Inform)              */
250 /* ------------------------------------------------------------------------- */
251
252 int no_errors, no_warnings, no_suppressed_warnings, no_compiler_errors;
253
254 char *forerrors_buff;
255 int  forerrors_pointer;
256
257 static void message(int style, char *s)
258 {
259     if (hash_printed_since_newline) printf("\n");
260     hash_printed_since_newline = FALSE;
261     print_preamble();
262     switch(style)
263     {   case 1: printf("Error: "); no_errors++; break;
264         case 2: printf("Warning: "); no_warnings++; break;
265         case 3: printf("Error:  [linking]  "); no_errors++; break;
266         case 4: printf("*** Compiler error: ");
267                 no_compiler_errors++; break;
268     }
269     printf(" %s\n", s);
270 #ifdef ARC_THROWBACK
271     throwback(((style <= 2) ? style : 1), s);
272 #endif
273 #ifdef MAC_FACE
274     ProcessEvents (&g_proc);
275     if (g_proc != true)
276     {   free_arrays();
277         close_all_source ();
278         abort_transcript_file();
279         longjmp (g_fallback, 1);
280     }
281 #endif
282     if ((!concise_switch) && (forerrors_pointer > 0) && (style <= 2))
283     {   forerrors_buff[forerrors_pointer] = 0;
284         sprintf(forerrors_buff+68,"  ...etc");
285         printf("> %s\n",forerrors_buff);
286     }
287 }
288
289 /* ------------------------------------------------------------------------- */
290 /*   Style 1: Error message routines                                         */
291 /* ------------------------------------------------------------------------- */
292
293 extern void error(char *s)
294 {   if (no_errors == MAX_ERRORS)
295         fatalerror("Too many errors: giving up");
296     message(1,s);
297 }
298
299 extern void error_fmt(const char *format, ...)
300 {
301     va_list argument_pointer;
302     va_start(argument_pointer, format);
303     vsnprintf(error_message_buff, ERROR_BUFLEN, format, argument_pointer);
304     va_end(argument_pointer);
305     ellipsize_error_message_buff();
306     error(error_message_buff);
307 }
308
309 extern void error_named(char *s1, char *s2)
310 {   snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
311     ellipsize_error_message_buff();
312     error(error_message_buff);
313 }
314
315 extern void error_named_at(char *s1, char *s2, brief_location report_line)
316 {   int i;
317
318     ErrorPosition E = ErrorReport;
319     export_brief_location(report_line, &ErrorReport);
320
321     snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
322     ellipsize_error_message_buff();
323
324     i = concise_switch; concise_switch = TRUE;
325     error(error_message_buff);
326     ErrorReport = E; concise_switch = i;
327 }
328
329 extern void ebf_error(char *s1, char *s2)
330 {   snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s1, s2);
331     ellipsize_error_message_buff();
332     error(error_message_buff);
333 }
334
335 extern void ebf_curtoken_error(char *s)
336 {
337     /* This is "Expected (s) but found (the current token_text)". We use
338        token_type as a hint for how to display token_text. */
339     
340     if (token_type == DQ_TT) {
341         snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found string \"%s\"", s, token_text);
342     }
343     else if (token_type == SQ_TT && strlen(token_text)==1) {
344         snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found char '%s'", s, token_text);
345     }
346     else if (token_type == SQ_TT) {
347         snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found dict word '%s'", s, token_text);
348     }
349     else {
350         /* Symbols, unquoted strings, and numbers can be printed directly. EOF will have "<end of file>" in token_text. */
351         snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s, token_text);
352     }
353     
354     ellipsize_error_message_buff();
355     error(error_message_buff);
356 }
357
358 extern void ebf_symbol_error(char *s1, char *name, char *type, brief_location report_line)
359 {   snprintf(error_message_buff, ERROR_BUFLEN, "\"%s\" is a name already in use and may not be used as a %s (%s \"%s\" was defined at %s)", name, s1, type, name, location_text(report_line));
360     ellipsize_error_message_buff();
361     error(error_message_buff);
362 }
363
364 extern void char_error(char *s, int ch)
365 {   int32 uni;
366
367     uni = iso_to_unicode(ch);
368
369     if (character_set_unicode)
370         snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
371     else if (uni >= 0x100)
372     {   snprintf(error_message_buff, ERROR_BUFLEN,
373             "%s (unicode) $%04x = (ISO %s) $%02x", s, uni,
374             name_of_iso_set(character_set_setting), ch);
375     }
376     else
377         snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
378
379     /* If the character set is set to Latin-1, and the char in question
380        is a printable Latin-1 character, we print it in the error message.
381        This conflates the source-text charset with the terminal charset,
382        really, but it's not a big deal. */
383
384     if (((uni>=32) && (uni<127))
385         || (((uni >= 0xa1) && (uni <= 0xff))
386         && (character_set_setting==1) && (!character_set_unicode))) 
387     {   int curlen = strlen(error_message_buff);
388         snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
389             ", i.e., '%c'", uni);
390     }
391
392     ellipsize_error_message_buff();
393     error(error_message_buff);
394 }
395
396 extern void unicode_char_error(char *s, int32 uni)
397 {
398     if (uni >= 0x100)
399         snprintf(error_message_buff, ERROR_BUFLEN, "%s (unicode) $%04x", s, uni);
400     else
401         snprintf(error_message_buff, ERROR_BUFLEN, "%s (ISO Latin1) $%02x", s, uni);
402
403     /* See comment above. */
404
405     if (((uni>=32) && (uni<127))
406         || (((uni >= 0xa1) && (uni <= 0xff))
407         && (character_set_setting==1) && (!character_set_unicode)))
408     {   int curlen = strlen(error_message_buff);
409         snprintf(error_message_buff+curlen, ERROR_BUFLEN-curlen,
410             ", i.e., '%c'", uni);
411     }
412
413     ellipsize_error_message_buff();
414     error(error_message_buff);
415 }
416
417 extern void error_max_dynamic_strings(int index)
418 {
419     if (index >= 96 && !glulx_mode)
420         snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(95) may be used in Z-code");
421     else if (MAX_DYNAMIC_STRINGS == 0)
422         snprintf(error_message_buff, ERROR_BUFLEN, "Dynamic strings may not be used, because $MAX_DYNAMIC_STRINGS has been set to 0. Increase MAX_DYNAMIC_STRINGS.");
423     else if (MAX_DYNAMIC_STRINGS == 32 && !glulx_mode)
424         snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(%02d) may be used, because $MAX_DYNAMIC_STRINGS has its default value of %d. Increase MAX_DYNAMIC_STRINGS.", MAX_DYNAMIC_STRINGS-1, MAX_DYNAMIC_STRINGS);
425     else
426         snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(%02d) may be used, because $MAX_DYNAMIC_STRINGS has been set to %d. Increase MAX_DYNAMIC_STRINGS.", MAX_DYNAMIC_STRINGS-1, MAX_DYNAMIC_STRINGS);
427
428     ellipsize_error_message_buff();
429     error(error_message_buff);
430 }
431
432 extern void error_max_abbreviations(int index)
433 {
434     /* This is only called for Z-code. */
435     if (index >= 96)
436         error("The number of abbreviations has exceeded 96, the limit in Z-code");
437     else
438         error("The number of abbreviations has exceeded MAX_ABBREVS. Increase MAX_ABBREVS.");
439 }
440
441 /* ------------------------------------------------------------------------- */
442 /*   Style 2: Warning message routines                                       */
443 /* ------------------------------------------------------------------------- */
444
445 extern void warning(char *s1)
446 {   if (nowarnings_switch) { no_suppressed_warnings++; return; }
447     message(2,s1);
448 }
449
450 extern void warning_fmt(const char *format, ...)
451 {
452     va_list argument_pointer;
453     if (nowarnings_switch) { no_suppressed_warnings++; return; }
454     va_start(argument_pointer, format);
455     vsnprintf(error_message_buff, ERROR_BUFLEN, format, argument_pointer);
456     va_end(argument_pointer);
457     ellipsize_error_message_buff();
458     message(2,error_message_buff);
459 }
460
461 extern void warning_named(char *s1, char *s2)
462 {
463     if (nowarnings_switch) { no_suppressed_warnings++; return; }
464     snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"", s1, s2);
465     ellipsize_error_message_buff();
466     message(2,error_message_buff);
467 }
468
469 extern void warning_at(char *name, brief_location report_line)
470 {   int i;
471     ErrorPosition E = ErrorReport;
472     if (nowarnings_switch) { no_suppressed_warnings++; return; }
473     export_brief_location(report_line, &ErrorReport);
474     snprintf(error_message_buff, ERROR_BUFLEN, "%s", name);
475     ellipsize_error_message_buff();
476     i = concise_switch; concise_switch = TRUE;
477     message(2,error_message_buff);
478     concise_switch = i;
479     ErrorReport = E;
480 }
481
482 extern void symtype_warning(char *context, char *name, char *type, char *wanttype)
483 {
484     if (nowarnings_switch) { no_suppressed_warnings++; return; }
485     if (name)
486         snprintf(error_message_buff, ERROR_BUFLEN, "In %s, expected %s but found %s \"%s\"", context, wanttype, type, name);
487     else
488         snprintf(error_message_buff, ERROR_BUFLEN, "In %s, expected %s but found %s", context, wanttype, type);
489     ellipsize_error_message_buff();
490     message(2,error_message_buff);
491 }
492
493 extern void dbnu_warning(char *type, char *name, brief_location report_line)
494 {   int i;
495     ErrorPosition E = ErrorReport;
496     if (nowarnings_switch) { no_suppressed_warnings++; return; }
497     export_brief_location(report_line, &ErrorReport);
498     snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" declared but not used", type, name);
499     ellipsize_error_message_buff();
500     i = concise_switch; concise_switch = TRUE;
501     message(2,error_message_buff);
502     concise_switch = i;
503     ErrorReport = E;
504 }
505
506 extern void uncalled_routine_warning(char *type, char *name, brief_location report_line)
507 {   int i;
508     /* This is called for functions which have been detected by the
509        track-unused-routines module. These will often (but not always)
510        be also caught by dbnu_warning(), which tracks symbols rather
511        than routine addresses. */
512     ErrorPosition E = ErrorReport;
513     if (nowarnings_switch) { no_suppressed_warnings++; return; }
514     export_brief_location(report_line, &ErrorReport);
515     if (OMIT_UNUSED_ROUTINES)
516         snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused and omitted", type, name);
517     else
518         snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\" unused (not omitted)", type, name);
519     ellipsize_error_message_buff();
520     i = concise_switch; concise_switch = TRUE;
521     message(2,error_message_buff);
522     concise_switch = i;
523     ErrorReport = E;
524 }
525
526 extern void obsolete_warning(char *s1)
527 {   if (is_systemfile()==1) return;
528     if (obsolete_switch || nowarnings_switch)
529     {   no_suppressed_warnings++; return; }
530     snprintf(error_message_buff, ERROR_BUFLEN, "Obsolete usage: %s",s1);
531     ellipsize_error_message_buff();
532     message(2,error_message_buff);
533 }
534
535 /* ------------------------------------------------------------------------- */
536 /*   Style 4: Compiler error message routines                                */
537 /* ------------------------------------------------------------------------- */
538
539 extern void print_sorry_message(void)
540 {   printf(
541 "***********************************************************************\n\
542 * 'Compiler errors' should never occur if Inform is working properly.  *\n\
543 * Check to see if there is a more recent version available, from which *\n\
544 * the problem may have been removed. If not, please report this fault  *\n\
545 * and if at all possible, please include your source code, as faults   *\n\
546 * such as these are rare  and often difficult to reproduce. Sorry.     *\n\
547 ***********************************************************************\n");
548 }
549
550 extern int compiler_error(char *s)
551 {
552     if (no_errors > 0) return FALSE;
553     if (no_compiler_errors==MAX_ERRORS)
554         fatalerror("Too many compiler errors: giving up");
555     message(4,s);
556     return TRUE;
557 }
558
559 extern int compiler_error_named(char *s1, char *s2)
560 {
561     if (no_errors > 0) return FALSE;
562     snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"",s1,s2);
563     ellipsize_error_message_buff();
564     compiler_error(error_message_buff);
565     return TRUE;
566 }
567
568 /* ------------------------------------------------------------------------- */
569 /*   Code for the Acorn RISC OS operating system, donated by Robin Watts,    */
570 /*   to provide error throwback under the DDE environment                    */
571 /* ------------------------------------------------------------------------- */
572
573 #ifdef ARC_THROWBACK
574
575 #define DDEUtils_ThrowbackStart 0x42587
576 #define DDEUtils_ThrowbackSend  0x42588
577 #define DDEUtils_ThrowbackEnd   0x42589
578
579 #include "kernel.h"
580
581 extern void throwback_start(void)
582 {    _kernel_swi_regs regs;
583      if (throwback_switch)
584          _kernel_swi(DDEUtils_ThrowbackStart, &regs, &regs);
585 }
586
587 extern void throwback_end(void)
588 {   _kernel_swi_regs regs;
589     if (throwback_switch)
590         _kernel_swi(DDEUtils_ThrowbackEnd, &regs, &regs);
591 }
592
593 int throwback_started = FALSE;
594
595 extern void throwback(int severity, char * error)
596 {   _kernel_swi_regs regs;
597     if (!throwback_started)
598     {   throwback_started = TRUE;
599         throwback_start();
600     }
601     if (throwback_switch)
602     {   regs.r[0] = 1;
603         if ((ErrorReport.file_number == -1)
604             || (ErrorReport.file_number == 0))
605             regs.r[2] = (int) (InputFiles[0].filename);
606         else regs.r[2] = (int) (InputFiles[ErrorReport.file_number-1].filename);
607         regs.r[3] = ErrorReport.line_number;
608         regs.r[4] = (2-severity);
609         regs.r[5] = (int) error;
610        _kernel_swi(DDEUtils_ThrowbackSend, &regs, &regs);
611     }
612 }
613
614 #endif
615
616 /* ========================================================================= */
617 /*   Data structure management routines                                      */
618 /* ------------------------------------------------------------------------- */
619
620 extern void init_errors_vars(void)
621 {   forerrors_buff = NULL;
622     no_errors = 0; no_warnings = 0; no_suppressed_warnings = 0;
623     no_compiler_errors = 0;
624 }
625
626 extern void errors_begin_pass(void)
627 {   ErrorReport.line_number = 0;
628     ErrorReport.file_number = -1;
629     ErrorReport.source = "<no text read yet>";
630     ErrorReport.main_flag = FALSE;
631     ErrorReport.orig_source = NULL;
632     ErrorReport.orig_file = 0;
633     ErrorReport.orig_line = 0;
634     ErrorReport.orig_char = 0;
635 }
636
637 extern void errors_allocate_arrays(void)
638 {   forerrors_buff = my_malloc(FORERRORS_SIZE, "errors buffer");
639 }
640
641 extern void errors_free_arrays(void)
642 {   my_free(&forerrors_buff, "errors buffer");
643 }
644
645 /* ========================================================================= */