/[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 1037 - (show annotations) (download) (as text)
Thu Jan 4 08:11:55 2007 UTC (15 years, 5 months ago) by johnpye
File MIME type: text/x-csrc
File size: 12988 byte(s)
Fixed a few more TestBlackBox test cases.
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,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,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 /* CONSOLE_DEBUG("TREE = %p",TREE); */
121 /* CONSOLE_DEBUG("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 static int writecount = 0;
237
238 asc_assert(TREE==NULL); /* else recursive calls will occur */
239
240 if(++writecount > 50){
241 CONSOLE_DEBUG("TOO MUCH WRITING");
242 return 0;
243 }
244
245 if(t->err){
246 res += error_reporter(t->err->sev, t->err->filename, t->err->line, t->err->func, t->err->msg);
247 }else{
248 /* CONSOLE_DEBUG("TREE HAS NO TOP-LEVEL ERROR"); */
249 }
250
251 if(t->head){
252 res += error_reporter_tree_write(t->head);
253 }
254 if(t->next){
255 res += error_reporter_tree_write(t->next);
256 }
257 return res;
258 }
259
260 #else /* ERROR_REPORTER_TREE_ACTIVE */
261 int error_reporter_tree_start(){
262 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Error reporter 'tree' turned off at compile time");
263 return 0;
264 }
265 int error_reporter_tree_end(){return 0;}
266 void error_reporter_tree_clear(){}
267 int error_reporter_tree_has_error(){
268 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Attempt to check 'tree_has_error' when 'tree' turned off at compile time");
269 return 0;
270 }
271 #endif /* ERROR_REPORTER_TREE_ACTIVE */
272
273 /*--------------------------
274 REALLY WHERE THE REPORTING HAPPENS
275 */
276
277 int
278 va_error_reporter(
279 const error_severity_t sev
280 , const char *errfile
281 , const int errline
282 , const char *errfunc
283 , const char *fmt
284 , const va_list args
285 ){
286 int res;
287
288 #ifdef ERROR_REPORTER_TREE_ACTIVE
289 error_reporter_tree_t *t;
290 if(sev != ASC_PROG_FATAL){
291 if(TREECURRENT){
292 /* add the error to the tree, don't output anything now */
293 t = error_reporter_tree_new();
294 t->err = error_reporter_meta_new();
295 res = vsnprintf(t->err->msg,ERROR_REPORTER_MAX_MSG,fmt,args);
296 t->err->filename = errfile;
297 t->err->func = errfunc;
298 t->err->line = errline;
299 t->err->sev = sev;
300 if(!TREECURRENT->head){
301 TREECURRENT->head = TREECURRENT->tail = t;
302 }else{
303 TREECURRENT->tail->next = t;
304 TREECURRENT->tail = t;
305 }
306 /* CONSOLE_DEBUG("Message (%d chars) added to tree",res); */
307 return res;
308 }else if(TREE){
309 /* flush the tree before outputting current message */
310 /* CONSOLE_DEBUG("WRITING OUT TREE CONTENTS"); */
311 t = TREE;
312 TREE = NULL;
313 error_reporter_tree_write(t);
314 CONSOLE_DEBUG("DONE WRITING TREE");
315 TREECURRENT = t;
316 error_reporter_tree_clear();
317 /* CONSOLE_DEBUG("DONE FREEING TREE");
318 CONSOLE_DEBUG("TREE = %p",TREE);
319 CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */
320 }
321 }
322 #endif
323
324 if(g_error_reporter_callback==NULL){
325 /* fprintf(stderr,"CALLING VFPRINTF\n"); */
326 res = error_reporter_default_callback(sev,errfile,errline,errfunc,fmt,args);
327 }else{
328 /* fprintf(stderr,"CALLING G_ERROR_REPORTER_CALLBACK\n"); */
329 res = g_error_reporter_callback(sev,errfile,errline,errfunc,fmt,args);
330 }
331
332 return res;
333 }
334
335 /*----------------------------
336 DROP-IN replacements for stdio.h / ascPrint.h
337 */
338
339 int vfprintf_error_reporter(FILE *file, const char *fmt, const va_list args){
340 char *msg;
341 int len;
342 int res;
343 if(file==stderr){
344 if(g_error_reporter_cache.iscaching){
345 msg = g_error_reporter_cache.msg;
346 len = strlen(msg);
347 res = vsnprintf(msg+len,ERROR_REPORTER_MAX_MSG-len,fmt,args);
348 if(len+res+1>=ERROR_REPORTER_MAX_MSG){
349 snprintf(msg+ERROR_REPORTER_MAX_MSG-16,15,"... (truncated)");
350 ASC_FPRINTF(stderr,"TRUNCATED MESSAGE, FULL MESSAGE FOLLOWS:\n----------START----------\n");
351 ASC_VFPRINTF(stderr,fmt,args);
352 ASC_FPRINTF(stderr,"\n-----------END----------\n");
353 }
354 }else{
355 /* Not caching: output all in one go as a ASC_PROG_NOTE */
356 res = va_error_reporter(ASC_PROG_NOTE,NULL,0,NULL,fmt,args);
357 }
358 }else{
359 res = ASC_VFPRINTF(file,fmt,args);
360 }
361 return res;
362 }
363
364 /**
365 This function performs caching of the error text if the flag is set
366 */
367 int
368 fprintf_error_reporter(FILE *file, const char *fmt, ...){
369 va_list args;
370 int res;
371
372 va_start(args,fmt);
373 res = vfprintf_error_reporter(file,fmt,args);
374 va_end(args);
375
376 return res;
377 }
378
379 int
380 fputc_error_reporter(int c, FILE *file){
381 if(file!=stderr){
382 return ASC_FPUTC(c,file);
383 }else if(fprintf_error_reporter(file,"%c",c) == 1){
384 return c;
385 }else{
386 return EOF;
387 }
388 }
389
390 int
391 fflush_error_reporter(FILE *file){
392 if(file!=stderr){
393 return ASC_FFLUSH(file);
394 }else{
395 return error_reporter_end_flush();
396 }
397 }
398
399 /*----------------------------
400 CACHING of multiple-FPRINTF error messages
401 */
402
403 int
404 error_reporter_start(const error_severity_t sev, const char *filename, const int line, const char *func){
405
406 if(g_error_reporter_cache.iscaching){
407 error_reporter_end_flush();
408 }
409 g_error_reporter_cache.iscaching = 1;
410 *(g_error_reporter_cache.msg) = '\0';
411 g_error_reporter_cache.sev = sev;
412 g_error_reporter_cache.filename = filename;
413 g_error_reporter_cache.line = line;
414 g_error_reporter_cache.func = func;
415
416 return 1;
417 }
418
419 int
420 error_reporter_end_flush(){
421 if(g_error_reporter_cache.iscaching){
422 error_reporter(
423 g_error_reporter_cache.sev
424 ,g_error_reporter_cache.filename
425 ,g_error_reporter_cache.line
426 ,g_error_reporter_cache.func
427 ,g_error_reporter_cache.msg
428 );
429 }else{
430 /* CONSOLE_DEBUG("IGNORING REPEATED CALL TO error_reporter_end_flush()"); */
431 }
432 g_error_reporter_cache.iscaching = 0;
433
434 return 0; /* output must be compatible with fflush */
435 }
436
437 /*--------------------------
438 REPORT the error
439 */
440 int
441 error_reporter(
442 const error_severity_t sev
443 , const char *errfile
444 , const int errline
445 , const char *errfunc
446 , const char *fmt
447 , ...
448 ){
449 int res;
450 va_list args;
451
452 va_start(args,fmt);
453 res = va_error_reporter(sev,errfile,errline,errfunc,fmt,args);
454 va_end(args);
455
456 return res;
457 }
458
459 /*-------------------------
460 SET the callback function
461 */
462 void
463 error_reporter_set_callback(
464 const error_reporter_callback_t new_callback
465 ){
466 g_error_reporter_callback = new_callback;
467 }
468
469 /*-------------------------
470 OPTIONAL code for systems not supporting variadic macros.
471 You know, your system probably does support variadic macros, it's just
472 a question of checking what your particular syntax is...
473 */
474
475 #ifdef NO_VARIADIC_MACROS
476 /* Following are only required on compilers without variadic macros: */
477
478 int error_reporter_note_no_line(const char *fmt,...){
479 int res;
480 va_list args;
481
482 va_start(args,fmt);
483 res = va_error_reporter(ASC_PROG_NOTE,"unknown-file",0,NULL,fmt,args);
484 va_end(args);
485
486 return res;
487 }
488
489 /**
490 Error reporter 'here' function for compilers not supporting
491 variadic macros.
492 */
493 ASC_DLLSPEC(int) error_reporter_here(const error_severity_t sev, const char *fmt,...){
494 int res;
495 va_list args;
496
497 va_start(args,fmt);
498 res = va_error_reporter(sev,"unknown-file",0,NULL,fmt,args);
499 va_end(args);
500
501 return res;
502 }
503
504
505 /**
506 Error reporter 'no line' function for compilers not supporting
507 variadic macros.
508 */
509 int error_reporter_noline(const error_severity_t sev, const char *fmt,...){
510 int res;
511 va_list args;
512
513 va_start(args,fmt);
514 res = va_error_reporter(sev,NULL,0,NULL,fmt,args);
515 va_end(args);
516
517 return res;
518 }
519
520 int console_debug(const char *fmt,...){
521 int res;
522 va_list args;
523
524 va_start(args,fmt);
525 res = Asc_VFPrintf(ASCERR,fmt,args);
526 va_end(args);
527
528 return res;
529 }
530
531 #endif /* NO_VARIADIC_MACROS */

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