PageRenderTime 61ms CodeModel.GetById 31ms app.highlight 24ms RepoModel.GetById 2ms app.codeStats 0ms

/brlcad/branches/STABLE/src/other/step/src/express/error.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 514 lines | 323 code | 65 blank | 126 comment | 47 complexity | ceb8eaf161b40765046b6e4c148584e3 MD5 | raw file
  1
  2
  3/** **********************************************************************
  4** Module:  Error \file error.c
  5** This module implements the ERROR abstraction
  6************************************************************************/
  7
  8/*
  9 * Development of this code was funded by the United States Government,
 10 * and is not subject to copyright.
 11 *
 12 * $Log: error.c,v $
 13 * Revision 1.13  1997/10/23 21:41:44  sauderd
 14 * I am backing out to version 1.10 before the changes related to va_list and
 15 * __STDC__ etc. I don't have time to finish fixing all this.
 16 *
 17 * Revision 1.12  1997/10/23 21:35:31  sauderd
 18 * Changed more mess with compiler directives for __STDC__ and HAVE_STDARG_H
 19 * but am getting deeper into problems because of how PROTO is defined for
 20 * dealing with prototypes based on standard C or not. PROTO is broken as well
 21 * so I'm not going down this road further. Next I will back out but am this
 22 * far ahead for later if we fix this.
 23 *
 24 * Revision 1.11  1997/10/22 16:10:26  sauderd
 25 * This would #include stdarg.h if __STDC__ was defined otherwise it would
 26 * #include vararg.h. I changed it to check the configure generated config file
 27 * named scl_cf.h (if HAVE_CONFIG_H is defined - it's also defined by
 28 * configure) to see if HAVE_STDARG_H is defined. If it is it #includes stdarg.h
 29 * otherwise it #includes vararg.h. If HAVE_CONFIG_H isn't defined then it works
 30 * like it used to.
 31 *
 32 * Revision 1.10  1997/01/21 19:19:51  dar
 33 * made C++ compatible
 34 *
 35 * Revision 1.9  1994/05/11  19:51:46  libes
 36 * numerous fixes
 37 *
 38 * Revision 1.8  1993/10/15  18:49:55  libes
 39 * CADDETC certified
 40 *
 41 * Revision 1.6  1993/02/22  21:44:34  libes
 42 * ANSI compat fixes
 43 *
 44 * Revision 1.5  1993/01/19  22:45:07  libes
 45 * *** empty log message ***
 46 *
 47 * Revision 1.4  1992/08/18  17:16:22  libes
 48 * rm'd extraneous error messages
 49 *
 50 * Revision 1.3  1992/06/08  18:08:05  libes
 51 * prettied up interface to print_objects_when_running
 52 */
 53
 54#include <scl_memmgr.h>
 55#include <stdlib.h>
 56#include <setjmp.h>
 57
 58#include "signal.h"
 59#include "express/error.h"
 60#include "string.h"
 61#include "express/linklist.h"
 62#ifdef __STDC__
 63#include <stdarg.h>
 64#else
 65#include <varargs.h>
 66#endif
 67
 68
 69bool __ERROR_buffer_errors = false;
 70char * current_filename = "stdin";
 71
 72/* flag to remember whether non-warning errors have occurred */
 73bool ERRORoccurred = false;
 74
 75
 76Error experrc = ERROR_none;
 77Error ERROR_subordinate_failed = ERROR_none;
 78Error ERROR_syntax_expecting = ERROR_none;
 79
 80/* all of these are 1 if true, 0 if false switches */
 81/* for debugging fedex */
 82int ERRORdebugging = 0;
 83/* for debugging malloc during resolution */
 84int malloc_debug_resolve = 0;
 85/* for debugging yacc/lex */
 86int debug = 0;
 87
 88struct Linked_List_ * ERRORwarnings;
 89struct freelist_head ERROR_OPT_fl;
 90
 91void ( *ERRORusage_function )( void );
 92
 93#include "express/express.h"
 94
 95#define ERROR_MAX_ERRORS    100 /**< max line-numbered errors */
 96#define ERROR_MAX_SPACE     4000 /**< max space for line-numbered errors */
 97#define ERROR_MAX_STRLEN    200 /**< assuming all error messages are less than this,
 98                                  * if we have less than this much space remaining
 99                                  * in the error string buffer, call it a day and
100                                  * dump the buffer */
101
102static struct heap_element {
103    unsigned int line;
104    char * msg;
105} heap[ERROR_MAX_ERRORS + 1]; /**< NOTE!  element 0 is purposely ignored, and
106                                * an additional element is at the end.  This
107                                * allows the later heap calculations to be
108                                * much simpler */
109
110static int ERROR_with_lines = 0;    /**< number of warnings & errors that have occurred with a line number */
111static char * ERROR_string;
112static char * ERROR_string_base;
113
114static bool ERROR_unsafe = false;
115static jmp_buf ERROR_safe_env;
116
117
118#define error_file stderr /**< message buffer file */
119
120/** Initialize the Error module */
121void ERRORinitialize( void ) {
122    ERROR_subordinate_failed =
123        ERRORcreate( "A subordinate failed.", SEVERITY_ERROR );
124    ERROR_syntax_expecting =
125        ERRORcreate( "%s, expecting %s in %s %s", SEVERITY_EXIT );
126
127    ERROR_string_base = ( char * )scl_malloc( ERROR_MAX_SPACE );
128    ERROR_start_message_buffer();
129
130
131#ifdef SIGQUIT
132    signal( SIGQUIT, ERRORabort );
133#endif
134#ifdef SIGBUS
135    signal( SIGBUS, ERRORabort );
136#endif
137#ifdef SIGSEGV
138    signal( SIGSEGV, ERRORabort );
139#endif
140#ifdef SIGABRT
141    signal( SIGABRT, ERRORabort );
142#endif
143}
144
145/** Need the LIST routines to complete ERROR initialization */
146void ERRORinitialize_after_LIST( void ) {
147    ERRORwarnings = LISTcreate();
148
149    MEMinitialize( &ERROR_OPT_fl, sizeof( struct Error_Warning_ ), 5, 5 );
150}
151
152void ERRORcreate_warning( char * name, Error error ) {
153    struct Error_Warning_ *o;
154
155    /* first check if we know about this type of error */
156    LISTdo( ERRORwarnings, opt, Error_Warning )
157    if( streq( name, opt->name ) ) {
158        LISTadd( opt->errors, ( Generic )error );
159        return;
160    }
161    LISTod
162
163    /* new error */
164    o = ERROR_OPT_new();
165    o->name = name;
166    o->errors = LISTcreate();
167    LISTadd( o->errors, ( Generic )error );
168    LISTadd( ERRORwarnings, ( Generic )o );
169}
170
171void ERRORset_warning( char * name, int set ) {
172    bool found = false;
173
174    if( streq( name, "all" ) ) {
175        ERRORset_all_warnings( set );
176    } else if( streq( name, "none" ) ) {
177        ERRORset_all_warnings( !set );
178    } else {
179        LISTdo( ERRORwarnings, opt, Error_Warning )
180        if( streq( opt->name, name ) ) {
181            found = true;
182            LISTdo( opt->errors, err, Error )
183            err->enabled = set;
184            LISTod
185        }
186        LISTod
187        if( found ) {
188            return;
189        }
190
191        fprintf( stderr, "unknown warning: %s\n", name );
192        if( ERRORusage_function ) {
193            ( *ERRORusage_function )();
194        }
195    }
196}
197
198/** \fn ERRORdisable
199** \param error error to disable
200** Disable an error (ERRORreport*() will ignore it)
201** \note this function is inlined in error.h
202*/
203
204/** \fn ERRORenable
205** \param error error to enable
206** Enable an error (ERRORreport*() will report it)
207** \note this function is inlined in error.h
208*/
209
210/** \fn ERRORis_enabled
211** \param error error to test
212** \return is reporting of the error enabled?
213** Check whether an error is enabled
214** \note this function is inlined in error.h
215*/
216
217/** \fn ERRORreport
218** \param what error to report
219** \param ... arguments for error string
220** Print a report of an error
221**
222** Notes:   The second and subsequent arguments should match the
223**      format fields of the message generated by 'what.'
224*/
225void ERRORset_all_warnings( int set ) {
226    LISTdo( ERRORwarnings, opts, Error_Warning )
227    LISTdo( opts->errors, err, Error )
228    err->enabled = set;
229    LISTod
230    LISTod
231}
232
233void
234#ifdef __STDC__
235ERRORreport( Error what, ... ) {
236#else
237ERRORreport( va_alist )
238va_dcl {
239    Error what;
240#endif
241    /*    extern void abort(void);*/
242    va_list args;
243
244#ifdef __STDC__
245    va_start( args, what );
246#else
247    va_start( args );
248    what = va_arg( args, Error );
249#endif
250
251    if( ( what != ERROR_none ) &&
252    ( what != ERROR_subordinate_failed ) &&
253    what->enabled ) {
254        if( what->severity >= SEVERITY_ERROR ) {
255            fprintf( error_file, "ERROR: " );
256            vfprintf( error_file, what->message, args );
257            fputc( '\n', error_file );
258            ERRORoccurred = true;
259        } else if( what->severity >= SEVERITY_WARNING ) {
260            fprintf( error_file, "WARNING: ");
261            vfprintf( error_file, what->message, args );
262            fputc( '\n', error_file );
263        }
264        if( what->severity >= SEVERITY_EXIT ) {
265            ERROR_flush_message_buffer();
266            if( what->severity >= SEVERITY_DUMP ) {
267                abort();
268            } else {
269                exit( EXPRESS_fail( ( Express )0 ) );
270            }
271        }
272    }
273    experrc = ERROR_none;
274    va_end( args );
275}
276
277/**
278** \param what error to report
279** \param line line number of error
280** \param ... arguments for error string
281** Print a report of an error, including a line number
282**
283** \note The third and subsequent arguments should match the
284**      format fields of the message generated by 'what.'
285*/
286void
287#ifdef __STDC__
288ERRORreport_with_line( Error what, int line, ... ) {
289#else
290ERRORreport_with_line( va_alist )
291va_dcl {
292    Error what;
293    int line;
294#endif
295
296    char buf[BUFSIZ];
297    char * savemsg; /* save what->message here while we fool */
298    /* ERRORreport_with_line */
299    Symbol sym;
300    va_list args;
301#ifdef __STDC__
302    va_start( args, line );
303#else
304    va_start( args );
305    what = va_arg( args, Error );
306    line = va_arg( args, int );
307#endif
308
309    sym.filename = current_filename;
310    sym.line = line;
311
312    vsprintf( buf, what->message, args );
313
314    /* gross, but there isn't any way to do this more directly */
315    /* without writing yet another variant of ERRORreport_with_line */
316    savemsg = what->message;
317    what->message = "%s";
318    ERRORreport_with_symbol( what, &sym, buf );
319    what->message = savemsg;
320}
321
322void
323#ifdef __STDC__
324ERRORreport_with_symbol( Error what, Symbol * sym, ... ) {
325#else
326ERRORreport_with_symbol( va_alist )
327va_dcl {
328    Error what;
329    Symbol * sym;
330#endif
331    /*    extern void abort(void);*/
332    va_list args;
333
334#ifdef __STDC__
335    va_start( args, sym );
336#else
337    va_start( args );
338    what = va_arg( args, Error );
339    sym = va_arg( args, Symbol * );
340#endif
341
342    if( ( what != ERROR_none ) && ( what != ERROR_subordinate_failed ) && what->enabled ) {
343        if( __ERROR_buffer_errors ) {
344            int child, parent;
345
346            /*
347             * add an element to the heap
348             * by (logically) storing the new value
349             * at the end of the array and bubbling
350             * it up as necessary
351             */
352
353            child = ++ERROR_with_lines;
354            parent = child / 2;
355            while( parent ) {
356                if( sym->line < heap[parent].line ) {
357                    heap[child] = heap[parent];
358                } else {
359                    break;
360                }
361                child = parent;
362                parent = child / 2;
363            }
364            heap[child].line = sym->line;
365            heap[child].msg = ERROR_string;
366
367            if( what->severity >= SEVERITY_ERROR ) {
368                sprintf( ERROR_string, "%s:%d: --ERROR: ", sym->filename, sym->line );
369                ERROR_string += strlen( ERROR_string );
370                vsprintf( ERROR_string, what->message, args );
371                ERROR_string += strlen( ERROR_string );
372                *ERROR_string++ = '\n';
373                *ERROR_string++ = '\0';
374                ERRORoccurred = true;
375            } else if( what->severity >= SEVERITY_WARNING ) {
376                sprintf( ERROR_string, "%s:%d: WARNING: ", sym->filename, sym->line );
377                ERROR_string += strlen( ERROR_string );
378                vsprintf( ERROR_string, what->message, args );
379                ERROR_string += strlen( ERROR_string );
380                *ERROR_string++ = '\n';
381                *ERROR_string++ = '\0';
382            }
383            if( what->severity >= SEVERITY_EXIT ||
384                    ERROR_string + ERROR_MAX_STRLEN > ERROR_string_base + ERROR_MAX_SPACE ||
385                    ERROR_with_lines == ERROR_MAX_ERRORS ) {
386                ERROR_flush_message_buffer();
387                if( what->severity >= SEVERITY_DUMP ) {
388                    abort();
389                } else {
390                    exit( EXPRESS_fail( ( Express )0 ) );
391                }
392            }
393        } else {
394            if( what->severity >= SEVERITY_ERROR ) {
395                fprintf( error_file, "%s:%d: --ERROR: ", sym->filename, sym->line );
396                vfprintf( error_file, what->message, args );
397                fprintf( error_file, "\n" );
398                ERRORoccurred = true;
399            } else if( what->severity >= SEVERITY_WARNING ) {
400                fprintf( error_file, "%s:%d: WARNING: ", sym->filename, sym->line );
401                ERROR_string += strlen( ERROR_string ) + 1;
402                vfprintf( error_file, what->message, args );
403                fprintf( error_file, "\n" );
404            }
405            if( what->severity >= SEVERITY_EXIT ) {
406                if( what->severity >= SEVERITY_DUMP ) {
407                    abort();
408                } else {
409                    exit( EXPRESS_fail( ( Express )0 ) );
410                }
411            }
412        }
413    }
414    experrc = ERROR_none;
415    va_end( args );
416}
417
418void ERRORnospace() {
419    fprintf( stderr, "%s: out of space\n", EXPRESSprogram_name );
420    ERRORabort( 0 );
421}
422
423/**
424** \param message error message
425** \param severity severity of error
426** \return newly created error
427** Create a new error
428*/
429Error ERRORcreate( char * message, Severity severity ) {
430    Error n;
431
432    n = ( struct Error_ * )scl_malloc( sizeof( struct Error_ ) );
433    n->message = message;
434    n->severity = severity;
435    n->enabled = true;
436    return n;
437}
438
439/** \fn ERRORbuffer_messages
440** \param flag    - to buffer or not to buffer
441** Selects buffering of error messages
442** \note this function is inlined in error.h
443*/
444
445/** \fn ERRORflush_messages
446** Flushes the error message buffer to standard output.
447** \note this function is inlined in error.h
448**
449** \note The error messages are sorted by line number (which appears in the third column).
450*/
451
452void ERROR_start_message_buffer( void ) {
453    ERROR_string = ERROR_string_base;
454    ERROR_with_lines = 0;
455}
456
457void ERROR_flush_message_buffer( void ) {
458    if( __ERROR_buffer_errors == false ) {
459        return;
460    }
461
462    while( ERROR_with_lines ) {
463        struct heap_element * replace;
464        int parent, child;
465
466        /* pop off the top of the heap */
467        fprintf( stderr, "%s", heap[1].msg );
468
469        replace = &heap[ERROR_with_lines--];
470
471        child = 1;
472        while( 1 ) {
473            parent = child;
474            child = 2 * parent;
475            if( child > ERROR_with_lines ) {
476                break;
477            }
478            if( child + 1 <= ERROR_with_lines ) {
479                if( heap[child].line > heap[child + 1].line ) {
480                    child++;
481                }
482            }
483            if( replace->line <= heap[child].line ) {
484                break;
485            }
486            heap[parent] = heap[child];
487        }
488        heap[parent] = *replace;
489    }
490}
491
492void ERRORabort( int sig ) {
493    ERRORflush_messages();
494    if( !ERRORdebugging ) {
495        if( ERROR_unsafe ) {
496            longjmp( ERROR_safe_env, 1 );
497        }
498#ifdef SIGABRT
499        signal( SIGABRT, SIG_DFL );
500#endif
501        abort();
502    }
503
504    fprintf( stderr, "pausing...press ^C now to enter debugger: " );
505    pause();
506}
507
508void ERRORsafe( jmp_buf env ) {
509    memcpy( ERROR_safe_env, env, sizeof( jmp_buf ) );
510}
511
512void ERRORunsafe() {
513    ERROR_unsafe = true;
514}