/[ascend]/trunk/base/generic/utilities/error.c
ViewVC logotype

Contents of /trunk/base/generic/utilities/error.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 962 - (show annotations) (download) (as text)
Mon Dec 11 14:43:02 2006 UTC (13 years, 7 months ago) by johnpye
File MIME type: text/x-csrc
File size: 12891 byte(s)
Adding more LSODE test cases.
Removing some 'error tree' debug output.
Added RTOLDEF and ATOLDEF parameters to LSODE (and fixed a bug relating to integrator_lsode_params_default).
1 #include <string.h>
2
3 #include "error.h"
4
5 #define ERROR_REPORTER_TREE_ACTIVE
6
7 #ifdef ERROR_REPORTER_TREE_ACTIVE
8 # include "ascMalloc.h"
9 # include "ascPanic.h"
10 #endif
11
12 /**
13 Global variable which stores the pointer to the callback
14 function being used.
15 */
16 static error_reporter_callback_t g_error_reporter_callback;
17
18 /**
19 Global variable which holds cached error info for
20 later output
21 */
22 static error_reporter_meta_t g_error_reporter_cache;
23
24 #ifdef ERROR_REPORTER_TREE_ACTIVE
25 static error_reporter_meta_t *error_reporter_meta_new(){
26 error_reporter_meta_t *e;
27 e = ASC_NEW(error_reporter_meta_t);
28 e->sev = ASC_USER_SUCCESS;
29 e->iscaching = 0;
30 e->filename = NULL;
31 e->func = NULL;
32 e->line = 0;
33 e->msg[0] = '\0';
34 return e;
35 }
36 #endif /* ERROR_REPORTER_TREE_ACTIVE */
37
38 /**
39 XTERM colour codes used to distinguish between errors of different types.
40 */
41 # define ERR_RED "31;1"
42 # define ERR_GRN "32;2"
43 # define ERR_BLU "34;1"
44 # define ERR_BRN "33;1"
45 # define ERR_BOLD "1"
46
47 /**
48 Default error reporter. To use this error reporter, set
49 the callback pointer to NULL.
50 */
51 int error_reporter_default_callback(ERROR_REPORTER_CALLBACK_ARGS){
52 char *sevmsg="";
53 char *color=NULL;
54 char *endtxt="\n";
55 int res=0;
56 switch(sev){
57 case ASC_PROG_FATAL: color=ERR_RED; sevmsg = "PROGRAM FATAL ERROR: "; break;
58 case ASC_PROG_ERROR: color=ERR_RED; sevmsg = "PROGRAM ERROR: "; break;
59 case ASC_PROG_WARNING: color=ERR_BOLD;sevmsg = "PROGRAM WARNING: "; break;
60 case ASC_PROG_NOTE: color=ERR_GRN; endtxt=""; break; /* default, keep unembellished for now */
61 case ASC_USER_ERROR: color=ERR_RED; sevmsg = "ERROR: "; break;
62 case ASC_USER_WARNING: color=ERR_BRN; sevmsg = "WARNING: "; break;
63 case ASC_USER_NOTE: sevmsg = "NOTE: "; break;
64 case ASC_USER_SUCCESS: color=ERR_GRN; sevmsg = "SUCCESS: "; break;
65 }
66
67 color_on(ASCERR,color);
68 res = ASC_FPRINTF(ASCERR,sevmsg);
69 color_off(ASCERR);
70
71 if(filename!=NULL){
72 res += ASC_FPRINTF(ASCERR,"%s:",filename);
73 }
74 if(line!=0){
75 res += ASC_FPRINTF(ASCERR,"%d:",line);
76 }
77 if(funcname!=NULL){
78 res += ASC_FPRINTF(ASCERR,"%s:",funcname);
79 }
80 if ((filename!=NULL) || (line!=0) || (funcname!=NULL)){
81 res += ASC_FPRINTF(ASCERR," ");
82 }
83
84 res += ASC_VFPRINTF(ASCERR,fmt,args);
85 res += ASC_FPRINTF(ASCERR,endtxt);
86
87 return res;
88 }
89
90 /*---------------------------------------------------------------------------
91 ERROR REPORTER TREE (BRANCHABLE ERROR STACK) FUNCTIONALITY
92 */
93
94 #ifdef ERROR_REPORTER_TREE_ACTIVE
95
96 static error_reporter_tree_t *g_error_reporter_tree = NULL;
97 static error_reporter_tree_t *g_error_reporter_tree_current = NULL;
98
99 # define TREECURRENT g_error_reporter_tree_current
100 # define TREE g_error_reporter_tree
101
102 static int error_reporter_tree_write(error_reporter_tree_t *t);
103 static void error_reporter_tree_free(error_reporter_tree_t *t);
104
105 static error_reporter_tree_t *error_reporter_tree_new(){
106 error_reporter_tree_t *tnew = ASC_NEW(error_reporter_tree_t);
107 tnew->next = NULL;
108 tnew->head = NULL;
109 tnew->tail = NULL;
110 tnew->err = NULL;
111 return tnew;
112 }
113
114 int error_reporter_tree_start(){
115 error_reporter_tree_t *tnew;
116 tnew = error_reporter_tree_new();
117
118 /* CONSOLE_DEBUG("TREE = %p",TREE); */
119 /* CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
120
121 #if 0
122 if(TREE != NULL && TREECURRENT == NULL){
123 CONSOLE_DEBUG("CALLED WITH NULL TREECURRENT BUT NON-NULL TREE");
124 error_reporter_tree_write(TREE);
125 error_reporter_tree_free(TREE);
126 TREE = NULL;
127 }
128 #endif
129
130 if(TREE == NULL){
131 /* CONSOLE_DEBUG("CREATING ROOT"); */
132 /* we're creating the root */
133 tnew->parent = NULL;
134 TREE = tnew;
135 TREECURRENT = tnew;
136 /* CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
137 }else{
138 asc_assert(TREECURRENT != NULL);
139 /* CONSOLE_DEBUG("CREATING SUBTREE"); */
140 if(TREECURRENT->head == NULL){
141 /* if the current tree has no elements, add it as the head */
142 TREECURRENT->head = tnew;
143 }else{
144 /* link the new tree to the last in the child list */
145 TREECURRENT->tail->next = tnew;
146 }
147 /* update the tail of the list */
148 TREECURRENT->tail = tnew;
149
150 /* now switch the context to the sub-tree */
151 tnew->parent = TREECURRENT;
152 /* CONSOLE_DEBUG("SET TREECURRENT TO %p",TREECURRENT); */
153 TREECURRENT = tnew;
154 }
155 return 0;
156 }
157
158 int error_reporter_tree_end(){
159 CONSOLE_DEBUG("TREE END");
160 if(!TREECURRENT){
161 ERROR_REPORTER_HERE(ASC_PROG_ERR,"'end' without TREECURRENT set");
162 return 1;
163 }
164 TREECURRENT = TREECURRENT->parent;
165 /* CONSOLE_DEBUG("SET TREECURRENT TO %p",TREECURRENT); */
166 return 0;
167 }
168
169 static void error_reporter_tree_free(error_reporter_tree_t *t){
170 if(t->head){
171 error_reporter_tree_free(t->head);
172 }
173 if(t->next){
174 error_reporter_tree_free(t->next);
175 }
176 if(t->err)ASC_FREE(t->err);
177 ASC_FREE(t);
178 }
179
180 void error_reporter_tree_clear(){
181 /* recursively free anything beneath the TREECURRENT node, return to the parent context */
182 error_reporter_tree_t *t;
183 if(!TREECURRENT){
184 /* CONSOLE_DEBUG("NOTHING TO CLEAR!"); */
185 return;
186 }
187 if(TREECURRENT->parent){
188 t = TREECURRENT->parent;
189 }else{
190 TREE = NULL;
191 t = NULL;
192 }
193 error_reporter_tree_free(TREECURRENT);
194 TREECURRENT = t;
195 }
196
197 static int error_reporter_tree_match_sev(error_reporter_tree_t *t, unsigned match){
198 if(t->err && (t->err->sev & match)){
199 /* CONSOLE_DEBUG("SEVERITY MATCH FOR t = %p",t); */
200 return 1;
201 }
202 if(t->next && error_reporter_tree_match_sev(t->next, match)){
203 /* CONSOLE_DEBUG("SEVERITY MATCH IN 'next' FOR t = %p",t); */
204 return 1;
205 }
206 if(t->head && error_reporter_tree_match_sev(t->head, match)){
207 /* CONSOLE_DEBUG("SEVERITTY MATCH IN 'head' FOR t = %p",t); */
208 return 1;
209 }
210 /* CONSOLE_DEBUG("NO MATCH FOR t = %p",t); */
211 return 0;
212 }
213
214 /**
215 traverse the tree, looking for ASC_PROG_ERR, ASC_USER_ERROR, or ASC_PROG_FATAL
216 @return 1 if errors found
217 */
218 int error_reporter_tree_has_error(){
219 int res;
220 if(TREECURRENT){
221 res = error_reporter_tree_match_sev(TREECURRENT,ASC_ERR_ERR);
222 if(res){
223 /* CONSOLE_DEBUG("ERROR(S) FOUND IN TREECURRENT %p",TREECURRENT); */
224 }
225 return res;
226 }else{
227 CONSOLE_DEBUG("NO TREE FOUND");
228 return 0;
229 }
230 }
231
232 static int error_reporter_tree_write(error_reporter_tree_t *t){
233 int res = 0;
234 static int writecount = 0;
235
236 asc_assert(TREE==NULL); /* else recursive calls will occur */
237
238 if(++writecount > 30){
239 CONSOLE_DEBUG("TOO MUCH WRITING");
240 return 0;
241 }
242
243 if(t->err){
244 res += error_reporter(t->err->sev, t->err->filename, t->err->line, t->err->func, t->err->msg);
245 }else{
246 /* CONSOLE_DEBUG("TREE HAS NO TOP-LEVEL ERROR"); */
247 }
248
249 if(t->head){
250 res += error_reporter_tree_write(t->head);
251 }
252 if(t->next){
253 res += error_reporter_tree_write(t->next);
254 }
255 return res;
256 }
257
258 #else /* ERROR_REPORTER_TREE_ACTIVE */
259 int error_reporter_tree_start(){
260 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Error reporter 'tree' turned off at compile time");
261 return 0;
262 }
263 int error_reporter_tree_end(){return 0;}
264 void error_reporter_tree_clear(){}
265 int error_reporter_tree_has_error(){
266 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Attempt to check 'tree_has_error' when 'tree' turned off at compile time");
267 return 0;
268 }
269 #endif /* ERROR_REPORTER_TREE_ACTIVE */
270
271 /*--------------------------
272 REALLY WHERE THE REPORTING HAPPENS
273 */
274
275 int
276 va_error_reporter(
277 const error_severity_t sev
278 , const char *errfile
279 , const int errline
280 , const char *errfunc
281 , const char *fmt
282 , const va_list args
283 ){
284 int res;
285
286 #ifdef ERROR_REPORTER_TREE_ACTIVE
287 error_reporter_tree_t *t;
288 if(sev != ASC_PROG_FATAL){
289 if(TREECURRENT){
290 /* add the error to the tree, don't output anything now */
291 t = error_reporter_tree_new();
292 t->err = error_reporter_meta_new();
293 res = vsnprintf(t->err->msg,ERROR_REPORTER_MAX_MSG,fmt,args);
294 t->err->filename = errfile;
295 t->err->func = errfunc;
296 t->err->line = errline;
297 t->err->sev = sev;
298 if(!TREECURRENT->head){
299 TREECURRENT->head = TREECURRENT->tail = t;
300 }else{
301 TREECURRENT->tail->next = t;
302 TREECURRENT->tail = t;
303 }
304 /* CONSOLE_DEBUG("Message (%d chars) added to tree",res); */
305 return res;
306 }else if(TREE){
307 /* flush the tree before outputting current message */
308 /* CONSOLE_DEBUG("WRITING OUT TREE CONTENTS"); */
309 t = TREE;
310 TREE = NULL;
311 error_reporter_tree_write(t);
312 CONSOLE_DEBUG("DONE WRITING TREE");
313 TREECURRENT = t;
314 error_reporter_tree_clear();
315 /* CONSOLE_DEBUG("DONE FREEING TREE");
316 CONSOLE_DEBUG("TREE = %p",TREE);
317 CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
318 }
319 }
320 #endif
321
322 if(g_error_reporter_callback==NULL){
323 /* fprintf(stderr,"CALLING VFPRINTF\n"); */
324 res = error_reporter_default_callback(sev,errfile,errline,errfunc,fmt,args);
325 }else{
326 /* fprintf(stderr,"CALLING G_ERROR_REPORTER_CALLBACK\n"); */
327 res = g_error_reporter_callback(sev,errfile,errline,errfunc,fmt,args);
328 }
329
330 return res;
331 }
332
333 /*----------------------------
334 DROP-IN replacements for stdio.h / ascPrint.h
335 */
336
337 /**
338 This function performs caching of the error text if the flag is set
339 */
340 int
341 fprintf_error_reporter(FILE *file, const char *fmt, ...){
342 va_list args;
343 char *msg;
344 int len;
345 int res;
346
347 /* fprintf(stderr,"ENTERED FPRINTF_ERROR_REPORTER\n"); */
348
349 va_start(args,fmt);
350 if(file==stderr){
351 if(g_error_reporter_cache.iscaching){
352 msg = g_error_reporter_cache.msg;
353 len = strlen(msg);
354 res = vsnprintf(msg+len,ERROR_REPORTER_MAX_MSG-len,fmt,args);
355 if(len+res+1>=ERROR_REPORTER_MAX_MSG){
356 snprintf(msg+ERROR_REPORTER_MAX_MSG-16,15,"... (truncated)");
357 ASC_FPRINTF(stderr,"TRUNCATED MESSAGE, FULL MESSAGE FOLLOWS:\n----------START----------\n");
358 ASC_VFPRINTF(stderr,fmt,args);
359 ASC_FPRINTF(stderr,"\n-----------END----------\n");
360 }
361 }else{
362 /* Not caching: output all in one go as a ASC_PROG_NOTE */
363 res = va_error_reporter(ASC_PROG_NOTE,NULL,0,NULL,fmt,args);
364 }
365 }else{
366 res = ASC_VFPRINTF(file,fmt,args);
367 }
368
369 va_end(args);
370
371 return res;
372 }
373
374 int
375 fputc_error_reporter(int c, FILE *file){
376 if(file!=stderr){
377 return ASC_FPUTC(c,file);
378 }else if(fprintf_error_reporter(file,"%c",c) == 1){
379 return c;
380 }else{
381 return EOF;
382 }
383 }
384
385 int
386 fflush_error_reporter(FILE *file){
387 if(file!=stderr){
388 return ASC_FFLUSH(file);
389 }else{
390 return error_reporter_end_flush();
391 }
392 }
393
394 /*----------------------------
395 CACHING of multiple-FPRINTF error messages
396 */
397
398 int
399 error_reporter_start(const error_severity_t sev, const char *filename, const int line, const char *func){
400
401 if(g_error_reporter_cache.iscaching){
402 error_reporter_end_flush();
403 }
404 g_error_reporter_cache.iscaching = 1;
405 *(g_error_reporter_cache.msg) = '\0';
406 g_error_reporter_cache.sev = sev;
407 g_error_reporter_cache.filename = filename;
408 g_error_reporter_cache.line = line;
409 g_error_reporter_cache.func = func;
410
411 return 1;
412 }
413
414 int
415 error_reporter_end_flush(){
416 if(g_error_reporter_cache.iscaching){
417 error_reporter(
418 g_error_reporter_cache.sev
419 ,g_error_reporter_cache.filename
420 ,g_error_reporter_cache.line
421 ,g_error_reporter_cache.func
422 ,g_error_reporter_cache.msg
423 );
424 }else{
425 /* CONSOLE_DEBUG("IGNORING REPEATED CALL TO error_reporter_end_flush()"); */
426 }
427 g_error_reporter_cache.iscaching = 0;
428
429 return 0; /* output must be compatible with fflush */
430 }
431
432 /*--------------------------
433 REPORT the error
434 */
435 int
436 error_reporter(
437 const error_severity_t sev
438 , const char *errfile
439 , const int errline
440 , const char *errfunc
441 , const char *fmt
442 , ...
443 ){
444 int res;
445 va_list args;
446
447 va_start(args,fmt);
448 res = va_error_reporter(sev,errfile,errline,errfunc,fmt,args);
449 va_end(args);
450
451 return res;
452 }
453
454 /*-------------------------
455 SET the callback function
456 */
457 void
458 error_reporter_set_callback(
459 const error_reporter_callback_t new_callback
460 ){
461 g_error_reporter_callback = new_callback;
462 }
463
464 /*-------------------------
465 OPTIONAL code for systems not supporting variadic macros.
466 You know, your system probably does support variadic macros, it's just
467 a question of checking what your particular syntax is...
468 */
469
470 #ifdef NO_VARIADIC_MACROS
471 /* Following are only required on compilers without variadic macros: */
472
473 int error_reporter_note_no_line(const char *fmt,...){
474 int res;
475 va_list args;
476
477 va_start(args,fmt);
478 res = va_error_reporter(ASC_PROG_NOTE,"unknown-file",0,NULL,fmt,args);
479 va_end(args);
480
481 return res;
482 }
483
484 /**
485 Error reporter 'here' function for compilers not supporting
486 variadic macros.
487 */
488 ASC_DLLSPEC(int) error_reporter_here(const error_severity_t sev, const char *fmt,...){
489 int res;
490 va_list args;
491
492 va_start(args,fmt);
493 res = va_error_reporter(sev,"unknown-file",0,NULL,fmt,args);
494 va_end(args);
495
496 return res;
497 }
498
499
500 /**
501 Error reporter 'no line' function for compilers not supporting
502 variadic macros.
503 */
504 int error_reporter_noline(const error_severity_t sev, const char *fmt,...){
505 int res;
506 va_list args;
507
508 va_start(args,fmt);
509 res = va_error_reporter(sev,NULL,0,NULL,fmt,args);
510 va_end(args);
511
512 return res;
513 }
514
515 int console_debug(const char *fmt,...){
516 int res;
517 va_list args;
518
519 va_start(args,fmt);
520 res = Asc_VFPrintf(ASCERR,fmt,args);
521 va_end(args);
522
523 return res;
524 }
525
526 #endif /* NO_VARIADIC_MACROS */

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22