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