xref: /onnv-gate/usr/src/lib/libast/common/misc/error.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * error and message formatter
284887Schin  *
294887Schin  *	level is the error level
304887Schin  *	level >= error_info.core!=0 dumps core
314887Schin  *	level >= ERROR_FATAL calls error_info.exit
324887Schin  *	level < 0 is for debug tracing
334887Schin  *
344887Schin  * NOTE: id && ERROR_NOID && !ERROR_USAGE implies format=id for errmsg()
354887Schin  */
364887Schin 
374887Schin #include "lclib.h"
384887Schin 
394887Schin #include <ctype.h>
404887Schin #include <ccode.h>
414887Schin #include <namval.h>
424887Schin #include <sig.h>
434887Schin #include <stk.h>
444887Schin #include <times.h>
454887Schin #include <regex.h>
464887Schin 
474887Schin /*
484887Schin  * 2007-03-19 move error_info from _error_info_ to (*_error_infop_)
494887Schin  *	      to allow future Error_info_t growth
504887Schin  *            by 2009 _error_info_ can be static
514887Schin  */
524887Schin 
534887Schin #if _BLD_ast && defined(__EXPORT__)
544887Schin #define extern		extern __EXPORT__
554887Schin #endif
564887Schin 
574887Schin extern Error_info_t	_error_info_;
584887Schin 
594887Schin Error_info_t	_error_info_ =
604887Schin {
614887Schin 	2, exit, write,
624887Schin 	0,0,0,0,0,0,0,0,
634887Schin 	0,			/* version			*/
644887Schin 	0,			/* auxilliary			*/
654887Schin 	0,0,0,0,0,0,0,		/* top of old context stack	*/
664887Schin 	0,0,0,0,0,0,0,		/* old empty context		*/
674887Schin 	0,			/* time				*/
684887Schin 	translate,
694887Schin 	0			/* catalog			*/
704887Schin };
714887Schin 
724887Schin #undef	extern
734887Schin 
744887Schin __EXTERN__(Error_info_t, _error_info_);
754887Schin 
764887Schin __EXTERN__(Error_info_t*, _error_infop_);
774887Schin 
784887Schin Error_info_t*	_error_infop_ = &_error_info_;
794887Schin 
804887Schin /*
814887Schin  * these should probably be in error_info
824887Schin  */
834887Schin 
844887Schin static struct State_s
854887Schin {
864887Schin 	char*		prefix;
874887Schin 	Sfio_t*		tty;
884887Schin 	unsigned long	count;
894887Schin 	int		breakpoint;
904887Schin 	regex_t*	match;
914887Schin } error_state;
924887Schin 
934887Schin #undef	ERROR_CATALOG
944887Schin #define ERROR_CATALOG	(ERROR_LIBRARY<<1)
954887Schin 
964887Schin #define OPT_BREAK	1
974887Schin #define OPT_CATALOG	2
984887Schin #define OPT_CORE	3
994887Schin #define OPT_COUNT	4
1004887Schin #define OPT_FD		5
1014887Schin #define OPT_LIBRARY	6
1024887Schin #define OPT_MASK	7
1034887Schin #define OPT_MATCH	8
1044887Schin #define OPT_PREFIX	9
1054887Schin #define OPT_SYSTEM	10
1064887Schin #define OPT_TIME	11
1074887Schin #define OPT_TRACE	12
1084887Schin 
1094887Schin static const Namval_t		options[] =
1104887Schin {
1114887Schin 	"break",	OPT_BREAK,
1124887Schin 	"catalog",	OPT_CATALOG,
1134887Schin 	"core",		OPT_CORE,
1144887Schin 	"count",	OPT_COUNT,
1154887Schin 	"debug",	OPT_TRACE,
1164887Schin 	"fd",		OPT_FD,
1174887Schin 	"library",	OPT_LIBRARY,
1184887Schin 	"mask",		OPT_MASK,
1194887Schin 	"match",	OPT_MATCH,
1204887Schin 	"prefix",	OPT_PREFIX,
1214887Schin 	"system",	OPT_SYSTEM,
1224887Schin 	"time",		OPT_TIME,
1234887Schin 	"trace",	OPT_TRACE,
1244887Schin 	0,		0
1254887Schin };
1264887Schin 
1274887Schin /*
1284887Schin  * called by stropt() to set options
1294887Schin  */
1304887Schin 
1314887Schin static int
setopt(void * a,const void * p,register int n,register const char * v)1324887Schin setopt(void* a, const void* p, register int n, register const char* v)
1334887Schin {
1344887Schin 	NoP(a);
1354887Schin 	if (p)
1364887Schin 		switch (((Namval_t*)p)->value)
1374887Schin 		{
1384887Schin 		case OPT_BREAK:
1394887Schin 		case OPT_CORE:
1404887Schin 			if (n)
1414887Schin 				switch (*v)
1424887Schin 				{
1434887Schin 				case 'e':
1444887Schin 				case 'E':
1454887Schin 					error_state.breakpoint = ERROR_ERROR;
1464887Schin 					break;
1474887Schin 				case 'f':
1484887Schin 				case 'F':
1494887Schin 					error_state.breakpoint = ERROR_FATAL;
1504887Schin 					break;
1514887Schin 				case 'p':
1524887Schin 				case 'P':
1534887Schin 					error_state.breakpoint = ERROR_PANIC;
1544887Schin 					break;
1554887Schin 				default:
1564887Schin 					error_state.breakpoint = strtol(v, NiL, 0);
1574887Schin 					break;
1584887Schin 				}
1594887Schin 			else
1604887Schin 				error_state.breakpoint = 0;
1614887Schin 			if (((Namval_t*)p)->value == OPT_CORE)
1624887Schin 				error_info.core = error_state.breakpoint;
1634887Schin 			break;
1644887Schin 		case OPT_CATALOG:
1654887Schin 			if (n)
1664887Schin 				error_info.set |= ERROR_CATALOG;
1674887Schin 			else
1684887Schin 				error_info.clear |= ERROR_CATALOG;
1694887Schin 			break;
1704887Schin 		case OPT_COUNT:
1714887Schin 			if (n)
1724887Schin 				error_state.count = strtol(v, NiL, 0);
1734887Schin 			else
1744887Schin 				error_state.count = 0;
1754887Schin 			break;
1764887Schin 		case OPT_FD:
1774887Schin 			error_info.fd = n ? strtol(v, NiL, 0) : -1;
1784887Schin 			break;
1794887Schin 		case OPT_LIBRARY:
1804887Schin 			if (n)
1814887Schin 				error_info.set |= ERROR_LIBRARY;
1824887Schin 			else
1834887Schin 				error_info.clear |= ERROR_LIBRARY;
1844887Schin 			break;
1854887Schin 		case OPT_MASK:
1864887Schin 			if (n)
1874887Schin 				error_info.mask = strtol(v, NiL, 0);
1884887Schin 			else
1894887Schin 				error_info.mask = 0;
1904887Schin 			break;
1914887Schin 		case OPT_MATCH:
1924887Schin 			if (error_state.match)
1934887Schin 				regfree(error_state.match);
1944887Schin 			if (n)
1954887Schin 			{
1964887Schin 				if ((error_state.match || (error_state.match = newof(0, regex_t, 1, 0))) && regcomp(error_state.match, v, REG_EXTENDED|REG_LENIENT))
1974887Schin 				{
1984887Schin 					free(error_state.match);
1994887Schin 					error_state.match = 0;
2004887Schin 				}
2014887Schin 			}
2024887Schin 			else if (error_state.match)
2034887Schin 			{
2044887Schin 				free(error_state.match);
2054887Schin 				error_state.match = 0;
2064887Schin 			}
2074887Schin 			break;
2084887Schin 		case OPT_PREFIX:
2094887Schin 			if (n)
2104887Schin 				error_state.prefix = strdup(v);
2114887Schin 			else if (error_state.prefix)
2124887Schin 			{
2134887Schin 				free(error_state.prefix);
2144887Schin 				error_state.prefix = 0;
2154887Schin 			}
2164887Schin 			break;
2174887Schin 		case OPT_SYSTEM:
2184887Schin 			if (n)
2194887Schin 				error_info.set |= ERROR_SYSTEM;
2204887Schin 			else
2214887Schin 				error_info.clear |= ERROR_SYSTEM;
2224887Schin 			break;
2234887Schin 		case OPT_TIME:
2244887Schin 			error_info.time = n ? 1 : 0;
2254887Schin 			break;
2264887Schin 		case OPT_TRACE:
2274887Schin 			if (n)
2284887Schin 				error_info.trace = -strtol(v, NiL, 0);
2294887Schin 			else
2304887Schin 				error_info.trace = 0;
2314887Schin 			break;
2324887Schin 		}
2334887Schin 	return 0;
2344887Schin }
2354887Schin 
2364887Schin /*
2374887Schin  * print a name with optional delimiter, converting unprintable chars
2384887Schin  */
2394887Schin 
2404887Schin static void
print(register Sfio_t * sp,register char * name,char * delim)2414887Schin print(register Sfio_t* sp, register char* name, char* delim)
2424887Schin {
2434887Schin 	if (mbwide())
2444887Schin 		sfputr(sp, name, -1);
2454887Schin 	else
2464887Schin 	{
2474887Schin #if CC_NATIVE != CC_ASCII
2484887Schin 		register int		c;
2494887Schin 		register unsigned char*	n2a;
2504887Schin 		register unsigned char*	a2n;
2514887Schin 		register int		aa;
2524887Schin 		register int		as;
2534887Schin 
2544887Schin 		n2a = ccmap(CC_NATIVE, CC_ASCII);
2554887Schin 		a2n = ccmap(CC_ASCII, CC_NATIVE);
2564887Schin 		aa = n2a['A'];
2574887Schin 		as = n2a[' '];
2584887Schin 		while (c = *name++)
2594887Schin 		{
2604887Schin 			c = n2a[c];
2614887Schin 			if (c & 0200)
2624887Schin 			{
2634887Schin 				c &= 0177;
2644887Schin 				sfputc(sp, '?');
2654887Schin 			}
2664887Schin 			if (c < as)
2674887Schin 			{
2684887Schin 				c += aa - 1;
2694887Schin 				sfputc(sp, '^');
2704887Schin 			}
2714887Schin 			c = a2n[c];
2724887Schin 			sfputc(sp, c);
2734887Schin 		}
2744887Schin #else
2754887Schin 		register int		c;
2764887Schin 
2774887Schin 		while (c = *name++)
2784887Schin 		{
2794887Schin 			if (c & 0200)
2804887Schin 			{
2814887Schin 				c &= 0177;
2824887Schin 				sfputc(sp, '?');
2834887Schin 			}
2844887Schin 			if (c < ' ')
2854887Schin 			{
2864887Schin 				c += 'A' - 1;
2874887Schin 				sfputc(sp, '^');
2884887Schin 			}
2894887Schin 			sfputc(sp, c);
2904887Schin 		}
2914887Schin #endif
2924887Schin 	}
2934887Schin 	if (delim)
2944887Schin 		sfputr(sp, delim, -1);
2954887Schin }
2964887Schin 
2974887Schin /*
2984887Schin  * print error context FIFO stack
2994887Schin  */
3004887Schin 
3014887Schin #define CONTEXT(f,p)	(((f)&ERROR_PUSH)?((Error_context_t*)&(p)->context->context):((Error_context_t*)(p)))
3024887Schin 
3034887Schin static void
context(register Sfio_t * sp,register Error_context_t * cp)3044887Schin context(register Sfio_t* sp, register Error_context_t* cp)
3054887Schin {
3064887Schin 	if (cp->context)
3074887Schin 		context(sp, CONTEXT(cp->flags, cp->context));
3084887Schin 	if (!(cp->flags & ERROR_SILENT))
3094887Schin 	{
3104887Schin 		if (cp->id)
3114887Schin 			print(sp, cp->id, NiL);
3124887Schin 		if (cp->line > ((cp->flags & ERROR_INTERACTIVE) != 0))
3134887Schin 		{
3144887Schin 			if (cp->file)
3154887Schin 				sfprintf(sp, ": \"%s\", %s %d", cp->file, ERROR_translate(NiL, NiL, ast.id, "line"), cp->line);
3164887Schin 			else
3174887Schin 				sfprintf(sp, "[%d]", cp->line);
3184887Schin 		}
3194887Schin 		sfputr(sp, ": ", -1);
3204887Schin 	}
3214887Schin }
3224887Schin 
3234887Schin /*
3244887Schin  * debugging breakpoint
3254887Schin  */
3264887Schin 
3274887Schin extern void
error_break(void)3284887Schin error_break(void)
3294887Schin {
3304887Schin 	char*	s;
3314887Schin 
3324887Schin 	if (error_state.tty || (error_state.tty = sfopen(NiL, "/dev/tty", "r+")))
3334887Schin 	{
3344887Schin 		sfprintf(error_state.tty, "error breakpoint: ");
3354887Schin 		if (s = sfgetr(error_state.tty, '\n', 1))
3364887Schin 		{
3374887Schin 			if (streq(s, "q") || streq(s, "quit"))
3384887Schin 				exit(0);
3394887Schin 			stropt(s, options, sizeof(*options), setopt, NiL);
3404887Schin 		}
3414887Schin 	}
3424887Schin }
3434887Schin 
3444887Schin void
error(int level,...)3454887Schin error(int level, ...)
3464887Schin {
3474887Schin 	va_list	ap;
3484887Schin 
3494887Schin 	va_start(ap, level);
3504887Schin 	errorv(NiL, level, ap);
3514887Schin 	va_end(ap);
3524887Schin }
3534887Schin 
3544887Schin void
errorv(const char * id,int level,va_list ap)3554887Schin errorv(const char* id, int level, va_list ap)
3564887Schin {
3574887Schin 	register int	n;
3584887Schin 	int		fd;
3594887Schin 	int		flags;
3604887Schin 	char*		s;
3614887Schin 	char*		t;
3624887Schin 	char*		format;
3634887Schin 	char*		library;
3644887Schin 	const char*	catalog;
3654887Schin 
3664887Schin 	int		line;
3674887Schin 	char*		file;
3684887Schin 
3694887Schin #if !_PACKAGE_astsa
3704887Schin 	unsigned long	d;
3714887Schin 	struct tms	us;
3724887Schin #endif
3734887Schin 
3744887Schin 	if (!error_info.init)
3754887Schin 	{
3764887Schin 		error_info.init = 1;
3774887Schin 		stropt(getenv("ERROR_OPTIONS"), options, sizeof(*options), setopt, NiL);
3784887Schin 	}
3794887Schin 	if (level > 0)
3804887Schin 	{
3814887Schin 		flags = level & ~ERROR_LEVEL;
3824887Schin 		level &= ERROR_LEVEL;
3834887Schin 	}
3844887Schin 	else
3854887Schin 		flags = 0;
3864887Schin 	if ((flags & (ERROR_USAGE|ERROR_NOID)) == ERROR_NOID)
3874887Schin 	{
3884887Schin 		format = (char*)id;
3894887Schin 		id = 0;
3904887Schin 	}
3914887Schin 	else
3924887Schin 		format = 0;
3934887Schin 	if (id)
3944887Schin 	{
3954887Schin 		catalog = (char*)id;
3964887Schin 		if (!*catalog || *catalog == ':')
3974887Schin 		{
3984887Schin 			catalog = 0;
3994887Schin 			library = 0;
4004887Schin 		}
4014887Schin 		else if ((library = strchr(catalog, ':')) && !*++library)
4024887Schin 			library = 0;
4034887Schin 	}
4044887Schin 	else
4054887Schin 	{
4064887Schin 		catalog = 0;
4074887Schin 		library = 0;
4084887Schin 	}
4094887Schin 	if (catalog)
4104887Schin 		id = 0;
4114887Schin 	else
4124887Schin 	{
4134887Schin 		id = (const char*)error_info.id;
4144887Schin 		catalog = error_info.catalog;
4154887Schin 	}
4164887Schin 	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))))
4174887Schin 	{
4184887Schin 		if (level >= ERROR_FATAL)
4194887Schin 			(*error_info.exit)(level - 1);
4204887Schin 		return;
4214887Schin 	}
4224887Schin 	if (error_info.trace < 0)
4234887Schin 		flags |= ERROR_LIBRARY|ERROR_SYSTEM;
4244887Schin 	flags |= error_info.set | error_info.flags;
4254887Schin 	flags &= ~error_info.clear;
4264887Schin 	if (!library)
4274887Schin 		flags &= ~ERROR_LIBRARY;
4284887Schin 	fd = (flags & ERROR_OUTPUT) ? va_arg(ap, int) : error_info.fd;
4294887Schin 	if (error_info.write)
4304887Schin 	{
4314887Schin 		long	off;
4324887Schin 		char*	bas;
4334887Schin 
4344887Schin 		bas = stkptr(stkstd, 0);
4354887Schin 		if (off = stktell(stkstd))
4364887Schin 			stkfreeze(stkstd, 0);
4374887Schin 		file = error_info.id;
4384887Schin 		if (error_state.prefix)
4394887Schin 			sfprintf(stkstd, "%s: ", error_state.prefix);
4404887Schin 		if (flags & ERROR_USAGE)
4414887Schin 		{
4424887Schin 			if (flags & ERROR_NOID)
4434887Schin 				sfprintf(stkstd, "       ");
4444887Schin 			else
4454887Schin 				sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "Usage"));
4464887Schin 			if (file || opt_info.argv && (file = opt_info.argv[0]))
4474887Schin 				print(stkstd, file, " ");
4484887Schin 		}
4494887Schin 		else
4504887Schin 		{
4514887Schin 			if (level && !(flags & ERROR_NOID))
4524887Schin 			{
4534887Schin 				if (error_info.context && level > 0)
4544887Schin 					context(stkstd, CONTEXT(error_info.flags, error_info.context));
4554887Schin 				if (file)
4564887Schin 					print(stkstd, file, (flags & ERROR_LIBRARY) ? " " : ": ");
4574887Schin 				if (flags & (ERROR_CATALOG|ERROR_LIBRARY))
4584887Schin 				{
4594887Schin 					sfprintf(stkstd, "[");
4604887Schin 					if (flags & ERROR_CATALOG)
4614887Schin 						sfprintf(stkstd, "%s %s%s",
4624887Schin 							catalog ? catalog : ERROR_translate(NiL, NiL, ast.id, "DEFAULT"),
4634887Schin 							ERROR_translate(NiL, NiL, ast.id, "catalog"),
4644887Schin 							(flags & ERROR_LIBRARY) ? ", " : "");
4654887Schin 					if (flags & ERROR_LIBRARY)
4664887Schin 						sfprintf(stkstd, "%s %s",
4674887Schin 							library,
4684887Schin 							ERROR_translate(NiL, NiL, ast.id, "library"));
4694887Schin 					sfprintf(stkstd, "]: ");
4704887Schin 				}
4714887Schin 			}
4724887Schin 			if (level > 0 && error_info.line > ((flags & ERROR_INTERACTIVE) != 0))
4734887Schin 			{
4744887Schin 				if (error_info.file && *error_info.file)
4754887Schin 					sfprintf(stkstd, "\"%s\", ", error_info.file);
4764887Schin 				sfprintf(stkstd, "%s %d: ", ERROR_translate(NiL, NiL, ast.id, "line"), error_info.line);
4774887Schin 			}
4784887Schin 		}
4794887Schin #if !_PACKAGE_astsa
4804887Schin 		if (error_info.time)
4814887Schin 		{
4824887Schin 			if ((d = times(&us)) < error_info.time || error_info.time == 1)
4834887Schin 				error_info.time = d;
4844887Schin 			sfprintf(stkstd, " %05lu.%05lu.%05lu ", d - error_info.time, (unsigned long)us.tms_utime, (unsigned long)us.tms_stime);
4854887Schin 		}
4864887Schin #endif
4874887Schin 		switch (level)
4884887Schin 		{
4894887Schin 		case 0:
4904887Schin 			flags &= ~ERROR_SYSTEM;
4914887Schin 			break;
4924887Schin 		case ERROR_WARNING:
4934887Schin 			sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "warning"));
4944887Schin 			break;
4954887Schin 		case ERROR_PANIC:
4964887Schin 			sfprintf(stkstd, "%s: ", ERROR_translate(NiL, NiL, ast.id, "panic"));
4974887Schin 			break;
4984887Schin 		default:
4994887Schin 			if (level < 0)
5004887Schin 			{
5014887Schin 				s = ERROR_translate(NiL, NiL, ast.id, "debug");
5024887Schin 				if (error_info.trace < -1)
5034887Schin 					sfprintf(stkstd, "%s%d:%s", s, level, level > -10 ? " " : "");
5044887Schin 				else
5054887Schin 					sfprintf(stkstd, "%s: ", s);
5064887Schin 				for (n = 0; n < error_info.indent; n++)
5074887Schin 				{
5084887Schin 					sfputc(stkstd, ' ');
5094887Schin 					sfputc(stkstd, ' ');
5104887Schin 				}
5114887Schin 			}
5124887Schin 			break;
5134887Schin 		}
5144887Schin 		if (flags & ERROR_SOURCE)
5154887Schin 		{
5164887Schin 			/*
5174887Schin 			 * source ([version], file, line) message
5184887Schin 			 */
5194887Schin 
5204887Schin 			file = va_arg(ap, char*);
5214887Schin 			line = va_arg(ap, int);
5224887Schin 			s = ERROR_translate(NiL, NiL, ast.id, "line");
5234887Schin 			if (error_info.version)
5244887Schin 				sfprintf(stkstd, "(%s: \"%s\", %s %d) ", error_info.version, file, s, line);
5254887Schin 			else
5264887Schin 				sfprintf(stkstd, "(\"%s\", %s %d) ", file, s, line);
5274887Schin 		}
5284887Schin 		if (format || (format = va_arg(ap, char*)))
5294887Schin 		{
5304887Schin 			if (!(flags & ERROR_USAGE))
5314887Schin 				format = ERROR_translate(NiL, id, catalog, format);
5324887Schin 			sfvprintf(stkstd, format, ap);
5334887Schin 		}
5344887Schin 		if (!(flags & ERROR_PROMPT))
5354887Schin 		{
5364887Schin 			/*
5374887Schin 			 * level&ERROR_OUTPUT on return means message
5384887Schin 			 * already output
5394887Schin 			 */
5404887Schin 
5414887Schin 			if ((flags & ERROR_SYSTEM) && errno && errno != error_info.last_errno)
5424887Schin 			{
5434887Schin 				sfprintf(stkstd, " [%s]", fmterror(errno));
5444887Schin 				if (error_info.set & ERROR_SYSTEM)
5454887Schin 					errno = 0;
5464887Schin 				error_info.last_errno = (level >= 0) ? 0 : errno;
5474887Schin 			}
5484887Schin 			if (error_info.auxilliary && level >= 0)
5494887Schin 				level = (*error_info.auxilliary)(stkstd, level, flags);
5504887Schin 			sfputc(stkstd, '\n');
5514887Schin 		}
5524887Schin 		if (level > 0)
5534887Schin 		{
5544887Schin 			if ((level & ~ERROR_OUTPUT) > 1)
5554887Schin 				error_info.errors++;
5564887Schin 			else
5574887Schin 				error_info.warnings++;
5584887Schin 		}
5594887Schin 		if (level < 0 || !(level & ERROR_OUTPUT))
5604887Schin 		{
5614887Schin 			n = stktell(stkstd);
5624887Schin 			s = stkptr(stkstd, 0);
5634887Schin 			if (t = memchr(s, '\f', n))
5644887Schin 			{
5654887Schin 				n -= ++t - s;
5664887Schin 				s = t;
5674887Schin 			}
5684887Schin #if HUH_19980401 /* nasty problems if sfgetr() is in effect! */
5694887Schin 			sfsync(sfstdin);
5704887Schin #endif
5714887Schin 			sfsync(sfstdout);
5724887Schin 			sfsync(sfstderr);
5734887Schin 			if (fd == sffileno(sfstderr) && error_info.write == write)
5744887Schin 			{
5754887Schin 				sfwrite(sfstderr, s, n);
5764887Schin 				sfsync(sfstderr);
5774887Schin 			}
5784887Schin 			else
5794887Schin 				(*error_info.write)(fd, s, n);
5804887Schin 		}
5814887Schin 		else
5824887Schin 		{
5834887Schin 			s = 0;
5844887Schin 			level &= ERROR_LEVEL;
5854887Schin 		}
5864887Schin 		stkset(stkstd, bas, off);
5874887Schin 	}
5884887Schin 	else
5894887Schin 		s = 0;
5904887Schin 	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))
5914887Schin 	{
5924887Schin 		if (error_info.core)
5934887Schin 		{
5944887Schin #ifndef SIGABRT
5954887Schin #ifdef	SIGQUIT
5964887Schin #define SIGABRT	SIGQUIT
5974887Schin #else
5984887Schin #ifdef	SIGIOT
5994887Schin #define SIGABRT	SIGIOT
6004887Schin #endif
6014887Schin #endif
6024887Schin #endif
6034887Schin #ifdef	SIGABRT
6044887Schin 			signal(SIGABRT, SIG_DFL);
6054887Schin 			kill(getpid(), SIGABRT);
6064887Schin 			pause();
6074887Schin #else
6084887Schin 			abort();
6094887Schin #endif
6104887Schin 		}
6114887Schin 		else
6124887Schin 			error_break();
6134887Schin 	}
6144887Schin 	if (level >= ERROR_FATAL)
6154887Schin 		(*error_info.exit)(level - ERROR_FATAL + 1);
6164887Schin }
6174887Schin 
6184887Schin /*
6194887Schin  * error_info context control
6204887Schin  */
6214887Schin 
6224887Schin static Error_info_t*	freecontext;
6234887Schin 
6244887Schin Error_info_t*
errorctx(Error_info_t * p,int op,int flags)6254887Schin errorctx(Error_info_t* p, int op, int flags)
6264887Schin {
6274887Schin 	if (op & ERROR_POP)
6284887Schin 	{
6294887Schin 		if (!(_error_infop_ = p->context))
6304887Schin 			_error_infop_ = &_error_info_;
6314887Schin 		if (op & ERROR_FREE)
6324887Schin 		{
6334887Schin 			p->context = freecontext;
6344887Schin 			freecontext = p;
6354887Schin 		}
6364887Schin 		p = _error_infop_;
6374887Schin 	}
6384887Schin 	else
6394887Schin 	{
6404887Schin 		if (!p)
6414887Schin 		{
6424887Schin 			if (p = freecontext)
6434887Schin 				freecontext = freecontext->context;
6444887Schin 			else if (!(p = newof(0, Error_info_t, 1, 0)))
6454887Schin 				return 0;
6464887Schin 			*p = *_error_infop_;
6474887Schin 			p->errors = p->flags = p->line = p->warnings = 0;
6484887Schin 			p->catalog = p->file = 0;
6494887Schin 		}
6504887Schin 		if (op & ERROR_PUSH)
6514887Schin 		{
6524887Schin 			p->flags = flags;
6534887Schin 			p->context = _error_infop_;
6544887Schin 			_error_infop_ = p;
6554887Schin 		}
6564887Schin 		p->flags |= ERROR_PUSH;
6574887Schin 	}
6584887Schin 	return p;
6594887Schin }
660