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

Contents of /trunk/ascend/utilities/error.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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