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