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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 962 - (hide annotations) (download) (as text)
Mon Dec 11 14:43:02 2006 UTC (13 years, 9 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 johnpye 62 #include <string.h>
2    
3     #include "error.h"
4    
5 johnpye 931 #define ERROR_REPORTER_TREE_ACTIVE
6    
7     #ifdef ERROR_REPORTER_TREE_ACTIVE
8     # include "ascMalloc.h"
9 johnpye 932 # include "ascPanic.h"
10 johnpye 931 #endif
11    
12 johnpye 62 /**
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 johnpye 932 #ifdef ERROR_REPORTER_TREE_ACTIVE
25 johnpye 931 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 johnpye 932 #endif /* ERROR_REPORTER_TREE_ACTIVE */
37 johnpye 931
38 johnpye 190 /**
39 johnpye 586 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 johnpye 62 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 johnpye 586 char *color=NULL;
54 johnpye 62 char *endtxt="\n";
55     int res=0;
56     switch(sev){
57 johnpye 586 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 johnpye 62 case ASC_USER_NOTE: sevmsg = "NOTE: "; break;
64 johnpye 586 case ASC_USER_SUCCESS: color=ERR_GRN; sevmsg = "SUCCESS: "; break;
65 johnpye 62 }
66 johnpye 190
67 johnpye 586 color_on(ASCERR,color);
68 johnpye 62 res = ASC_FPRINTF(ASCERR,sevmsg);
69 johnpye 586 color_off(ASCERR);
70    
71 johnpye 62 if(filename!=NULL){
72 johnpye 222 res += ASC_FPRINTF(ASCERR,"%s:",filename);
73 johnpye 62 }
74 johnpye 222 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 johnpye 62 res += ASC_VFPRINTF(ASCERR,fmt,args);
85     res += ASC_FPRINTF(ASCERR,endtxt);
86 johnpye 190
87 johnpye 62 return res;
88     }
89    
90 johnpye 931 /*---------------------------------------------------------------------------
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 johnpye 932
99 johnpye 931 # define TREECURRENT g_error_reporter_tree_current
100     # define TREE g_error_reporter_tree
101    
102 johnpye 932 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 johnpye 931 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 johnpye 962 /* CONSOLE_DEBUG("TREE = %p",TREE); */
119     /* CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
120 johnpye 932
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 johnpye 931 if(TREE == NULL){
131 johnpye 962 /* CONSOLE_DEBUG("CREATING ROOT"); */
132 johnpye 931 /* we're creating the root */
133     tnew->parent = NULL;
134     TREE = tnew;
135     TREECURRENT = tnew;
136 johnpye 962 /* CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
137 johnpye 931 }else{
138 johnpye 932 asc_assert(TREECURRENT != NULL);
139 johnpye 962 /* CONSOLE_DEBUG("CREATING SUBTREE"); */
140 johnpye 931 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 johnpye 962 /* CONSOLE_DEBUG("SET TREECURRENT TO %p",TREECURRENT); */
153 johnpye 931 TREECURRENT = tnew;
154     }
155     return 0;
156     }
157 johnpye 932
158 johnpye 931 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 johnpye 962 /* CONSOLE_DEBUG("SET TREECURRENT TO %p",TREECURRENT); */
166 johnpye 931 return 0;
167     }
168    
169     static void error_reporter_tree_free(error_reporter_tree_t *t){
170 johnpye 932 if(t->head){
171     error_reporter_tree_free(t->head);
172     }
173     if(t->next){
174     error_reporter_tree_free(t->next);
175     }
176 johnpye 931 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 johnpye 932 TREE = NULL;
191 johnpye 931 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 johnpye 932 if(t->err && (t->err->sev & match)){
199 johnpye 937 /* CONSOLE_DEBUG("SEVERITY MATCH FOR t = %p",t); */
200 johnpye 932 return 1;
201     }
202     if(t->next && error_reporter_tree_match_sev(t->next, match)){
203 johnpye 937 /* CONSOLE_DEBUG("SEVERITY MATCH IN 'next' FOR t = %p",t); */
204 johnpye 932 return 1;
205     }
206     if(t->head && error_reporter_tree_match_sev(t->head, match)){
207 johnpye 937 /* CONSOLE_DEBUG("SEVERITTY MATCH IN 'head' FOR t = %p",t); */
208 johnpye 932 return 1;
209     }
210 johnpye 937 /* CONSOLE_DEBUG("NO MATCH FOR t = %p",t); */
211 johnpye 931 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 johnpye 933 int res;
220 johnpye 931 if(TREECURRENT){
221 johnpye 933 res = error_reporter_tree_match_sev(TREECURRENT,ASC_ERR_ERR);
222 johnpye 937 if(res){
223     /* CONSOLE_DEBUG("ERROR(S) FOUND IN TREECURRENT %p",TREECURRENT); */
224     }
225 johnpye 933 return res;
226 johnpye 931 }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 johnpye 937 asc_assert(TREE==NULL); /* else recursive calls will occur */
237    
238 johnpye 931 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 johnpye 932 /* CONSOLE_DEBUG("TREE HAS NO TOP-LEVEL ERROR"); */
247 johnpye 931 }
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 johnpye 932 return 0;
262 johnpye 931 }
263 johnpye 932 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 johnpye 931 #endif /* ERROR_REPORTER_TREE_ACTIVE */
270    
271 johnpye 62 /*--------------------------
272 johnpye 931 REALLY WHERE THE REPORTING HAPPENS
273 johnpye 62 */
274 johnpye 931
275 johnpye 62 int
276     va_error_reporter(
277 johnpye 222 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 johnpye 62 ){
284     int res;
285    
286 johnpye 931 #ifdef ERROR_REPORTER_TREE_ACTIVE
287     error_reporter_tree_t *t;
288 johnpye 932 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 johnpye 962 /* CONSOLE_DEBUG("WRITING OUT TREE CONTENTS"); */
309 johnpye 932 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 johnpye 962 /* CONSOLE_DEBUG("DONE FREEING TREE");
316 johnpye 932 CONSOLE_DEBUG("TREE = %p",TREE);
317 johnpye 962 CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
318 johnpye 931 }
319     }
320     #endif
321    
322 johnpye 62 if(g_error_reporter_callback==NULL){
323     /* fprintf(stderr,"CALLING VFPRINTF\n"); */
324 johnpye 222 res = error_reporter_default_callback(sev,errfile,errline,errfunc,fmt,args);
325 johnpye 62 }else{
326     /* fprintf(stderr,"CALLING G_ERROR_REPORTER_CALLBACK\n"); */
327 johnpye 222 res = g_error_reporter_callback(sev,errfile,errline,errfunc,fmt,args);
328 johnpye 62 }
329 johnpye 190
330 johnpye 62 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 johnpye 127 snprintf(msg+ERROR_REPORTER_MAX_MSG-16,15,"... (truncated)");
357 johnpye 62 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 johnpye 222 res = va_error_reporter(ASC_PROG_NOTE,NULL,0,NULL,fmt,args);
364 johnpye 62 }
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 johnpye 222 error_reporter_start(const error_severity_t sev, const char *filename, const int line, const char *func){
400 johnpye 190
401 johnpye 62 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 johnpye 222 g_error_reporter_cache.func = func;
410 johnpye 62
411     return 1;
412     }
413    
414     int
415     error_reporter_end_flush(){
416 johnpye 936 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 johnpye 62 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 johnpye 222 const error_severity_t sev
438     , const char *errfile
439     , const int errline
440     , const char *errfunc
441     , const char *fmt
442     , ...
443 johnpye 62 ){
444     int res;
445     va_list args;
446    
447     va_start(args,fmt);
448 johnpye 222 res = va_error_reporter(sev,errfile,errline,errfunc,fmt,args);
449 johnpye 62 va_end(args);
450    
451     return res;
452     }
453    
454 johnpye 379 /*-------------------------
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 johnpye 427 #ifdef NO_VARIADIC_MACROS
471 johnpye 85 /* Following are only required on compilers without variadic macros: */
472    
473 johnpye 62 int error_reporter_note_no_line(const char *fmt,...){
474     int res;
475     va_list args;
476    
477     va_start(args,fmt);
478 johnpye 490 res = va_error_reporter(ASC_PROG_NOTE,"unknown-file",0,NULL,fmt,args);
479 johnpye 62 va_end(args);
480    
481     return res;
482     }
483 johnpye 85
484 johnpye 190 /**
485 johnpye 188 Error reporter 'here' function for compilers not supporting
486     variadic macros.
487     */
488 johnpye 513 ASC_DLLSPEC(int) error_reporter_here(const error_severity_t sev, const char *fmt,...){
489 johnpye 188 int res;
490     va_list args;
491    
492     va_start(args,fmt);
493 johnpye 490 res = va_error_reporter(sev,"unknown-file",0,NULL,fmt,args);
494 johnpye 188 va_end(args);
495    
496     return res;
497     }
498    
499 johnpye 190
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 johnpye 490 res = va_error_reporter(sev,NULL,0,NULL,fmt,args);
510 johnpye 190 va_end(args);
511    
512     return res;
513     }
514    
515 johnpye 85 int console_debug(const char *fmt,...){
516     int res;
517     va_list args;
518    
519     va_start(args,fmt);
520 johnpye 86 res = Asc_VFPrintf(ASCERR,fmt,args);
521 johnpye 85 va_end(args);
522    
523     return res;
524 johnpye 86 }
525 johnpye 931
526 johnpye 427 #endif /* NO_VARIADIC_MACROS */

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