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