PageRenderTime 36ms CodeModel.GetById 13ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 523 lines | 329 code | 67 blank | 127 comment | 47 complexity | b592c33629c4f70dc8eb494b14aaf55b 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/** Clean up the Error module */
146void ERRORcleanup( void ) {
147    ERRORdestroy( ERROR_subordinate_failed );
148    ERRORdestroy( ERROR_syntax_expecting );
149
150    scl_free( ERROR_string_base );
151}
152
153/** Need the LIST routines to complete ERROR initialization */
154void ERRORinitialize_after_LIST( void ) {
155    ERRORwarnings = LISTcreate();
156
157    MEMinitialize( &ERROR_OPT_fl, sizeof( struct Error_Warning_ ), 5, 5 );
158}
159
160void ERRORcreate_warning( char * name, Error error ) {
161    struct Error_Warning_ *o;
162
163    /* first check if we know about this type of error */
164    LISTdo( ERRORwarnings, opt, Error_Warning )
165    if( streq( name, opt->name ) ) {
166        LISTadd( opt->errors, ( Generic )error );
167        return;
168    }
169    LISTod
170
171    /* new error */
172    o = ERROR_OPT_new();
173    o->name = name;
174    o->errors = LISTcreate();
175    LISTadd( o->errors, ( Generic )error );
176    LISTadd( ERRORwarnings, ( Generic )o );
177}
178
179void ERRORset_warning( char * name, int set ) {
180    bool found = false;
181
182    if( streq( name, "all" ) ) {
183        ERRORset_all_warnings( set );
184    } else if( streq( name, "none" ) ) {
185        ERRORset_all_warnings( !set );
186    } else {
187        LISTdo( ERRORwarnings, opt, Error_Warning )
188        if( streq( opt->name, name ) ) {
189            found = true;
190            LISTdo( opt->errors, err, Error )
191            err->enabled = set;
192            LISTod
193        }
194        LISTod
195        if( found ) {
196            return;
197        }
198
199        fprintf( stderr, "unknown warning: %s\n", name );
200        if( ERRORusage_function ) {
201            ( *ERRORusage_function )();
202        }
203    }
204}
205
206/** \fn ERRORdisable
207** \param error error to disable
208** Disable an error (ERRORreport*() will ignore it)
209** \note this function is inlined in error.h
210*/
211
212/** \fn ERRORenable
213** \param error error to enable
214** Enable an error (ERRORreport*() will report it)
215** \note this function is inlined in error.h
216*/
217
218/** \fn ERRORis_enabled
219** \param error error to test
220** \return is reporting of the error enabled?
221** Check whether an error is enabled
222** \note this function is inlined in error.h
223*/
224
225/** \fn ERRORreport
226** \param what error to report
227** \param ... arguments for error string
228** Print a report of an error
229**
230** Notes:   The second and subsequent arguments should match the
231**      format fields of the message generated by 'what.'
232*/
233void ERRORset_all_warnings( int set ) {
234    LISTdo( ERRORwarnings, opts, Error_Warning )
235    LISTdo( opts->errors, err, Error )
236    err->enabled = set;
237    LISTod
238    LISTod
239}
240
241void
242#ifdef __STDC__
243ERRORreport( Error what, ... ) {
244#else
245ERRORreport( va_alist )
246va_dcl {
247    Error what;
248#endif
249    /*    extern void abort(void);*/
250    va_list args;
251
252#ifdef __STDC__
253    va_start( args, what );
254#else
255    va_start( args );
256    what = va_arg( args, Error );
257#endif
258
259    if( ( what != ERROR_none ) &&
260    ( what != ERROR_subordinate_failed ) &&
261    what->enabled ) {
262        if( what->severity >= SEVERITY_ERROR ) {
263            fprintf( error_file, "ERROR: " );
264            vfprintf( error_file, what->message, args );
265            fputc( '\n', error_file );
266            ERRORoccurred = true;
267        } else if( what->severity >= SEVERITY_WARNING ) {
268            fprintf( error_file, "WARNING: ");
269            vfprintf( error_file, what->message, args );
270            fputc( '\n', error_file );
271        }
272        if( what->severity >= SEVERITY_EXIT ) {
273            ERROR_flush_message_buffer();
274            if( what->severity >= SEVERITY_DUMP ) {
275                abort();
276            } else {
277                exit( EXPRESS_fail( ( Express )0 ) );
278            }
279        }
280    }
281    experrc = ERROR_none;
282    va_end( args );
283}
284
285/**
286** \param what error to report
287** \param line line number of error
288** \param ... arguments for error string
289** Print a report of an error, including a line number
290**
291** \note The third and subsequent arguments should match the
292**      format fields of the message generated by 'what.'
293*/
294void
295#ifdef __STDC__
296ERRORreport_with_line( Error what, int line, ... ) {
297#else
298ERRORreport_with_line( va_alist )
299va_dcl {
300    Error what;
301    int line;
302#endif
303
304    char buf[BUFSIZ];
305    char * savemsg; /* save what->message here while we fool */
306    /* ERRORreport_with_line */
307    Symbol sym;
308    va_list args;
309#ifdef __STDC__
310    va_start( args, line );
311#else
312    va_start( args );
313    what = va_arg( args, Error );
314    line = va_arg( args, int );
315#endif
316
317    sym.filename = current_filename;
318    sym.line = line;
319
320    vsprintf( buf, what->message, args );
321
322    /* gross, but there isn't any way to do this more directly */
323    /* without writing yet another variant of ERRORreport_with_line */
324    savemsg = what->message;
325    what->message = "%s";
326    ERRORreport_with_symbol( what, &sym, buf );
327    what->message = savemsg;
328}
329
330void
331#ifdef __STDC__
332ERRORreport_with_symbol( Error what, Symbol * sym, ... ) {
333#else
334ERRORreport_with_symbol( va_alist )
335va_dcl {
336    Error what;
337    Symbol * sym;
338#endif
339    /*    extern void abort(void);*/
340    va_list args;
341
342#ifdef __STDC__
343    va_start( args, sym );
344#else
345    va_start( args );
346    what = va_arg( args, Error );
347    sym = va_arg( args, Symbol * );
348#endif
349
350    if( ( what != ERROR_none ) && ( what != ERROR_subordinate_failed ) && what->enabled ) {
351        if( __ERROR_buffer_errors ) {
352            int child, parent;
353
354            /*
355             * add an element to the heap
356             * by (logically) storing the new value
357             * at the end of the array and bubbling
358             * it up as necessary
359             */
360
361            child = ++ERROR_with_lines;
362            parent = child / 2;
363            while( parent ) {
364                if( sym->line < heap[parent].line ) {
365                    heap[child] = heap[parent];
366                } else {
367                    break;
368                }
369                child = parent;
370                parent = child / 2;
371            }
372            heap[child].line = sym->line;
373            heap[child].msg = ERROR_string;
374
375            if( what->severity >= SEVERITY_ERROR ) {
376                sprintf( ERROR_string, "%s:%d: --ERROR: ", 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                ERRORoccurred = true;
383            } else if( what->severity >= SEVERITY_WARNING ) {
384                sprintf( ERROR_string, "%s:%d: WARNING: ", sym->filename, sym->line );
385                ERROR_string += strlen( ERROR_string );
386                vsprintf( ERROR_string, what->message, args );
387                ERROR_string += strlen( ERROR_string );
388                *ERROR_string++ = '\n';
389                *ERROR_string++ = '\0';
390            }
391            if( what->severity >= SEVERITY_EXIT ||
392                    ERROR_string + ERROR_MAX_STRLEN > ERROR_string_base + ERROR_MAX_SPACE ||
393                    ERROR_with_lines == ERROR_MAX_ERRORS ) {
394                ERROR_flush_message_buffer();
395                if( what->severity >= SEVERITY_DUMP ) {
396                    abort();
397                } else {
398                    exit( EXPRESS_fail( ( Express )0 ) );
399                }
400            }
401        } else {
402            if( what->severity >= SEVERITY_ERROR ) {
403                fprintf( error_file, "%s:%d: --ERROR: ", sym->filename, sym->line );
404                vfprintf( error_file, what->message, args );
405                fprintf( error_file, "\n" );
406                ERRORoccurred = true;
407            } else if( what->severity >= SEVERITY_WARNING ) {
408                fprintf( error_file, "%s:%d: WARNING: ", sym->filename, sym->line );
409                ERROR_string += strlen( ERROR_string ) + 1;
410                vfprintf( error_file, what->message, args );
411                fprintf( error_file, "\n" );
412            }
413            if( what->severity >= SEVERITY_EXIT ) {
414                if( what->severity >= SEVERITY_DUMP ) {
415                    abort();
416                } else {
417                    exit( EXPRESS_fail( ( Express )0 ) );
418                }
419            }
420        }
421    }
422    experrc = ERROR_none;
423    va_end( args );
424}
425
426void ERRORnospace() {
427    fprintf( stderr, "%s: out of space\n", EXPRESSprogram_name );
428    ERRORabort( 0 );
429}
430
431/**
432** \param message error message
433** \param severity severity of error
434** \return newly created error
435** Create a new error
436*/
437Error ERRORcreate( char * message, Severity severity ) {
438    Error n;
439
440    n = ( struct Error_ * )scl_malloc( sizeof( struct Error_ ) );
441    n->message = message;
442    n->severity = severity;
443    n->enabled = true;
444    return n;
445}
446
447void ERRORdestroy( Error error ) {
448    scl_free( error );
449}
450
451/** \fn ERRORbuffer_messages
452** \param flag    - to buffer or not to buffer
453** Selects buffering of error messages
454** \note this function is inlined in error.h
455*/
456
457/** \fn ERRORflush_messages
458** Flushes the error message buffer to standard output.
459** \note this function is inlined in error.h
460**
461** \note The error messages are sorted by line number (which appears in the third column).
462*/
463
464void ERROR_start_message_buffer( void ) {
465    ERROR_string = ERROR_string_base;
466    ERROR_with_lines = 0;
467}
468
469void ERROR_flush_message_buffer( void ) {
470    if( __ERROR_buffer_errors == false ) {
471        return;
472    }
473
474    while( ERROR_with_lines ) {
475        struct heap_element * replace;
476        int parent, child;
477
478        /* pop off the top of the heap */
479        fprintf( stderr, "%s", heap[1].msg );
480
481        replace = &heap[ERROR_with_lines--];
482
483        child = 1;
484        while( 1 ) {
485            parent = child;
486            child = 2 * parent;
487            if( child > ERROR_with_lines ) {
488                break;
489            }
490            if( child + 1 <= ERROR_with_lines ) {
491                if( heap[child].line > heap[child + 1].line ) {
492                    child++;
493                }
494            }
495            if( replace->line <= heap[child].line ) {
496                break;
497            }
498            heap[parent] = heap[child];
499        }
500        heap[parent] = *replace;
501    }
502}
503
504void ERRORabort( int sig ) {
505    ERRORflush_messages();
506    if( !ERRORdebugging ) {
507        if( ERROR_unsafe ) {
508            longjmp( ERROR_safe_env, 1 );
509        }
510#ifdef SIGABRT
511        signal( SIGABRT, SIG_DFL );
512#endif
513        abort();
514    }
515}
516
517void ERRORsafe( jmp_buf env ) {
518    memcpy( ERROR_safe_env, env, sizeof( jmp_buf ) );
519}
520
521void ERRORunsafe() {
522    ERROR_unsafe = true;
523}