Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra5-amd64/src/producers/common/utility/error.c – Rev 6

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 7u83 2
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
6 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
6 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
6 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
6 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
6 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#if FS_STDARG
63
#include <stdarg.h>
64
#else
65
#include <varargs.h>
66
#endif
67
#include <limits.h>
68
#include "system.h"
69
#include "version.h"
70
#include "c_types.h"
71
#include "err_ext.h"
72
#include "exp_ops.h"
73
#include "loc_ext.h"
74
#include "error.h"
75
#include "catalog.h"
76
#include "option.h"
77
#include "tdf.h"
78
#include "basetype.h"
79
#include "buffer.h"
80
#include "capsule.h"
81
#include "dump.h"
82
#include "file.h"
83
#include "lex.h"
84
#include "literal.h"
85
#include "preproc.h"
86
#include "print.h"
87
#include "save.h"
88
#include "statement.h"
89
#include "ustring.h"
90
#include "xalloc.h"
91
 
92
 
93
/*
94
    PROGRAM NAME
95
 
96
    These variables give the program name and version number.
97
*/
98
 
6 7u83 99
CONST char *progname = NULL;
100
CONST char *progvers = NULL;
2 7u83 101
 
102
 
103
/*
104
    SET PROGRAM NAME
105
 
106
    This routine sets the program name to the basename of prog and the
107
    program version to vers.
108
*/
109
 
6 7u83 110
void
111
set_progname(CONST char *prog, CONST char *vers)
2 7u83 112
{
6 7u83 113
	error_file = stderr;
114
	if (prog) {
115
		char *s = strrchr(prog, '/');
116
		if (s)prog = s + 1;
117
		s = strrchr(prog, file_sep);
118
		if (s)prog = s + 1;
119
		progname = prog;
120
	} else {
121
		progname = "unknown";
122
	}
123
	progvers = vers;
124
	return;
2 7u83 125
}
126
 
127
 
128
/*
129
    PRINT VERSION NUMBER
130
 
131
    This routine prints the program name and version number plus the
132
    versions of C++ and the TDF specification it supports to the print
133
    buffer, returning the result.
134
*/
135
 
6 7u83 136
string
137
report_version(int vers)
2 7u83 138
{
6 7u83 139
	BUFFER *bf = clear_buffer(&print_buff, NIL(FILE));
140
	bfprintf(bf, "%x: Version %x", progname, progvers);
141
	if (vers) {
142
		char buff[20];
143
		char *v = LANGUAGE_VERSION;
144
		sprintf_v(buff, "%.4s-%.2s", v, v + 4);
145
		bfprintf(bf, " (%x %x", LANGUAGE_NAME, buff);
146
		bfprintf(bf, " to TDF %d.%d", TDF_major, TDF_minor);
2 7u83 147
#ifdef RELEASE
6 7u83 148
		bfprintf(bf, ", Release %x", RELEASE);
2 7u83 149
#endif
6 7u83 150
		bfprintf(bf, ")");
151
	}
152
	return (bf->start);
2 7u83 153
}
154
 
155
 
156
/*
157
    CURRENT FILE POSITION
158
 
159
    This structure gives the current file position.  This consists of a
160
    string, giving the file name, an integer, giving the line number, and
161
    a pointer to any previous positions from which this is derived by a
162
    #include directive.
163
*/
164
 
6 7u83 165
LOCATION crt_loc = NULL_loc;
166
LOCATION builtin_loc = NULL_loc;
2 7u83 167
 
168
 
169
/*
170
    ERROR REPORTING VARIABLES
171
 
172
    These variables are used by the error reporting routines.  exit_status
173
    gives the overall status of the program - it is EXIT_SUCCESS if no
174
    serious errors have occurred, and EXIT_FAILURE otherwise.  A count of
175
    the number of serious errors is kept in number_errors, up to a maximum
176
    of max_errors.
177
*/
178
 
6 7u83 179
FILE *error_file = NULL;
180
int exit_status = EXIT_SUCCESS;
181
unsigned long number_errors = 0;
182
unsigned long number_warnings = 0;
183
unsigned long max_errors = 32;
184
int error_threshold = ERROR_NONE;
185
int no_error_args = 0;
186
int verbose = 0;
187
static int print_short = 0;
188
static int print_error_loc = 0;
189
static int print_error_name = 0;
190
static int print_error_source = 0;
191
static int print_iso_ref = 1;
192
static int print_ansi_ref = 0;
2 7u83 193
 
194
 
195
/*
196
    PROCESS AN ERROR FORMATTING OPTION
197
 
198
    This routine processes the error formatting options given by opt.
199
    This corresponds to the command-line option '-mopt'.
200
*/
201
 
6 7u83 202
void
203
error_option(string opt)
2 7u83 204
{
6 7u83 205
	int out = 1;
206
	character c;
207
	while (c = *(opt++), c != 0) {
208
		switch (c) {
209
		case 'a':
210
			print_ansi_ref = out;
211
			break;
212
		case 'c':
213
			print_error_source = out;
214
			break;
215
		case 'e':
216
			print_error_name = out;
217
			break;
218
		case 'f':
219
			good_fseek = out;
220
			break;
221
		case 'g':
222
			record_location = out;
223
			break;
224
		case 'i':
225
			good_stat = out;
226
			break;
227
		case 'k':
228
			output_spec = out;
229
			break;
230
		case 'l':
231
			print_error_loc = out;
232
			break;
233
		case 'm':
234
			allow_multibyte = out;
235
			break;
236
		case 'p':
237
			preproc_space = out;
238
			break;
239
		case 'q':
240
			print_short = out;
241
			break;
242
		case 'r':
243
			allow_dos_newline = out;
244
			break;
245
		case 's':
246
			print_iso_ref = out;
247
			break;
248
		case 't':
249
			print_type_alias = out;
250
			break;
251
		case 'x':
252
			print_c_style = out;
253
			break;
254
		case '+':
255
			out = 1;
256
			break;
257
		case '-':
258
			out = 0;
259
			break;
260
		case 'o': {
261
			error_file = (out ? stdout : stderr);
262
			break;
263
		}
264
		case 'w': {
265
			OPTION sev = OPTION_WARN;
266
			if (out) {
267
				sev = OPTION_OFF;
268
			}
269
			OPT_CATALOG[OPT_warning].def[0] = sev;
270
			OPT_CATALOG[OPT_warning].def[1] = sev;
271
			break;
272
		}
273
		case 'z': {
274
			OPTION sev = OPTION_ON;
275
			if (out) {
276
				sev = OPTION_WARN;
277
			}
278
			OPT_CATALOG[OPT_error].def[0] = sev;
279
			OPT_CATALOG[OPT_error].def[1] = sev;
280
			break;
281
		}
282
		default : {
283
			/* Unknown output options */
284
			CONST char *err =
285
			    "Unknown error formatting option, '%c'";
286
			error(ERROR_WARNING, err,(int)c);
287
			break;
288
		}
289
		}
2 7u83 290
	}
6 7u83 291
	return;
2 7u83 292
}
293
 
294
 
295
/*
296
    ERROR MESSAGE PARAMETERS
297
 
298
    These macros are used to parameterise the form of the error messages.
299
*/
300
 
301
#define HEADER_FATAL		"Fatal error"
302
#define HEADER_SERIOUS		"Error"
303
#define HEADER_WARNING		"Warning"
304
#define HEADER_INTERNAL		"Internal error"
305
#define HEADER_ASSERT		"Assertion"
306
 
6 7u83 307
#define PRINT_HEADER(M, L, F)\
308
	print_location((L), (F));\
309
	fputs_v(": ",(F));\
310
	fputs_v((M), (F));\
311
	fputs_v(":\n",(F))
2 7u83 312
 
6 7u83 313
#define PRINT_SOURCE(L, F)\
314
	print_source((L), 1, 0, "    ",(F))
2 7u83 315
 
6 7u83 316
#define PRINT_FROM(L, F)\
317
	fputs_v("    (included from ",(F));\
318
	print_location((L), (F));\
319
	fputs_v(")\n",(F))
2 7u83 320
 
6 7u83 321
#define PRINT_START(M, F)\
322
	fputs_v((M), (F));\
323
	fputs_v(": ",(F))
2 7u83 324
 
325
#define MESSAGE_START		"  "
326
#define MESSAGE_END		".\n"
327
#define MESSAGE_TERM		"\n"
328
#define MESSAGE_NAME		"[%x]: "
329
#define MESSAGE_ISO		"[ISO %x]: "
330
#define MESSAGE_ANSI		"[ANSI "
331
#define MESSAGE_ANSI_END	"]: "
332
#define MESSAGE_PRAGMA		"[Pragma]: "
333
#define MESSAGE_PRINTF		"[Printf]: "
334
#define MESSAGE_SYNTAX		"[Syntax]: "
335
#define MESSAGE_TOKEN		"[Token]: "
336
 
337
 
338
/*
339
    FORWARD DECLARATION
340
 
341
    The following forward declaration is necessary.
342
*/
343
 
6 7u83 344
static void print_error_msg(ERROR, LOCATION *, FILE *);
2 7u83 345
 
346
 
347
/*
348
    TERMINATE PROGRAM
349
 
350
    This routine is called to terminate the program.  It tidies up any
351
    output files and error messages and then exits.  fatal is true after
352
    a memory allocation error when the amount of tidying up which can
353
    be done is limited, although some memory is freed to give a little
354
    leeway.
355
*/
356
 
6 7u83 357
void
358
term_error(int fatal)
2 7u83 359
{
6 7u83 360
	if (fatal) {
361
		/* Cope with memory allocation errors */
362
		exit_status = EXIT_FAILURE;
363
		output_capsule = 0;
364
		output_spec = 0;
365
		free_buffer(&token_buff);
366
	}
367
	if (do_dump) {
368
		/* End dump file */
369
		term_dump();
370
		do_dump = 0;
371
	}
372
	if (do_error) {
373
		/* Report errors in dump file */
374
		unsigned long e = number_errors;
375
		unsigned long w = number_warnings;
376
		int sev = (e ? ERROR_SERIOUS : ERROR_WARNING);
377
		do_error = 0;
378
		error(sev, "%lu error(s), %lu warning(s)", e, w);
379
	}
380
	if (output_name[OUTPUT_SPEC]) {
381
		/* Write spec file */
382
		begin_spec();
383
		end_spec();
384
	}
385
	if (output_tdf) {
386
		/* Write capsule */
387
		write_capsule();
388
	}
389
	exit(exit_status);
2 7u83 390
}
391
 
392
 
393
/*
394
    ERROR BREAKPOINT ROUTINE
395
 
396
    This routine is intended to aid in debugging.  It is called just after
397
    any error message is printed.
398
*/
399
 
6 7u83 400
static void
401
error_break(void)
2 7u83 402
{
6 7u83 403
	return;
2 7u83 404
}
405
 
406
 
407
/*
408
    FIND AN ERROR MESSAGE HEADER
409
 
410
    This routine returns the error message header for an error of severity
411
    sev.  It also updates the internal flags.
412
*/
413
 
6 7u83 414
static CONST char *
415
error_header(int sev)
2 7u83 416
{
6 7u83 417
	CONST char *msg;
418
	switch (sev) {
419
	case ERROR_FATAL: {
420
		msg = HEADER_FATAL;
421
		exit_status = EXIT_FAILURE;
422
		output_capsule = 0;
423
		number_errors++;
424
		break;
2 7u83 425
	}
6 7u83 426
	case ERROR_INTERNAL: {
427
		msg = HEADER_INTERNAL;
428
		if (error_severity[OPTION_ON] == ERROR_SERIOUS) {
429
			exit_status = EXIT_FAILURE;
430
			output_capsule = 0;
431
		}
432
		number_errors++;
433
		break;
2 7u83 434
	}
435
	default : {
6 7u83 436
		msg = HEADER_SERIOUS;
437
		if (error_severity[OPTION_ON] == ERROR_SERIOUS) {
438
			exit_status = EXIT_FAILURE;
439
			output_capsule = 0;
440
		}
441
		number_errors++;
442
		break;
2 7u83 443
	}
6 7u83 444
	case ERROR_WARNING: {
445
		msg = HEADER_WARNING;
446
		number_warnings++;
447
		break;
2 7u83 448
	}
6 7u83 449
	}
450
	return (msg);
2 7u83 451
}
452
 
453
 
454
/*
455
    PRINT A LOCATION TO A FILE
456
 
457
    This routine prints the location loc to the file f.
458
*/
459
 
6 7u83 460
static void
461
print_location(LOCATION *loc, FILE *f)
2 7u83 462
{
6 7u83 463
	BUFFER *bf = clear_buffer(&print_buff, f);
464
	IGNORE print_loc(loc, NIL(LOCATION), bf, 0);
465
	output_buffer(bf, 0);
466
	return;
2 7u83 467
}
468
 
469
 
470
/*
471
    CONVERT AN ISO SECTION NUMBER TO AN ANSI SECTION NUMBER
472
 
473
    The ISO C standard was based on the ANSI C standard but the sections
474
    were renumbered.  The ISO and ANSI C++ standards are identical.  This
475
    routine converts the ISO section number s to the corresponding ANSI
476
    section number, printing it to the buffer bf.
477
*/
478
 
6 7u83 479
static void
480
iso_to_ansi(BUFFER *bf, CONST char *s)
2 7u83 481
{
482
#if LANGUAGE_C
6 7u83 483
	char c;
484
	unsigned long n = 0;
485
	CONST char *p = "1.";
486
	CONST char *q = s;
487
	while (c = *q,(c >= '0' && c <= '9')) {
488
		n = 10 * n + (unsigned long)(c - '0');
489
		q++;
2 7u83 490
	}
6 7u83 491
	if (n == 0) {
492
		bfprintf(bf, "%x", s);
493
	} else {
494
		switch (n) {
495
		case 1:
496
			n = 2;
497
			break;
498
		case 2:
499
			n = 3;
500
			break;
501
		case 3:
502
			n = 6;
503
			break;
504
		case 4:
505
			n = 7;
506
			break;
507
		default:
508
			p = "";
509
			n -= 3;
510
			break;
511
		}
512
		bfprintf(bf, "%x%lu%x", p, n, q);
513
	}
2 7u83 514
#else
6 7u83 515
	bfprintf(bf, "%x", s);
2 7u83 516
#endif
6 7u83 517
	return;
2 7u83 518
}
519
 
520
 
521
/*
522
    PRINT THE START OF AN ERROR MESSAGE
523
 
524
    This routine prints the start of an error message of severity sev and
525
    location loc to the file f.
526
*/
527
 
6 7u83 528
static void
529
print_error_start(FILE *f, LOCATION *loc, int sev)
2 7u83 530
{
6 7u83 531
	CONST char *msg = error_header(sev);
532
	if (loc) {
533
		PRINT_HEADER(msg, loc, f);
534
		if (print_error_loc) {
535
			/* Print full error location */
536
			LOCATION floc;
537
			LOCATION *ploc = loc;
538
			for (;;) {
539
				PTR(LOCATION)from;
540
				PTR(POSITION)posn = ploc->posn;
541
				if (IS_NULL_ptr(posn)) {
542
					break;
543
				}
544
				from = DEREF_ptr(posn_from(posn));
545
				if (IS_NULL_ptr(from)) {
546
					break;
547
				}
548
				DEREF_loc(from, floc);
549
				ploc = &floc;
550
				PRINT_FROM(ploc, f);
551
			}
552
		}
553
		if (print_error_source) {
554
			/* Print source line */
555
			PRINT_SOURCE(loc, f);
556
		}
557
	} else {
558
		PRINT_START(msg, f);
2 7u83 559
	}
6 7u83 560
	return;
2 7u83 561
}
562
 
563
 
564
/*
565
    PRINT THE END OF AN ERROR MESSAGE
566
 
567
    This routine prints the end of an error message of severity sev to
568
    the file f.
569
*/
570
 
6 7u83 571
static void
572
print_error_end(FILE *f, int sev)
2 7u83 573
{
6 7u83 574
	unsigned long n = number_errors;
575
	if (n >= max_errors && sev != ERROR_FATAL) {
576
		ERROR err = ERR_fail_too_many(n);
577
		print_error_msg(err, &crt_loc, f);
578
		sev = ERROR_FATAL;
579
	}
580
	fputs_v(MESSAGE_TERM, f);
581
	error_break();
582
	if (sev == ERROR_FATAL) {
583
		term_error(0);
584
	}
585
	return;
2 7u83 586
}
587
 
588
 
589
/*
590
    OPTION SEVERITY LEVELS
591
 
592
    This table gives the mapping between options and error severity
593
    levels.
594
*/
595
 
6 7u83 596
int error_severity[] = {
597
	ERROR_NONE,			/* OPTION_OFF */
598
	ERROR_WARNING,			/* OPTION_WARN */
599
	ERROR_SERIOUS,			/* OPTION_ON */
600
	ERROR_WHATEVER			/* OPTION_WHATEVER */
601
};
2 7u83 602
 
6 7u83 603
int default_severity[] = {
604
	ERROR_NONE,			/* OPTION_OFF */
605
	ERROR_WARNING,			/* OPTION_WARN */
606
	ERROR_SERIOUS,			/* OPTION_ON */
607
	ERROR_WHATEVER			/* OPTION_WHATEVER */
608
};
2 7u83 609
 
610
 
611
/*
612
    CREATE AN ERROR STRUCTURE
613
 
614
    This routine creates a structure for error n in the error catalogue.
615
    Any extra arguments needed by the error should also be given.  Because
616
    of restrictions imposed by the way that stdarg is implemented, any
617
    structure arguments need to be explicitly passed by reference.  Note
618
    that these arguments are stored in the result in reverse order.
619
*/
620
 
6 7u83 621
ERROR
622
make_error(int n, ...) /* VARARGS */
2 7u83 623
{
6 7u83 624
	int sev;
625
	ERROR e;
626
	OPTION opt;
627
	va_list args;
628
	ERR_DATA *msg;
629
	CONST char *s;
2 7u83 630
#if FS_STDARG
6 7u83 631
	va_start(args, n);
2 7u83 632
#else
6 7u83 633
	int n;
634
	va_start(args);
635
	n = va_arg(args, int);
2 7u83 636
#endif
637
 
6 7u83 638
	/* Check severity level */
639
	msg = ERR_CATALOG + n;
640
	if (crt_opt) {
641
		opt = crt_opt[msg->usage];
642
	} else {
643
		/* Can have errors before crt_opt is initialised */
644
		opt = OPT_CATALOG[msg->usage].def[0];
645
	}
646
	sev = error_severity[opt];
647
	if (sev == ERROR_NONE) {
648
		va_end(args);
649
		return (NULL_err);
650
	}
2 7u83 651
 
6 7u83 652
	/* Read arguments */
653
	s = msg->signature;
654
	if (s == NULL) {
655
		MAKE_err_simple(sev, n, e);
656
	} else {
657
		unsigned i, m = (unsigned)strlen(s);
658
		if (no_error_args)m = 0;
659
		MAKE_err_simple_args(sev, n, m, e);
660
		for (i = 0; i < m; i++) {
661
			switch (s[i]) {
662
			case ERR_KEY_BASE_TYPE: {
663
				BASE_TYPE arg = va_arg(args, BASE_TYPE);
664
				COPY_btype(err_arg(e, i, BASE_TYPE), arg);
665
				break;
666
			}
667
			case ERR_KEY_CLASS_TYPE: {
668
				CLASS_TYPE arg = va_arg(args, CLASS_TYPE);
669
				COPY_ctype(err_arg(e, i, CLASS_TYPE), arg);
670
				break;
671
			}
672
			case ERR_KEY_CV_SPEC: {
673
				CV_SPEC arg = va_arg(args, CV_SPEC);
674
				COPY_cv(err_arg(e, i, CV_SPEC), arg);
675
				break;
676
			}
677
			case ERR_KEY_ACCESS:
678
			case ERR_KEY_DECL_SPEC: {
679
				DECL_SPEC arg = va_arg(args, DECL_SPEC);
680
				COPY_dspec(err_arg(e, i, DECL_SPEC), arg);
681
				break;
682
			}
683
			case ERR_KEY_FLOAT: {
684
				FLOAT arg = va_arg(args, FLOAT);
685
				COPY_flt(err_arg(e, i, FLOAT), arg);
686
				break;
687
			}
688
			case ERR_KEY_HASHID: {
689
				HASHID arg = va_arg(args, HASHID);
690
				COPY_hashid(err_arg(e, i, HASHID), arg);
691
				break;
692
			}
693
			case ERR_KEY_IDENTIFIER:
694
			case ERR_KEY_LONG_ID: {
695
				IDENTIFIER arg = va_arg(args, IDENTIFIER);
696
				COPY_id(err_arg(e, i, IDENTIFIER), arg);
697
				break;
698
			}
699
			case ERR_KEY_LEX: {
700
				LEX arg = va_arg(args, LEX);
701
				COPY_int(err_arg(e, i, LEX), arg);
702
				break;
703
			}
704
			case ERR_KEY_NAMESPACE: {
705
				NAMESPACE arg = va_arg(args, NAMESPACE);
706
				COPY_nspace(err_arg(e, i, NAMESPACE), arg);
707
				break;
708
			}
709
			case ERR_KEY_NAT: {
710
				NAT arg = va_arg(args, NAT);
711
				COPY_nat(err_arg(e, i, NAT), arg);
712
				break;
713
			}
714
			case ERR_KEY_PPTOKEN_P: {
715
				PPTOKEN_P arg = va_arg(args, PPTOKEN_P);
716
				COPY_pptok(err_arg(e, i, PPTOKEN_P), arg);
717
				break;
718
			}
719
			case ERR_KEY_PTR_LOC: {
720
				PTR_LOC arg = va_arg(args, PTR_LOC);
721
				COPY_ptr(err_arg(e, i, PTR_LOC), arg);
722
				break;
723
			}
724
			case ERR_KEY_QUALIFIER: {
725
				QUALIFIER arg = va_arg(args, QUALIFIER);
726
				COPY_qual(err_arg(e, i, QUALIFIER), arg);
727
				break;
728
			}
729
			case ERR_KEY_STRING: {
730
				STRING arg = va_arg(args, STRING);
731
				COPY_str(err_arg(e, i, STRING), arg);
732
				break;
733
			}
734
			case ERR_KEY_TYPE: {
735
				TYPE arg = va_arg(args, TYPE);
736
				COPY_type(err_arg(e, i, TYPE), arg);
737
				break;
738
			}
739
			case ERR_KEY_cint: {
740
				cint arg = va_arg(args, cint);
741
				COPY_int(err_arg(e, i, cint), arg);
742
				break;
743
			}
744
			case ERR_KEY_cstring: {
745
				cstring arg = va_arg(args, cstring);
746
				string uarg = ustrlit(arg);
747
				COPY_string(err_arg(e, i, string), uarg);
748
				break;
749
			}
750
			case ERR_KEY_string: {
751
				string arg = va_arg(args, string);
752
				COPY_string(err_arg(e, i, string), arg);
753
				break;
754
			}
755
			case ERR_KEY_ulong:
756
			case ERR_KEY_ucint: {
757
				ulong arg = va_arg(args, ulong);
758
				COPY_ulong(err_arg(e, i, ulong), arg);
759
				break;
760
			}
761
			case ERR_KEY_unsigned:
762
			case ERR_KEY_plural: {
763
				unsigned arg = va_arg(args, unsigned);
764
				COPY_unsigned(err_arg(e, i, unsigned), arg);
765
				break;
766
			}
767
			default : {
768
				FAIL(Bad signature);
769
				break;
770
			}
771
			}
2 7u83 772
		}
773
	}
6 7u83 774
	va_end(args);
775
	return (e);
2 7u83 776
}
777
 
778
 
779
/*
780
    PRINT THE BODY OF AN ERROR STRUCTURE
781
 
782
    This routine prints the body of the simple error message e to the
783
    buffer bf.
784
*/
785
 
6 7u83 786
static void
787
print_error_body(ERROR e, LOCATION *loc, BUFFER *bf)
2 7u83 788
{
6 7u83 789
	char c;
790
	QUALIFIER qual = qual_none;
2 7u83 791
 
6 7u83 792
	/* Extract error information */
793
	int n = DEREF_int(err_simple_number(e));
794
	unsigned sz = DEREF_unsigned(err_simple_size(e));
2 7u83 795
 
6 7u83 796
	/* Look up error in catalogue */
797
	ERR_DATA *msg = ERR_CATALOG + n;
798
	CONST char *sig = msg->signature;
799
	CONST char *s = msg->key_STD;
2 7u83 800
 
6 7u83 801
	/* Print the error message */
802
	if (s == NULL) return;
803
	while (c = *(s++), c != 0) {
804
		if (c == '%') {
805
			/* Error argument - find number */
806
			unsigned a;
807
			c = *(s++);
808
			if (c >= '0' && c <= '9') {
809
				/* Arguments 0 to 9 */
810
				a = (unsigned)(c - '0');
811
			} else {
812
				if (c != '%')bfputc(bf, '%');
813
				bfputc(bf, c);
814
				continue;
815
			}
2 7u83 816
 
6 7u83 817
			/* Find argument type */
818
			if (a < sz) {
819
				c = sig[a];
820
			} else {
821
				c = '?';
822
			}
2 7u83 823
 
6 7u83 824
			/* Print appropriate argument */
825
			switch (c) {
826
			case ERR_KEY_ACCESS: {
827
				ACCESS arg = DEREF_dspec(err_arg(e, a, ACCESS));
828
				IGNORE print_access(arg, bf, 0);
829
				break;
2 7u83 830
			}
6 7u83 831
			case ERR_KEY_BASE_TYPE: {
832
				BASE_TYPE arg;
833
				arg = DEREF_btype(err_arg(e, a, BASE_TYPE));
834
				IGNORE print_btype(arg, bf, 0);
835
				break;
836
			}
837
			case ERR_KEY_CLASS_TYPE: {
838
				CLASS_TYPE arg;
839
				arg = DEREF_ctype(err_arg(e, a, CLASS_TYPE));
840
				IGNORE print_ctype(arg, qual_none, 0, bf, 0);
841
				break;
842
			}
843
			case ERR_KEY_CV_SPEC: {
844
				CV_SPEC arg = DEREF_cv(err_arg(e, a, CV_SPEC));
845
				if (!print_cv(arg, bf, 0)) {
846
					bfprintf(bf, "<none>");
847
				}
848
				break;
849
			}
850
			case ERR_KEY_DECL_SPEC: {
851
				DECL_SPEC arg;
852
				arg = DEREF_dspec(err_arg(e, a, DECL_SPEC));
853
				if (!print_dspec(arg, bf, 0)) {
854
					bfprintf(bf, "<none>");
855
				}
856
				break;
857
			}
858
			case ERR_KEY_FLOAT: {
859
				FLOAT arg = DEREF_flt(err_arg(e, a, FLOAT));
860
				IGNORE print_flt(arg, bf, 0);
861
				break;
862
			}
863
			case ERR_KEY_HASHID: {
864
				HASHID arg = DEREF_hashid(err_arg(e, a, HASHID));
865
				IGNORE print_hashid(arg, 1, 1, bf, 0);
866
				break;
867
			}
868
			case ERR_KEY_IDENTIFIER: {
869
				IDENTIFIER arg;
870
				arg = DEREF_id(err_arg(e, a, IDENTIFIER));
871
				IGNORE print_id_short(arg, qual, bf, 0);
872
				qual = qual_none;
873
				break;
874
			}
875
			case ERR_KEY_LEX: {
876
				LEX arg = DEREF_int(err_arg(e, a, LEX));
877
				IGNORE print_lex(arg, bf, 0);
878
				break;
879
			}
880
			case ERR_KEY_LONG_ID: {
881
				LONG_ID arg = DEREF_id(err_arg(e, a, LONG_ID));
882
				IGNORE print_id_long(arg, qual, bf, 0);
883
				qual = qual_none;
884
				break;
885
			}
886
			case ERR_KEY_NAMESPACE: {
887
				NAMESPACE arg;
888
				arg = DEREF_nspace(err_arg(e, a, NAMESPACE));
889
				IGNORE print_nspace(arg, qual_none, 0, bf, 0);
890
				break;
891
			}
892
			case ERR_KEY_NAT: {
893
				NAT arg = DEREF_nat(err_arg(e, a, NAT));
894
				IGNORE print_nat(arg, 0, bf, 0);
895
				break;
896
			}
897
			case ERR_KEY_PPTOKEN_P: {
898
				PPTOKEN_P arg;
899
				arg = DEREF_pptok(err_arg(e, a, PPTOKEN_P));
900
				IGNORE print_pptok(arg, bf, 0);
901
				break;
902
			}
903
			case ERR_KEY_PTR_LOC: {
904
				PTR_LOC arg;
905
				arg = DEREF_ptr(err_arg(e, a, PTR_LOC));
906
				if (!IS_NULL_ptr(arg)) {
907
					LOCATION ploc;
908
					DEREF_loc(arg, ploc);
909
					IGNORE print_loc(&ploc, loc, bf, 0);
910
				} else {
911
					IGNORE print_loc(loc, loc, bf, 0);
912
				}
913
				break;
914
			}
915
			case ERR_KEY_QUALIFIER: {
916
				QUALIFIER arg;
917
				arg = DEREF_qual(err_arg(e, a, QUALIFIER));
918
				qual = arg;
919
				break;
920
			}
921
			case ERR_KEY_STRING: {
922
				STRING arg = DEREF_str(err_arg(e, a, STRING));
923
				IGNORE print_str(arg, bf, 0);
924
				break;
925
			}
926
			case ERR_KEY_TYPE: {
927
				TYPE arg = DEREF_type(err_arg(e, a, TYPE));
928
				IGNORE print_type(arg, bf, 0);
929
				break;
930
			}
931
			case ERR_KEY_cint: {
932
				cint arg = DEREF_int(err_arg(e, a, cint));
933
				unsigned long ca = (unsigned long)arg;
934
				print_char(ca, CHAR_SIMPLE, 0, bf);
935
				break;
936
			}
937
			case ERR_KEY_plural: {
938
				plural arg = DEREF_unsigned(err_arg(e, a, plural));
939
				if (arg != 1)bfputc(bf, 's');
940
				break;
941
			}
942
			case ERR_KEY_cstring:
943
			case ERR_KEY_string: {
944
				string arg =
945
				    DEREF_string(err_arg(e, a, string));
946
				if (arg) {
947
					ulong u;
948
					while (u = (ulong)*(arg++), u != 0) {
949
						print_char(u, CHAR_SIMPLE, 0,
950
							   bf);
951
					}
952
				}
953
				break;
954
			}
955
			case ERR_KEY_ucint: {
956
				ucint arg = DEREF_ulong(err_arg(e, a, ucint));
957
				if (arg <= (ucint)0xffff) {
958
					print_char(arg, CHAR_UNI4, 0, bf);
959
				} else {
960
					print_char(arg, CHAR_UNI8, 0, bf);
961
				}
962
				break;
963
			}
964
			case ERR_KEY_ulong: {
965
				ulong arg = DEREF_ulong(err_arg(e, a, ulong));
966
				bfprintf(bf, "%lu", arg);
967
				break;
968
			}
969
			case ERR_KEY_unsigned: {
970
				unsigned arg;
971
				arg = DEREF_unsigned(err_arg(e, a, unsigned));
972
				bfprintf(bf, "%u", arg);
973
				break;
974
			}
975
			default : {
976
				bfprintf(bf, "<arg%u>", a);
977
				break;
978
			}
979
			}
980
		} else {
981
			/* Other characters */
982
			bfputc(bf, c);
2 7u83 983
		}
984
	}
6 7u83 985
	return;
2 7u83 986
}
987
 
988
 
989
/*
990
    PRINT AN ERROR STRUCTURE
991
 
992
    This routine prints the body of the error message given by e to the
993
    file f.
994
*/
995
 
6 7u83 996
static void
997
print_error_msg(ERROR e, LOCATION *loc, FILE *f)
2 7u83 998
{
6 7u83 999
	if (IS_err_simple(e)) {
1000
		/* Print simple error message */
1001
		BUFFER *bf;
1002
		int n = DEREF_int(err_simple_number(e));
1003
		ERR_DATA *msg = ERR_CATALOG + n;
1004
		ERR_PROPS props = msg->props;
1005
		int sev = DEREF_int(err_severity(e));
1006
		if (sev == ERROR_WHATEVER && print_short) return;
1007
		bf = clear_buffer(&print_buff, f);
1008
		if (loc)bfprintf(bf, MESSAGE_START);
1009
		if (print_error_name) {
1010
			CONST char *name = msg->name;
1011
			if (name)bfprintf(bf, MESSAGE_NAME, name);
2 7u83 1012
		}
6 7u83 1013
		if (!(props & ERR_PROP_non_iso) && print_iso_ref) {
1014
			CONST char *iso;
1015
			ERR_DATA *prev = msg;
1016
			while (iso = prev->key_ISO, iso == NULL) {
1017
				/* Scan back to current section number */
1018
				if (prev == ERR_CATALOG)break;
1019
				prev--;
1020
			}
1021
			msg->key_ISO = iso;
1022
			if (iso && iso[0]) {
1023
				if (print_ansi_ref) {
1024
					bfprintf(bf, MESSAGE_ANSI);
1025
					iso_to_ansi(bf, iso);
1026
					bfprintf(bf, MESSAGE_ANSI_END);
1027
				} else {
1028
					bfprintf(bf, MESSAGE_ISO, iso);
1029
				}
1030
			}
1031
		}
1032
		if (props) {
1033
			if (props & ERR_PROP_pragma) {
1034
				bfprintf(bf, MESSAGE_PRAGMA);
1035
			}
1036
			if (props & ERR_PROP_printf) {
1037
				bfprintf(bf, MESSAGE_PRINTF);
1038
			}
1039
			if (props & ERR_PROP_token) {
1040
				bfprintf(bf, MESSAGE_TOKEN);
1041
			}
1042
			if (props & ERR_PROP_syntax) {
1043
				bfprintf(bf, MESSAGE_SYNTAX);
1044
			}
1045
		}
1046
		print_error_body(e, loc, bf);
1047
		bfprintf(bf, MESSAGE_END);
1048
		output_buffer(bf, 1);
1049
 
1050
	} else {
1051
		/* Print composite error message */
1052
		ERROR e1 = DEREF_err(err_compound_head(e));
1053
		ERROR e2 = DEREF_err(err_compound_tail(e));
1054
		print_error_msg(e1, loc, f);
1055
		print_error_msg(e2, loc, f);
2 7u83 1056
	}
6 7u83 1057
	return;
2 7u83 1058
}
1059
 
1060
 
1061
/*
1062
    DESTROY AN ERROR STRUCTURE
1063
 
1064
    This routine destroys the error structure e.  If d is false then the
1065
    first component of a compound error is not destroyed.
1066
*/
1067
 
6 7u83 1068
void
1069
destroy_error(ERROR e, int d)
2 7u83 1070
{
6 7u83 1071
	if (!IS_NULL_err(e)) {
1072
		if (IS_err_simple(e)) {
1073
			if (d)DESTROY_err_simple_args(e);
1074
		} else {
1075
			int sev;
1076
			ERROR e1, e2;
1077
			DESTROY_err_compound(destroy, sev, e1, e2, e);
1078
			if (d)destroy_error(e1, 1);
1079
			destroy_error(e2, 1);
1080
			UNUSED(sev);
1081
		}
2 7u83 1082
	}
6 7u83 1083
	return;
2 7u83 1084
}
1085
 
1086
 
1087
/*
1088
    JOIN TWO ERROR STRUCTURES
1089
 
1090
    This routine joins the error structures e1 and e2 into a single compound
1091
    error structure.
1092
*/
1093
 
6 7u83 1094
ERROR
1095
concat_error(ERROR e1, ERROR e2)
2 7u83 1096
{
6 7u83 1097
	ERROR e;
1098
	int s1, s2;
1099
	if (IS_NULL_err(e1)) {
1100
		return (e2);
1101
	}
1102
	if (IS_NULL_err(e2)) {
1103
		return (e1);
1104
	}
1105
	s1 = DEREF_int(err_severity(e1));
1106
	s2 = DEREF_int(err_severity(e2));
1107
	if (s2 > s1) {
1108
		s1 = s2;
1109
	}
1110
	MAKE_err_compound(s1, e1, e2, e);
1111
	return (e);
2 7u83 1112
}
1113
 
1114
 
1115
/*
1116
    OPTIONALLY JOIN TWO ERROR STRUCTURES
1117
 
1118
    This routine joins the error structures e1 and e2 into a single compound
1119
    error structure if e1 represents a serious error.  Otherwise e2 is
1120
    destroyed and e1 is returned.
1121
*/
1122
 
6 7u83 1123
ERROR
1124
concat_warning(ERROR e1, ERROR e2)
2 7u83 1125
{
6 7u83 1126
	ERROR e;
1127
	int s1, s2;
1128
	if (IS_NULL_err(e1)) {
1129
		return (e2);
1130
	}
1131
	if (IS_NULL_err(e2)) {
1132
		return (e1);
1133
	}
1134
	s1 = DEREF_int(err_severity(e1));
1135
	if (s1 > ERROR_WARNING) {
1136
		s2 = DEREF_int(err_severity(e2));
1137
		if (s2 > s1) {
1138
			s1 = s2;
1139
		}
1140
		MAKE_err_compound(s1, e1, e2, e);
1141
	} else {
1142
		destroy_error(e2, 1);
1143
		e = e1;
1144
	}
1145
	return (e);
2 7u83 1146
}
1147
 
1148
 
1149
/*
1150
    ADD AN ERROR TO A LIST
1151
 
1152
    This routine adds the error e to the end of the list indicated by err.
1153
    If err is the null pointer then e is destroyed.
1154
*/
1155
 
6 7u83 1156
void
1157
add_error(ERROR *err, ERROR e)
2 7u83 1158
{
6 7u83 1159
	if (!IS_NULL_err(e)) {
1160
		if (err) {
1161
			ERROR e1 = *err;
1162
			if (IS_NULL_err(e1)) {
1163
				*err = e;
1164
			} else {
1165
				int s1 = DEREF_int(err_severity(e1));
1166
				int s2 = DEREF_int(err_severity(e));
1167
				if (s2 > s1) {
1168
					s1 = s2;
1169
				}
1170
				MAKE_err_compound(s1, e1, e, *err);
1171
			}
1172
		} else {
1173
			destroy_error(e, 1);
1174
		}
2 7u83 1175
	}
6 7u83 1176
	return;
2 7u83 1177
}
1178
 
1179
 
1180
/*
1181
    STANDARD ERROR PREFIX
1182
 
1183
    These variables give an error message which is added to the start
1184
    of any error before it is printed.  The prefix error severity is not
1185
    taken into account in the overall error severity.
1186
*/
1187
 
6 7u83 1188
static ERROR error_prefix = NULL_err;
2 7u83 1189
 
1190
 
1191
/*
1192
    SET ERROR PREFIX
1193
 
1194
    This routine sets the error prefix to be e, returning the previous
1195
    value.
1196
*/
1197
 
6 7u83 1198
ERROR
1199
set_prefix(ERROR e)
2 7u83 1200
{
6 7u83 1201
	ERROR p = error_prefix;
1202
	error_prefix = e;
1203
	return (p);
2 7u83 1204
}
1205
 
1206
 
1207
/*
1208
    RESTORE ERROR PREFIX
1209
 
1210
    This routine restores the error prefix to e, destroying the previous
1211
    value.
1212
*/
1213
 
6 7u83 1214
void
1215
restore_prefix(ERROR e)
2 7u83 1216
{
6 7u83 1217
	destroy_error(error_prefix, 1);
1218
	error_prefix = e;
1219
	return;
2 7u83 1220
}
1221
 
1222
 
1223
/*
1224
    PRINT AN ERROR MESSAGE
1225
 
1226
    This routine prints the error e at location loc.
1227
*/
1228
 
6 7u83 1229
void
1230
print_error(LOCATION *loc, ERROR e)
2 7u83 1231
{
6 7u83 1232
	if (!IS_NULL_err(e)) {
1233
		int d = 1;
1234
		int sev = DEREF_int(err_severity(e));
1235
		if (sev > error_threshold) {
1236
			ERROR p = error_prefix;
1237
			if (!IS_NULL_err(p)) {
1238
				/* Add error prefix */
1239
				MAKE_err_compound(sev, p, e, e);
1240
				d = 0;
1241
			}
1242
			if (do_error && dump_error(e, loc, sev, 0)) {
1243
				/* Dump error to file */
1244
				unsigned long n;
1245
				IGNORE error_header(sev);
1246
				n = number_errors;
1247
				error_break();
1248
				if (sev == ERROR_FATAL)term_error(0);
1249
				if (n >= max_errors)term_error(0);
1250
			} else {
1251
				/* Print error to standard error */
1252
				FILE *f = error_file;
1253
				print_error_start(f, loc, sev);
1254
				print_error_msg(e, loc, f);
1255
				print_error_end(f, sev);
1256
			}
1257
		}
1258
		destroy_error(e, d);
2 7u83 1259
	}
6 7u83 1260
	return;
2 7u83 1261
}
1262
 
1263
 
1264
/*
1265
    CREATE AN INSTALLER ERROR EXPRESSION
1266
 
1267
    This routine creates an install-time error expression for the error
1268
    e at the location loc.
1269
*/
1270
 
6 7u83 1271
EXP
1272
install_error(LOCATION *loc, ERROR e)
2 7u83 1273
{
6 7u83 1274
	EXP a = NULL_exp;
1275
	if (!IS_NULL_err(e)) {
1276
		int sev = DEREF_int(err_severity(e));
1277
		if (sev > ERROR_WARNING) {
1278
			string s;
1279
			BUFFER *bf = clear_buffer(&print_buff, NIL(FILE));
1280
			if (loc) {
1281
				IGNORE print_loc(loc, NIL(LOCATION), bf, 0);
1282
				bfprintf(bf, ": ");
1283
			}
1284
			print_error_body(e, loc, bf);
1285
			bfputc(bf, 0);
1286
			s = xustrcpy(bf->start);
1287
			MAKE_exp_fail(type_bottom, s, a);
1288
		}
1289
		destroy_error(e, 1);
2 7u83 1290
	}
6 7u83 1291
	return (a);
2 7u83 1292
}
1293
 
1294
 
1295
/*
1296
    PRINT A SIMPLE ERROR
1297
 
1298
    This routine prints a simple error message at the current location of
1299
    severity sev given by the printf style string s.  Any extra arguments
1300
    needed by s should also be given.
1301
*/
1302
 
6 7u83 1303
void
1304
error(int sev, CONST char *s, ...) /* VARARGS */
2 7u83 1305
{
6 7u83 1306
	va_list args;
2 7u83 1307
#if FS_STDARG
6 7u83 1308
	va_start(args, s);
2 7u83 1309
#else
6 7u83 1310
	int sev;
1311
	CONST char *s;
1312
	va_start(args);
1313
	sev = va_arg(args, int);
1314
	s = va_arg(args, CONST char *);
2 7u83 1315
#endif
6 7u83 1316
	if (sev > error_threshold) {
1317
		FILE *f = error_file;
1318
		print_error_start(f, NIL(LOCATION), sev);
1319
		vfprintf_v(f, s, args);
1320
		fputs_v(MESSAGE_END, f);
1321
		print_error_end(f, sev);
1322
	}
1323
	va_end(args);
1324
	return;
2 7u83 1325
}
1326
 
1327
 
1328
/*
1329
    PRINT A RUNNING COMMENTARY
1330
 
1331
    This routine is used in verbose mode to print a running commentary of
1332
    the compilation of the object id.
1333
*/
1334
 
6 7u83 1335
void
1336
commentary(IDENTIFIER id)
2 7u83 1337
{
6 7u83 1338
	if (verbose && !IS_NULL_id(id)) {
1339
		BUFFER *bf = clear_buffer(&print_buff, stdout);
1340
		print_id_desc++;
1341
		IGNORE print_id_long(id, qual_none, bf, 0);
1342
		print_id_desc--;
1343
		bfprintf(bf, " ;\n");
1344
		output_buffer(bf, 1);
1345
	}
1346
	return;
2 7u83 1347
}
1348
 
1349
 
1350
/*
1351
    PRINT AN ASSERTION
1352
 
1353
    The routine assertion prints the assertion s which occurred at the
1354
    location given by file and line.  The routine is_true is used to
1355
    check whether the condition of an assertion is false.
1356
*/
1357
 
1358
#ifdef ASSERTS
1359
 
6 7u83 1360
void
1361
assertion(CONST char *s, CONST char *file, int line)
2 7u83 1362
{
6 7u83 1363
	FILE *f = error_file;
1364
	PRINT_HEADER(HEADER_ASSERT, &crt_loc, f);
1365
	fprintf_v(f, "  %s, %s: line %d.\n\n", s, file, line);
1366
	error_break();
1367
	abort();
2 7u83 1368
}
1369
 
6 7u83 1370
int
1371
is_true(int c)
2 7u83 1372
{
6 7u83 1373
	return (c);
2 7u83 1374
}
1375
 
1376
#endif