1 /* ------------------------------------------------------------------------
2 @NAME : error.c
3 @DESCRIPTION: Anything relating to reporting or recording errors and
4 warnings.
5 @GLOBALS : errclass_names
6 err_actions
7 err_handlers
8 errclass_counts
9 error_buf
10 @CALLS :
11 @CREATED : 1996/08/28, Greg Ward
12 @MODIFIED :
13 @VERSION : $Id: error.c,v 2.5 1999/11/29 01:13:10 greg Rel $
14 @COPYRIGHT : Copyright (c) 1996-99 by Gregory P. Ward. All rights reserved.
15
16 This file is part of the btparse library. This library is
17 free software; you can redistribute it and/or modify it under
18 the terms of the GNU General Public License as
19 published by the Free Software Foundation; either version 2
20 of the License, or (at your option) any later version.
21 -------------------------------------------------------------------------- */
22
23 /*#include "bt_config.h"*/
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include "btparse.h"
29 #include "error.h"
30 /*#include "my_dmalloc.h"*/
31
32
33 #define NUM_ERRCLASSES ((int) BTERR_INTERNAL + 1)
34
35
36 static const char *errclass_names[NUM_ERRCLASSES] =
37 {
38 NULL, /* BTERR_NOTIFY */
39 "warning", /* BTERR_CONTENT */
40 "warning", /* BTERR_LEXWARN */
41 "warning", /* BTERR_USAGEWARN */
42 "error", /* BTERR_LEXERR */
43 "syntax error", /* BTERR_SYNTAX */
44 "fatal error", /* BTERR_USAGEERR */
45 "internal error" /* BTERR_INTERNAL */
46 };
47
48 static const bt_erraction err_actions[NUM_ERRCLASSES] =
49 {
50 BTACT_NONE, /* BTERR_NOTIFY */
51 BTACT_NONE, /* BTERR_CONTENT */
52 BTACT_NONE, /* BTERR_LEXWARN */
53 BTACT_NONE, /* BTERR_USAGEWARN */
54 BTACT_NONE, /* BTERR_LEXERR */
55 BTACT_NONE, /* BTERR_SYNTAX */
56 BTACT_CRASH, /* BTERR_USAGEERR */
57 BTACT_ABORT /* BTERR_INTERNAL */
58 };
59
60 void print_error (bt_error *err);
61
62 static bt_err_handler err_handlers[NUM_ERRCLASSES] =
63 {
64 print_error,
65 print_error,
66 print_error,
67 print_error,
68 print_error,
69 print_error,
70 print_error,
71 print_error
72 };
73
74 static int errclass_counts[NUM_ERRCLASSES] = { 0, 0, 0, 0, 0, 0, 0, 0 };
75 static char error_buf[MAX_ERROR+1];
76
77
78 /* ----------------------------------------------------------------------
79 * Error-handling functions.
80 */
81
print_error(bt_error * err)82 void print_error (bt_error *err)
83 {
84 const char * name;
85 boolean something_printed;
86
87 something_printed = FALSE;
88
89 if (err->filename)
90 {
91 fprintf (stderr,"%s" ,err->filename);
92 something_printed = TRUE;
93 }
94 if (err->line > 0) /* going to print a line number? */
95 {
96 if (something_printed)
97 fprintf (stderr, ", ");
98 fprintf (stderr, "line %d", err->line);
99 something_printed = TRUE;
100 }
101 if (err->item_desc && err->item > 0) /* going to print an item number? */
102 {
103 if (something_printed)
104 fprintf (stderr, ", ");
105 fprintf (stderr, "%s %d", err->item_desc, err->item);
106 something_printed = TRUE;
107 }
108
109 name = errclass_names[(int) err->errclass];
110 if (name)
111 {
112 if (something_printed)
113 fprintf (stderr, ", ");
114 fprintf (stderr,"%s" ,name);
115 something_printed = TRUE;
116 }
117
118 if (something_printed)
119 fprintf (stderr, ": ");
120
121 fprintf (stderr, "%s\n", err->message);
122
123 } /* print_error() */
124
125
126
127 /* ----------------------------------------------------------------------
128 * Error-reporting functions: these are called anywhere in the library
129 * when we encounter an error.
130 */
131
132 void
report_error(bt_errclass errclass,const char * filename,int line,const char * item_desc,int item,const char * fmt,va_list arglist)133 report_error (bt_errclass errclass,
134 const char * filename,
135 int line,
136 const char * item_desc,
137 int item,
138 const char * fmt,
139 va_list arglist)
140 {
141 bt_error err;
142
143 err.errclass = errclass;
144 err.filename = filename;
145 err.line = line;
146 err.item_desc = item_desc;
147 err.item = item;
148
149 errclass_counts[(int) errclass]++;
150
151
152 /*
153 * Blech -- we're writing to a static buffer because there's no easy
154 * way to know how long the error message is going to be. (Short of
155 * reimplementing printf(), or maybe printf()'ing to a dummy file
156 * and using the return value -- ugh!) The GNU C library conveniently
157 * supplies vsnprintf(), which neatly solves this problem by truncating
158 * the output string if it gets too long. (I could check for this
159 * truncation if I wanted to, but I don't think it's necessary given the
160 * ample size of the message buffer.) For non-GNU systems, though,
161 * we're stuck with using vsprintf()'s return value. This can't be
162 * trusted on all systems -- thus there's a check for it in configure.
163 * Also, this won't necessarily trigger the internal_error() if we
164 * do overflow; it's conceivable that vsprintf() itself would crash.
165 * At least doing it this way we avoid the possibility of vsprintf()
166 * silently corrupting some memory, and crashing unpredictably at some
167 * later point.
168 */
169
170 vsnprintf (error_buf, MAX_ERROR, fmt, arglist);
171
172 err.message = error_buf;
173 if (err_handlers[errclass])
174 (*err_handlers[errclass]) (&err);
175
176 switch (err_actions[errclass])
177 {
178 case BTACT_NONE: return;
179 case BTACT_CRASH: exit (1);
180 case BTACT_ABORT: abort ();
181 default: internal_error ("invalid error action %d for class %d (%s)",
182 (int) err_actions[errclass],
183 (int) errclass, errclass_names[errclass]);
184 }
185
186 } /* report_error() */
187
188
189 GEN_ERRFUNC (general_error,
190 (bt_errclass errclass,
191 char * filename,
192 int line,
193 const char * item_desc,
194 int item,
195 const char * fmt,
196 ...),
197 errclass, filename, line, item_desc, item, fmt)
198
199 GEN_ERRFUNC (error,
200 (bt_errclass errclass,
201 char * filename,
202 int line,
203 char * fmt,
204 ...),
205 errclass, filename, line, NULL, -1, fmt)
206
207 GEN_ERRFUNC (ast_error,
208 (bt_errclass errclass,
209 AST * ast,
210 char * fmt,
211 ...),
212 errclass, ast->filename, ast->line, NULL, -1, fmt)
213
214 GEN_ERRFUNC (notify,
215 (const char * fmt, ...),
216 BTERR_NOTIFY, NULL, -1, NULL, -1, fmt)
217
218 GEN_ERRFUNC (usage_warning,
219 (const char * fmt, ...),
220 BTERR_USAGEWARN, NULL, -1, NULL, -1, fmt)
221
222 GEN_ERRFUNC (usage_error,
223 (const char * fmt, ...),
224 BTERR_USAGEERR, NULL, -1, NULL, -1, fmt)
225
226 GEN_ERRFUNC (internal_error,
227 (const char * fmt, ...),
228 BTERR_INTERNAL, NULL, -1, NULL, -1, fmt)
229
230
231 /* ======================================================================
232 * Functions to be used outside of the library
233 */
234
235 /* ------------------------------------------------------------------------
236 @NAME : bt_reset_error_counts()
237 @INPUT :
238 @OUTPUT :
239 @RETURNS :
240 @DESCRIPTION: Resets all the error counters to zero.
241 @GLOBALS :
242 @CALLS :
243 @CREATED : 1997/01/08, GPW
244 @MODIFIED :
245 -------------------------------------------------------------------------- */
bt_reset_error_counts(void)246 void bt_reset_error_counts (void)
247 {
248 int i;
249
250 for (i = 0; i < NUM_ERRCLASSES; i++)
251 errclass_counts[i] = 0;
252 }
253
254
255 /* ------------------------------------------------------------------------
256 @NAME : bt_get_error_count()
257 @INPUT : errclass
258 @OUTPUT :
259 @RETURNS :
260 @DESCRIPTION: Returns number of errors seen in the specified class.
261 @GLOBALS : errclass_counts
262 @CALLS :
263 @CREATED :
264 @MODIFIED :
265 -------------------------------------------------------------------------- */
bt_get_error_count(bt_errclass errclass)266 int bt_get_error_count (bt_errclass errclass)
267 {
268 return errclass_counts[errclass];
269 }
270
271
272 /* ------------------------------------------------------------------------
273 @NAME : bt_get_error_counts()
274 @INPUT : counts - pointer to an array big enough to hold all the counts
275 if NULL, the array will be allocated for you (and you
276 must free() it when done with it)
277 @OUTPUT :
278 @RETURNS : counts - either the passed-in pointer, or the newly-
279 allocated array if you pass in NULL
280 @DESCRIPTION: Returns a newly-allocated array with the number of errors
281 in each error class, indexed by the members of the
282 eclass_t enum.
283 @GLOBALS : errclass_counts
284 @CALLS :
285 @CREATED : 1997/01/06, GPW
286 @MODIFIED :
287 -------------------------------------------------------------------------- */
bt_get_error_counts(int * counts)288 int *bt_get_error_counts (int *counts)
289 {
290 int i;
291
292 if (counts == NULL)
293 counts = (int *) malloc (sizeof (int) * NUM_ERRCLASSES);
294 for (i = 0; i < NUM_ERRCLASSES; i++)
295 counts[i] = errclass_counts[i];
296
297 return counts;
298 }
299
300
301 /* ------------------------------------------------------------------------
302 @NAME : bt_error_status
303 @INPUT : saved_counts - an array of error counts as returned by
304 bt_get_error_counts, or NULL not to compare
305 to a previous checkpoint
306 @OUTPUT :
307 @RETURNS :
308 @DESCRIPTION: Computes a bitmap where a bit is set for each error class
309 that has more errors now than it used to have (or, if
310 saved_counts is NULL, the bit is set of there are have been
311 any errors in the corresponding error class).
312
313 Eg. "x & (1<<E_SYNTAX)" (where x is returned by bt_error_status)
314 is true if there have been any syntax errors.
315 @GLOBALS :
316 @CALLS :
317 @CREATED :
318 @MODIFIED :
319 -------------------------------------------------------------------------- */
bt_error_status(int * saved_counts)320 ushort bt_error_status (int *saved_counts)
321 {
322 int i;
323 ushort status;
324
325 status = 0;
326
327 if (saved_counts)
328 {
329 for (i = 0; i < NUM_ERRCLASSES; i++)
330 status |= ( (errclass_counts[i] > saved_counts[i]) << i);
331 }
332 else
333 {
334 for (i = 0; i < NUM_ERRCLASSES; i++)
335 status |= ( (errclass_counts[i] > 0) << i);
336 }
337
338 return status;
339 } /* bt_error_status () */
340