14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 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 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 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 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 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 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* 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