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