1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin /*
24*4887Schin  * Glenn Fowler
25*4887Schin  * AT&T Research
26*4887Schin  *
27*4887Schin  * error and message formatter
28*4887Schin  *
29*4887Schin  *	level is the error level
30*4887Schin  *	level >= error_info.core!=0 dumps core
31*4887Schin  *	level >= ERROR_FATAL calls error_info.exit
32*4887Schin  *	level < 0 is for debug tracing
33*4887Schin  *
34*4887Schin  * NOTE: id && ERROR_NOID && !ERROR_USAGE implies format=id for errmsg()
35*4887Schin  */
36*4887Schin 
37*4887Schin #include "lclib.h"
38*4887Schin 
39*4887Schin #include <ctype.h>
40*4887Schin #include <ccode.h>
41*4887Schin #include <namval.h>
42*4887Schin #include <sig.h>
43*4887Schin #include <stk.h>
44*4887Schin #include <times.h>
45*4887Schin #include <regex.h>
46*4887Schin 
47*4887Schin /*
48*4887Schin  * 2007-03-19 move error_info from _error_info_ to (*_error_infop_)
49*4887Schin  *	      to allow future Error_info_t growth
50*4887Schin  *            by 2009 _error_info_ can be static
51*4887Schin  */
52*4887Schin 
53*4887Schin #if _BLD_ast && defined(__EXPORT__)
54*4887Schin #define extern		extern __EXPORT__
55*4887Schin #endif
56*4887Schin 
57*4887Schin extern Error_info_t	_error_info_;
58*4887Schin 
59*4887Schin Error_info_t	_error_info_ =
60*4887Schin {
61*4887Schin 	2, exit, write,
62*4887Schin 	0,0,0,0,0,0,0,0,
63*4887Schin 	0,			/* version			*/
64*4887Schin 	0,			/* auxilliary			*/
65*4887Schin 	0,0,0,0,0,0,0,		/* top of old context stack	*/
66*4887Schin 	0,0,0,0,0,0,0,		/* old empty context		*/
67*4887Schin 	0,			/* time				*/
68*4887Schin 	translate,
69*4887Schin 	0			/* catalog			*/
70*4887Schin };
71*4887Schin 
72*4887Schin #undef	extern
73*4887Schin 
74*4887Schin __EXTERN__(Error_info_t, _error_info_);
75*4887Schin 
76*4887Schin __EXTERN__(Error_info_t*, _error_infop_);
77*4887Schin 
78*4887Schin Error_info_t*	_error_infop_ = &_error_info_;
79*4887Schin 
80*4887Schin /*
81*4887Schin  * these should probably be in error_info
82*4887Schin  */
83*4887Schin 
84*4887Schin static struct State_s
85*4887Schin {
86*4887Schin 	char*		prefix;
87*4887Schin 	Sfio_t*		tty;
88*4887Schin 	unsigned long	count;
89*4887Schin 	int		breakpoint;
90*4887Schin 	regex_t*	match;
91*4887Schin } error_state;
92*4887Schin 
93*4887Schin #undef	ERROR_CATALOG
94*4887Schin #define ERROR_CATALOG	(ERROR_LIBRARY<<1)
95*4887Schin 
96*4887Schin #define OPT_BREAK	1
97*4887Schin #define OPT_CATALOG	2
98*4887Schin #define OPT_CORE	3
99*4887Schin #define OPT_COUNT	4
100*4887Schin #define OPT_FD		5
101*4887Schin #define OPT_LIBRARY	6
102*4887Schin #define OPT_MASK	7
103*4887Schin #define OPT_MATCH	8
104*4887Schin #define OPT_PREFIX	9
105*4887Schin #define OPT_SYSTEM	10
106*4887Schin #define OPT_TIME	11
107*4887Schin #define OPT_TRACE	12
108*4887Schin 
109*4887Schin static const Namval_t		options[] =
110*4887Schin {
111*4887Schin 	"break",	OPT_BREAK,
112*4887Schin 	"catalog",	OPT_CATALOG,
113*4887Schin 	"core",		OPT_CORE,
114*4887Schin 	"count",	OPT_COUNT,
115*4887Schin 	"debug",	OPT_TRACE,
116*4887Schin 	"fd",		OPT_FD,
117*4887Schin 	"library",	OPT_LIBRARY,
118*4887Schin 	"mask",		OPT_MASK,
119*4887Schin 	"match",	OPT_MATCH,
120*4887Schin 	"prefix",	OPT_PREFIX,
121*4887Schin 	"system",	OPT_SYSTEM,
122*4887Schin 	"time",		OPT_TIME,
123*4887Schin 	"trace",	OPT_TRACE,
124*4887Schin 	0,		0
125*4887Schin };
126*4887Schin 
127*4887Schin /*
128*4887Schin  * called by stropt() to set options
129*4887Schin  */
130*4887Schin 
131*4887Schin static int
132*4887Schin setopt(void* a, const void* p, register int n, register const char* v)
133*4887Schin {
134*4887Schin 	NoP(a);
135*4887Schin 	if (p)
136*4887Schin 		switch (((Namval_t*)p)->value)
137*4887Schin 		{
138*4887Schin 		case OPT_BREAK:
139*4887Schin 		case OPT_CORE:
140*4887Schin 			if (n)
141*4887Schin 				switch (*v)
142*4887Schin 				{
143*4887Schin 				case 'e':
144*4887Schin 				case 'E':
145*4887Schin 					error_state.breakpoint = ERROR_ERROR;
146*4887Schin 					break;
147*4887Schin 				case 'f':
148*4887Schin 				case 'F':
149*4887Schin 					error_state.breakpoint = ERROR_FATAL;
150*4887Schin 					break;
151*4887Schin 				case 'p':
152*4887Schin 				case 'P':
153*4887Schin 					error_state.breakpoint = ERROR_PANIC;
154*4887Schin 					break;
155*4887Schin 				default:
156*4887Schin 					error_state.breakpoint = strtol(v, NiL, 0);
157*4887Schin 					break;
158*4887Schin 				}
159*4887Schin 			else
160*4887Schin 				error_state.breakpoint = 0;
161*4887Schin 			if (((Namval_t*)p)->value == OPT_CORE)
162*4887Schin 				error_info.core = error_state.breakpoint;
163*4887Schin 			break;
164*4887Schin 		case OPT_CATALOG:
165*4887Schin 			if (n)
166*4887Schin 				error_info.set |= ERROR_CATALOG;
167*4887Schin 			else
168*4887Schin 				error_info.clear |= ERROR_CATALOG;
169*4887Schin 			break;
170*4887Schin 		case OPT_COUNT:
171*4887Schin 			if (n)
172*4887Schin 				error_state.count = strtol(v, NiL, 0);
173*4887Schin 			else
174*4887Schin 				error_state.count = 0;
175*4887Schin 			break;
176*4887Schin 		case OPT_FD:
177*4887Schin 			error_info.fd = n ? strtol(v, NiL, 0) : -1;
178*4887Schin 			break;
179*4887Schin 		case OPT_LIBRARY:
180*4887Schin 			if (n)
181*4887Schin 				error_info.set |= ERROR_LIBRARY;
182*4887Schin 			else
183*4887Schin 				error_info.clear |= ERROR_LIBRARY;
184*4887Schin 			break;
185*4887Schin 		case OPT_MASK:
186*4887Schin 			if (n)
187*4887Schin 				error_info.mask = strtol(v, NiL, 0);
188*4887Schin 			else
189*4887Schin 				error_info.mask = 0;
190*4887Schin 			break;
191*4887Schin 		case OPT_MATCH:
192*4887Schin 			if (error_state.match)
193*4887Schin 				regfree(error_state.match);
194*4887Schin 			if (n)
195*4887Schin 			{
196*4887Schin 				if ((error_state.match || (error_state.match = newof(0, regex_t, 1, 0))) && regcomp(error_state.match, v, REG_EXTENDED|REG_LENIENT))
197*4887Schin 				{
198*4887Schin 					free(error_state.match);
199*4887Schin 					error_state.match = 0;
200*4887Schin 				}
201*4887Schin 			}
202*4887Schin 			else if (error_state.match)
203*4887Schin 			{
204*4887Schin 				free(error_state.match);
205*4887Schin 				error_state.match = 0;
206*4887Schin 			}
207*4887Schin 			break;
208*4887Schin 		case OPT_PREFIX:
209*4887Schin 			if (n)
210*4887Schin 				error_state.prefix = strdup(v);
211*4887Schin 			else if (error_state.prefix)
212*4887Schin 			{
213*4887Schin 				free(error_state.prefix);
214*4887Schin 				error_state.prefix = 0;
215*4887Schin 			}
216*4887Schin 			break;
217*4887Schin 		case OPT_SYSTEM:
218*4887Schin 			if (n)
219*4887Schin 				error_info.set |= ERROR_SYSTEM;
220*4887Schin 			else
221*4887Schin 				error_info.clear |= ERROR_SYSTEM;
222*4887Schin 			break;
223*4887Schin 		case OPT_TIME:
224*4887Schin 			error_info.time = n ? 1 : 0;
225*4887Schin 			break;
226*4887Schin 		case OPT_TRACE:
227*4887Schin 			if (n)
228*4887Schin 				error_info.trace = -strtol(v, NiL, 0);
229*4887Schin 			else
230*4887Schin 				error_info.trace = 0;
231*4887Schin 			break;
232*4887Schin 		}
233*4887Schin 	return 0;
234*4887Schin }
235*4887Schin 
236*4887Schin /*
237*4887Schin  * print a name with optional delimiter, converting unprintable chars
238*4887Schin  */
239*4887Schin 
240*4887Schin static void
241*4887Schin print(register Sfio_t* sp, register char* name, char* delim)
242*4887Schin {
243*4887Schin 	if (mbwide())
244*4887Schin 		sfputr(sp, name, -1);
245*4887Schin 	else
246*4887Schin 	{
247*4887Schin #if CC_NATIVE != CC_ASCII
248*4887Schin 		register int		c;
249*4887Schin 		register unsigned char*	n2a;
250*4887Schin 		register unsigned char*	a2n;
251*4887Schin 		register int		aa;
252*4887Schin 		register int		as;
253*4887Schin 
254*4887Schin 		n2a = ccmap(CC_NATIVE, CC_ASCII);
255*4887Schin 		a2n = ccmap(CC_ASCII, CC_NATIVE);
256*4887Schin 		aa = n2a['A'];
257*4887Schin 		as = n2a[' '];
258*4887Schin 		while (c = *name++)
259*4887Schin 		{
260*4887Schin 			c = n2a[c];
261*4887Schin 			if (c & 0200)
262*4887Schin 			{
263*4887Schin 				c &= 0177;
264*4887Schin 				sfputc(sp, '?');
265*4887Schin 			}
266*4887Schin 			if (c < as)
267*4887Schin 			{
268*4887Schin 				c += aa - 1;
269*4887Schin 				sfputc(sp, '^');
270*4887Schin 			}
271*4887Schin 			c = a2n[c];
272*4887Schin 			sfputc(sp, c);
273*4887Schin 		}
274*4887Schin #else
275*4887Schin 		register int		c;
276*4887Schin 
277*4887Schin 		while (c = *name++)
278*4887Schin 		{
279*4887Schin 			if (c & 0200)
280*4887Schin 			{
281*4887Schin 				c &= 0177;
282*4887Schin 				sfputc(sp, '?');
283*4887Schin 			}
284*4887Schin 			if (c < ' ')
285*4887Schin 			{
286*4887Schin 				c += 'A' - 1;
287*4887Schin 				sfputc(sp, '^');
288*4887Schin 			}
289*4887Schin 			sfputc(sp, c);
290*4887Schin 		}
291*4887Schin #endif
292*4887Schin 	}
293*4887Schin 	if (delim)
294*4887Schin 		sfputr(sp, delim, -1);
295*4887Schin }
296*4887Schin 
297*4887Schin /*
298*4887Schin  * print error context FIFO stack
299*4887Schin  */
300*4887Schin 
301*4887Schin #define CONTEXT(f,p)	(((f)&ERROR_PUSH)?((Error_context_t*)&(p)->context->context):((Error_context_t*)(p)))
302*4887Schin 
303*4887Schin static void
304*4887Schin context(register Sfio_t* sp, register Error_context_t* cp)
305*4887Schin {
306*4887Schin 	if (cp->context)
307*4887Schin 		context(sp, CONTEXT(cp->flags, cp->context));
308*4887Schin 	if (!(cp->flags & ERROR_SILENT))
309*4887Schin 	{
310*4887Schin 		if (cp->id)
311*4887Schin 			print(sp, cp->id, NiL);
312*4887Schin 		if (cp->line > ((cp->flags & ERROR_INTERACTIVE) != 0))
313*4887Schin 		{
314*4887Schin 			if (cp->file)
315*4887Schin 				sfprintf(sp, ": \"%s\", %s %d", cp->file, ERROR_translate(NiL, NiL, ast.id, "line"), cp->line);
316*4887Schin 			else
317*4887Schin 				sfprintf(sp, "[%d]", cp->line);
318*4887Schin 		}
319*4887Schin 		sfputr(sp, ": ", -1);
320*4887Schin 	}
321*4887Schin }
322*4887Schin 
323*4887Schin /*
324*4887Schin  * debugging breakpoint
325*4887Schin  */
326*4887Schin 
327*4887Schin extern void
328*4887Schin error_break(void)
329*4887Schin {
330*4887Schin 	char*	s;
331*4887Schin 
332*4887Schin 	if (error_state.tty || (error_state.tty = sfopen(NiL, "/dev/tty", "r+")))
333*4887Schin 	{
334*4887Schin 		sfprintf(error_state.tty, "error breakpoint: ");
335*4887Schin 		if (s = sfgetr(error_state.tty, '\n', 1))
336*4887Schin 		{
337*4887Schin 			if (streq(s, "q") || streq(s, "quit"))
338*4887Schin 				exit(0);
339*4887Schin 			stropt(s, options, sizeof(*options), setopt, NiL);
340*4887Schin 		}
341*4887Schin 	}
342*4887Schin }
343*4887Schin 
344*4887Schin void
345*4887Schin error(int level, ...)
346*4887Schin {
347*4887Schin 	va_list	ap;
348*4887Schin 
349*4887Schin 	va_start(ap, level);
350*4887Schin 	errorv(NiL, level, ap);
351*4887Schin 	va_end(ap);
352*4887Schin }
353*4887Schin 
354*4887Schin void
355*4887Schin errorv(const char* id, int level, va_list ap)
356*4887Schin {
357*4887Schin 	register int	n;
358*4887Schin 	int		fd;
359*4887Schin 	int		flags;
360*4887Schin 	char*		s;
361*4887Schin 	char*		t;
362*4887Schin 	char*		format;
363*4887Schin 	char*		library;
364*4887Schin 	const char*	catalog;
365*4887Schin 
366*4887Schin 	int		line;
367*4887Schin 	char*		file;
368*4887Schin 
369*4887Schin #if !_PACKAGE_astsa
370*4887Schin 	unsigned long	d;
371*4887Schin 	struct tms	us;
372*4887Schin #endif
373*4887Schin 
374*4887Schin 	if (!error_info.init)
375*4887Schin 	{
376*4887Schin 		error_info.init = 1;
377*4887Schin 		stropt(getenv("ERROR_OPTIONS"), options, sizeof(*options), setopt, NiL);
378*4887Schin 	}
379*4887Schin 	if (level > 0)
380*4887Schin 	{
381*4887Schin 		flags = level & ~ERROR_LEVEL;
382*4887Schin 		level &= ERROR_LEVEL;
383*4887Schin 	}
384*4887Schin 	else
385*4887Schin 		flags = 0;
386*4887Schin 	if ((flags & (ERROR_USAGE|ERROR_NOID)) == ERROR_NOID)
387*4887Schin 	{
388*4887Schin 		format = (char*)id;
389*4887Schin 		id = 0;
390*4887Schin 	}
391*4887Schin 	else
392*4887Schin 		format = 0;
393*4887Schin 	if (id)
394*4887Schin 	{
395*4887Schin 		catalog = (char*)id;
396*4887Schin 		if (!*catalog || *catalog == ':')
397*4887Schin 		{
398*4887Schin 			catalog = 0;
399*4887Schin 			library = 0;
400*4887Schin 		}
401*4887Schin 		else if ((library = strchr(catalog, ':')) && !*++library)
402*4887Schin 			library = 0;
403*4887Schin 	}
404*4887Schin 	else
405*4887Schin 	{
406*4887Schin 		catalog = 0;
407*4887Schin 		library = 0;
408*4887Schin 	}
409*4887Schin 	if (catalog)
410*4887Schin 		id = 0;
411*4887Schin 	else
412*4887Schin 	{
413*4887Schin 		id = (const char*)error_info.id;
414*4887Schin 		catalog = error_info.catalog;
415*4887Schin 	}
416*4887Schin 	if (level < error_info.trace || (flags & ERROR_LIBRARY) && !(((error_info.set | error_info.flags) ^ error_info.clear) & ERROR_LIBRARY) || level < 0 && error_info.mask && !(error_info.mask & (1<<(-level - 1))))
417*4887Schin 	{
418*4887Schin 		if (level >= ERROR_FATAL)
419*4887Schin 			(*error_info.exit)(level - 1);
420*4887Schin 		return;
421*4887Schin 	}
422*4887Schin 	if (error_info.trace < 0)
423*4887Schin 		flags |= ERROR_LIBRARY|ERROR_SYSTEM;
424*4887Schin 	flags |= error_info.set | error_info.flags;
425*4887Schin 	flags &= ~error_info.clear;
426*4887Schin 	if (!library)
427*4887Schin 		flags &= ~ERROR_LIBRARY;
428*4887Schin 	fd = (flags & ERROR_OUTPUT) ? va_arg(ap, int) : error_info.fd;
429*4887Schin 	if (error_info.write)
430*4887Schin 	{
431*4887Schin 		long	off;
432*4887Schin 		char*	bas;
433*4887Schin 
434*4887Schin 		bas = stkptr(stkstd, 0);
435*4887Schin 		if (off = stktell(stkstd))
436*4887Schin 			stkfreeze(stkstd, 0);
437*4887Schin 		file = error_info.id;
438*4887Schin 		if (error_state.prefix)
439*4887Schin 			sfprintf(stkstd, "%s: ", error_state.prefix);
440*4887Schin 		if (flags & ERROR_USAGE)
441*4887Schin 		{
442*4887Schin 			if (flags & ERROR_NOID)
443*4887Schin 				sfprintf(stkstd, "       ");
444*4887Schin 			else
445*4887Schin 				sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "Usage"));
446*4887Schin 			if (file || opt_info.argv && (file = opt_info.argv[0]))
447*4887Schin 				print(stkstd, file, " ");
448*4887Schin 		}
449*4887Schin 		else
450*4887Schin 		{
451*4887Schin 			if (level && !(flags & ERROR_NOID))
452*4887Schin 			{
453*4887Schin 				if (error_info.context && level > 0)
454*4887Schin 					context(stkstd, CONTEXT(error_info.flags, error_info.context));
455*4887Schin 				if (file)
456*4887Schin 					print(stkstd, file, (flags & ERROR_LIBRARY) ? " " : ": ");
457*4887Schin 				if (flags & (ERROR_CATALOG|ERROR_LIBRARY))
458*4887Schin 				{
459*4887Schin 					sfprintf(stkstd, "[");
460*4887Schin 					if (flags & ERROR_CATALOG)
461*4887Schin 						sfprintf(stkstd, "%s %s%s",
462*4887Schin 							catalog ? catalog : ERROR_translate(NiL, NiL, ast.id, "DEFAULT"),
463*4887Schin 							ERROR_translate(NiL, NiL, ast.id, "catalog"),
464*4887Schin 							(flags & ERROR_LIBRARY) ? ", " : "");
465*4887Schin 					if (flags & ERROR_LIBRARY)
466*4887Schin 						sfprintf(stkstd, "%s %s",
467*4887Schin 							library,
468*4887Schin 							ERROR_translate(NiL, NiL, ast.id, "library"));
469*4887Schin 					sfprintf(stkstd, "]: ");
470*4887Schin 				}
471*4887Schin 			}
472*4887Schin 			if (level > 0 && error_info.line > ((flags & ERROR_INTERACTIVE) != 0))
473*4887Schin 			{
474*4887Schin 				if (error_info.file && *error_info.file)
475*4887Schin 					sfprintf(stkstd, "\"%s\", ", error_info.file);
476*4887Schin 				sfprintf(stkstd, "%s %d: ", ERROR_translate(NiL, NiL, ast.id, "line"), error_info.line);
477*4887Schin 			}
478*4887Schin 		}
479*4887Schin #if !_PACKAGE_astsa
480*4887Schin 		if (error_info.time)
481*4887Schin 		{
482*4887Schin 			if ((d = times(&us)) < error_info.time || error_info.time == 1)
483*4887Schin 				error_info.time = d;
484*4887Schin 			sfprintf(stkstd, " %05lu.%05lu.%05lu ", d - error_info.time, (unsigned long)us.tms_utime, (unsigned long)us.tms_stime);
485*4887Schin 		}
486*4887Schin #endif
487*4887Schin 		switch (level)
488*4887Schin 		{
489*4887Schin 		case 0:
490*4887Schin 			flags &= ~ERROR_SYSTEM;
491*4887Schin 			break;
492*4887Schin 		case ERROR_WARNING:
493*4887Schin 			sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "warning"));
494*4887Schin 			break;
495*4887Schin 		case ERROR_PANIC:
496*4887Schin 			sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "panic"));
497*4887Schin 			break;
498*4887Schin 		default:
499*4887Schin 			if (level < 0)
500*4887Schin 			{
501*4887Schin 				s = ERROR_translate(NiL, NiL, ast.id, "debug");
502*4887Schin 				if (error_info.trace < -1)
503*4887Schin 					sfprintf(stkstd, "%s%d:%s", s, level, level > -10 ? " " : "");
504*4887Schin 				else
505*4887Schin 					sfprintf(stkstd, "%s: ", s);
506*4887Schin 				for (n = 0; n < error_info.indent; n++)
507*4887Schin 				{
508*4887Schin 					sfputc(stkstd, ' ');
509*4887Schin 					sfputc(stkstd, ' ');
510*4887Schin 				}
511*4887Schin 			}
512*4887Schin 			break;
513*4887Schin 		}
514*4887Schin 		if (flags & ERROR_SOURCE)
515*4887Schin 		{
516*4887Schin 			/*
517*4887Schin 			 * source ([version], file, line) message
518*4887Schin 			 */
519*4887Schin 
520*4887Schin 			file = va_arg(ap, char*);
521*4887Schin 			line = va_arg(ap, int);
522*4887Schin 			s = ERROR_translate(NiL, NiL, ast.id, "line");
523*4887Schin 			if (error_info.version)
524*4887Schin 				sfprintf(stkstd, "(%s: \"%s\", %s %d) ", error_info.version, file, s, line);
525*4887Schin 			else
526*4887Schin 				sfprintf(stkstd, "(\"%s\", %s %d) ", file, s, line);
527*4887Schin 		}
528*4887Schin 		if (format || (format = va_arg(ap, char*)))
529*4887Schin 		{
530*4887Schin 			if (!(flags & ERROR_USAGE))
531*4887Schin 				format = ERROR_translate(NiL, id, catalog, format);
532*4887Schin 			sfvprintf(stkstd, format, ap);
533*4887Schin 		}
534*4887Schin 		if (!(flags & ERROR_PROMPT))
535*4887Schin 		{
536*4887Schin 			/*
537*4887Schin 			 * level&ERROR_OUTPUT on return means message
538*4887Schin 			 * already output
539*4887Schin 			 */
540*4887Schin 
541*4887Schin 			if ((flags & ERROR_SYSTEM) && errno && errno != error_info.last_errno)
542*4887Schin 			{
543*4887Schin 				sfprintf(stkstd, " [%s]", fmterror(errno));
544*4887Schin 				if (error_info.set & ERROR_SYSTEM)
545*4887Schin 					errno = 0;
546*4887Schin 				error_info.last_errno = (level >= 0) ? 0 : errno;
547*4887Schin 			}
548*4887Schin 			if (error_info.auxilliary && level >= 0)
549*4887Schin 				level = (*error_info.auxilliary)(stkstd, level, flags);
550*4887Schin 			sfputc(stkstd, '\n');
551*4887Schin 		}
552*4887Schin 		if (level > 0)
553*4887Schin 		{
554*4887Schin 			if ((level & ~ERROR_OUTPUT) > 1)
555*4887Schin 				error_info.errors++;
556*4887Schin 			else
557*4887Schin 				error_info.warnings++;
558*4887Schin 		}
559*4887Schin 		if (level < 0 || !(level & ERROR_OUTPUT))
560*4887Schin 		{
561*4887Schin 			n = stktell(stkstd);
562*4887Schin 			s = stkptr(stkstd, 0);
563*4887Schin 			if (t = memchr(s, '\f', n))
564*4887Schin 			{
565*4887Schin 				n -= ++t - s;
566*4887Schin 				s = t;
567*4887Schin 			}
568*4887Schin #if HUH_19980401 /* nasty problems if sfgetr() is in effect! */
569*4887Schin 			sfsync(sfstdin);
570*4887Schin #endif
571*4887Schin 			sfsync(sfstdout);
572*4887Schin 			sfsync(sfstderr);
573*4887Schin 			if (fd == sffileno(sfstderr) && error_info.write == write)
574*4887Schin 			{
575*4887Schin 				sfwrite(sfstderr, s, n);
576*4887Schin 				sfsync(sfstderr);
577*4887Schin 			}
578*4887Schin 			else
579*4887Schin 				(*error_info.write)(fd, s, n);
580*4887Schin 		}
581*4887Schin 		else
582*4887Schin 		{
583*4887Schin 			s = 0;
584*4887Schin 			level &= ERROR_LEVEL;
585*4887Schin 		}
586*4887Schin 		stkset(stkstd, bas, off);
587*4887Schin 	}
588*4887Schin 	else
589*4887Schin 		s = 0;
590*4887Schin 	if (level >= error_state.breakpoint && error_state.breakpoint && (!error_state.match || !regexec(error_state.match, s ? s : format, 0, NiL, 0)) && (!error_state.count || !--error_state.count))
591*4887Schin 	{
592*4887Schin 		if (error_info.core)
593*4887Schin 		{
594*4887Schin #ifndef SIGABRT
595*4887Schin #ifdef	SIGQUIT
596*4887Schin #define SIGABRT	SIGQUIT
597*4887Schin #else
598*4887Schin #ifdef	SIGIOT
599*4887Schin #define SIGABRT	SIGIOT
600*4887Schin #endif
601*4887Schin #endif
602*4887Schin #endif
603*4887Schin #ifdef	SIGABRT
604*4887Schin 			signal(SIGABRT, SIG_DFL);
605*4887Schin 			kill(getpid(), SIGABRT);
606*4887Schin 			pause();
607*4887Schin #else
608*4887Schin 			abort();
609*4887Schin #endif
610*4887Schin 		}
611*4887Schin 		else
612*4887Schin 			error_break();
613*4887Schin 	}
614*4887Schin 	if (level >= ERROR_FATAL)
615*4887Schin 		(*error_info.exit)(level - ERROR_FATAL + 1);
616*4887Schin }
617*4887Schin 
618*4887Schin /*
619*4887Schin  * error_info context control
620*4887Schin  */
621*4887Schin 
622*4887Schin #include <error.h>
623*4887Schin 
624*4887Schin static Error_info_t*	freecontext;
625*4887Schin 
626*4887Schin Error_info_t*
627*4887Schin errorctx(Error_info_t* p, int op, int flags)
628*4887Schin {
629*4887Schin 	if (op & ERROR_POP)
630*4887Schin 	{
631*4887Schin 		if (!(_error_infop_ = p->context))
632*4887Schin 			_error_infop_ = &_error_info_;
633*4887Schin 		if (op & ERROR_FREE)
634*4887Schin 		{
635*4887Schin 			p->context = freecontext;
636*4887Schin 			freecontext = p;
637*4887Schin 		}
638*4887Schin 		p = _error_infop_;
639*4887Schin 	}
640*4887Schin 	else
641*4887Schin 	{
642*4887Schin 		if (!p)
643*4887Schin 		{
644*4887Schin 			if (p = freecontext)
645*4887Schin 				freecontext = freecontext->context;
646*4887Schin 			else if (!(p = newof(0, Error_info_t, 1, 0)))
647*4887Schin 				return 0;
648*4887Schin 			*p = *_error_infop_;
649*4887Schin 			p->errors = p->flags = p->line = p->warnings = 0;
650*4887Schin 			p->catalog = p->file = 0;
651*4887Schin 		}
652*4887Schin 		if (op & ERROR_PUSH)
653*4887Schin 		{
654*4887Schin 			p->flags = flags;
655*4887Schin 			p->context = _error_infop_;
656*4887Schin 			_error_infop_ = p;
657*4887Schin 		}
658*4887Schin 		p->flags |= ERROR_PUSH;
659*4887Schin 	}
660*4887Schin 	return p;
661*4887Schin }
662