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