/[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 933 - (show annotations) (download) (as text)
Thu Nov 23 22:28:00 2006 UTC (17 years, 8 months ago) by johnpye
File MIME type: text/x-csrc
File size: 12599 byte(s)
Fixed some bugs with error_reporter_tree, and with error_callback in gtkbrowser.py
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)CONSOLE_DEBUG("ERROR(S) FOUND IN TREECURRENT %p",TREECURRENT);
223 return res;
224 }else{
225 CONSOLE_DEBUG("NO TREE FOUND");
226 return 0;
227 }
228 }
229
230 static int error_reporter_tree_write(error_reporter_tree_t *t){
231 int res = 0;
232 static int writecount = 0;
233
234 if(++writecount > 30){
235 CONSOLE_DEBUG("TOO MUCH WRITING");
236 return 0;
237 }
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 , const 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 /**
334 This function performs caching of the error text if the flag is set
335 */
336 int
337 fprintf_error_reporter(FILE *file, const char *fmt, ...){
338 va_list args;
339 char *msg;
340 int len;
341 int res;
342
343 /* fprintf(stderr,"ENTERED FPRINTF_ERROR_REPORTER\n"); */
344
345 va_start(args,fmt);
346 if(file==stderr){
347 if(g_error_reporter_cache.iscaching){
348 msg = g_error_reporter_cache.msg;
349 len = strlen(msg);
350 res = vsnprintf(msg+len,ERROR_REPORTER_MAX_MSG-len,fmt,args);
351 if(len+res+1>=ERROR_REPORTER_MAX_MSG){
352 snprintf(msg+ERROR_REPORTER_MAX_MSG-16,15,"... (truncated)");
353 ASC_FPRINTF(stderr,"TRUNCATED MESSAGE, FULL MESSAGE FOLLOWS:\n----------START----------\n");
354 ASC_VFPRINTF(stderr,fmt,args);
355 ASC_FPRINTF(stderr,"\n-----------END----------\n");
356 }
357 }else{
358 /* Not caching: output all in one go as a ASC_PROG_NOTE */
359 res = va_error_reporter(ASC_PROG_NOTE,NULL,0,NULL,fmt,args);
360 }
361 }else{
362 res = ASC_VFPRINTF(file,fmt,args);
363 }
364
365 va_end(args);
366
367 return res;
368 }
369
370 int
371 fputc_error_reporter(int c, FILE *file){
372 if(file!=stderr){
373 return ASC_FPUTC(c,file);
374 }else if(fprintf_error_reporter(file,"%c",c) == 1){
375 return c;
376 }else{
377 return EOF;
378 }
379 }
380
381 int
382 fflush_error_reporter(FILE *file){
383 if(file!=stderr){
384 return ASC_FFLUSH(file);
385 }else{
386 return error_reporter_end_flush();
387 }
388 }
389
390 /*----------------------------
391 CACHING of multiple-FPRINTF error messages
392 */
393
394 int
395 error_reporter_start(const error_severity_t sev, const char *filename, const int line, const char *func){
396
397 if(g_error_reporter_cache.iscaching){
398 error_reporter_end_flush();
399 }
400 g_error_reporter_cache.iscaching = 1;
401 *(g_error_reporter_cache.msg) = '\0';
402 g_error_reporter_cache.sev = sev;
403 g_error_reporter_cache.filename = filename;
404 g_error_reporter_cache.line = line;
405 g_error_reporter_cache.func = func;
406
407 return 1;
408 }
409
410 int
411 error_reporter_end_flush(){
412
413 error_reporter(
414 g_error_reporter_cache.sev
415 ,g_error_reporter_cache.filename
416 ,g_error_reporter_cache.line
417 ,g_error_reporter_cache.func
418 ,g_error_reporter_cache.msg
419 );
420 g_error_reporter_cache.iscaching = 0;
421
422 return 0; /* output must be compatible with fflush */
423 }
424
425 /*--------------------------
426 REPORT the error
427 */
428 int
429 error_reporter(
430 const error_severity_t sev
431 , const char *errfile
432 , const int errline
433 , const char *errfunc
434 , const char *fmt
435 , ...
436 ){
437 int res;
438 va_list args;
439
440 va_start(args,fmt);
441 res = va_error_reporter(sev,errfile,errline,errfunc,fmt,args);
442 va_end(args);
443
444 return res;
445 }
446
447 /*-------------------------
448 SET the callback function
449 */
450 void
451 error_reporter_set_callback(
452 const error_reporter_callback_t new_callback
453 ){
454 g_error_reporter_callback = new_callback;
455 }
456
457 /*-------------------------
458 OPTIONAL code for systems not supporting variadic macros.
459 You know, your system probably does support variadic macros, it's just
460 a question of checking what your particular syntax is...
461 */
462
463 #ifdef NO_VARIADIC_MACROS
464 /* Following are only required on compilers without variadic macros: */
465
466 int error_reporter_note_no_line(const char *fmt,...){
467 int res;
468 va_list args;
469
470 va_start(args,fmt);
471 res = va_error_reporter(ASC_PROG_NOTE,"unknown-file",0,NULL,fmt,args);
472 va_end(args);
473
474 return res;
475 }
476
477 /**
478 Error reporter 'here' function for compilers not supporting
479 variadic macros.
480 */
481 ASC_DLLSPEC(int) error_reporter_here(const error_severity_t sev, const char *fmt,...){
482 int res;
483 va_list args;
484
485 va_start(args,fmt);
486 res = va_error_reporter(sev,"unknown-file",0,NULL,fmt,args);
487 va_end(args);
488
489 return res;
490 }
491
492
493 /**
494 Error reporter 'no line' function for compilers not supporting
495 variadic macros.
496 */
497 int error_reporter_noline(const error_severity_t sev, const char *fmt,...){
498 int res;
499 va_list args;
500
501 va_start(args,fmt);
502 res = va_error_reporter(sev,NULL,0,NULL,fmt,args);
503 va_end(args);
504
505 return res;
506 }
507
508 int console_debug(const char *fmt,...){
509 int res;
510 va_list args;
511
512 va_start(args,fmt);
513 res = Asc_VFPrintf(ASCERR,fmt,args);
514 va_end(args);
515
516 return res;
517 }
518
519 #endif /* NO_VARIADIC_MACROS */

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