/[ascend]/branches/relerrorlist/ascend/utilities/error.c
ViewVC logotype

Diff of /branches/relerrorlist/ascend/utilities/error.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3195 by jpye, Sun Apr 2 13:41:44 2017 UTC revision 3196 by jpye, Sat Apr 22 13:10:46 2017 UTC
# Line 16  Line 16 
16  static error_reporter_callback_t g_error_reporter_callback;  static error_reporter_callback_t g_error_reporter_callback;
17    
18  /**  /**
19      Global variable which holds cached error info for      Global variable which enables caching of *individual* error messages,
20      later output      as used with error_reporter_start() and error_reporter_end_flush().
21        This is not the same as the caching performed by error_reporter_tree_start()
22        which holds/records multiple error messages depending on the iscaching
23        setting.
24  */  */
25  static error_reporter_meta_t g_error_reporter_cache;  static error_reporter_meta_t g_error_reporter_cache;
26    
 #ifdef ERROR_REPORTER_TREE_ACTIVE  
 static error_reporter_meta_t *error_reporter_meta_new(){  
     error_reporter_meta_t *e;  
     e = ASC_NEW(error_reporter_meta_t);  
     e->sev = ASC_USER_SUCCESS;  
     e->iscaching = 0;  
     e->filename = NULL;  
     e->func = NULL;  
     e->line = 0;  
     e->msg[0] = '\0';  
     return e;  
 }  
 #endif /* ERROR_REPORTER_TREE_ACTIVE */  
   
27  /**  /**
28      Default error reporter. To use this error reporter, set      Default error reporter. This error reporter is used whenever the callback
29      the callback pointer to NULL.      pointer is NULL, but can be replaced with another callback (eg for GUI
30        reporting) using error_reporter_set_callback()
31  */  */
32  int error_reporter_default_callback(ERROR_REPORTER_CALLBACK_ARGS){  int error_reporter_default_callback(ERROR_REPORTER_CALLBACK_ARGS){
33      char *sevmsg="";      char *sevmsg="";
# Line 46  int error_reporter_default_callback(ERRO Line 36  int error_reporter_default_callback(ERRO
36      int res=0;      int res=0;
37      switch(sev){      switch(sev){
38          case ASC_PROG_FATAL:    color=ASC_FG_BRIGHTRED; sevmsg = "PROGRAM FATAL ERROR: "; break;          case ASC_PROG_FATAL:    color=ASC_FG_BRIGHTRED; sevmsg = "PROGRAM FATAL ERROR: "; break;
39          case ASC_PROG_ERROR:          case ASC_PROG_ERROR:    color=ASC_FG_RED; sevmsg = "PROGRAM ERROR: "; break;
             color=ASC_FG_RED; sevmsg = "PROGRAM ERROR: ";  
             break;  
40          case ASC_PROG_WARNING:  color=ASC_FG_BROWN;sevmsg = "PROGRAM WARNING: "; break;          case ASC_PROG_WARNING:  color=ASC_FG_BROWN;sevmsg = "PROGRAM WARNING: "; break;
41          case ASC_PROG_NOTE:     color=ASC_FG_BRIGHTGREEN; endtxt=""; break; /* default, keep unembellished for now */          case ASC_PROG_NOTE:     color=ASC_FG_BRIGHTGREEN; endtxt=""; break; /* default, keep unembellished for now */
42          case ASC_USER_ERROR:    color=ASC_FG_BRIGHTRED; sevmsg = "ERROR: "; break;          case ASC_USER_ERROR:    color=ASC_FG_BRIGHTRED; sevmsg = "ERROR: "; break;
# Line 56  int error_reporter_default_callback(ERRO Line 44  int error_reporter_default_callback(ERRO
44          case ASC_USER_NOTE:     sevmsg = "NOTE: "; break;          case ASC_USER_NOTE:     sevmsg = "NOTE: "; break;
45          case ASC_USER_SUCCESS:  color=ASC_FG_BRIGHTGREEN; sevmsg = "SUCCESS: "; break;          case ASC_USER_SUCCESS:  color=ASC_FG_BRIGHTGREEN; sevmsg = "SUCCESS: "; break;
46      }      }
   
47      color_on(ASCERR,color);      color_on(ASCERR,color);
48      res = ASC_FPRINTF(ASCERR,"%s",sevmsg);      res = ASC_FPRINTF(ASCERR,"%s",sevmsg);
49      color_off(ASCERR);      color_off(ASCERR);
50        if(filename!=NULL)res += ASC_FPRINTF(ASCERR,"%s:",filename);
51      if(filename!=NULL){      if(line!=0)res += ASC_FPRINTF(ASCERR,"%d:",line);
52          res += ASC_FPRINTF(ASCERR,"%s:",filename);      if(funcname!=NULL)res += ASC_FPRINTF(ASCERR,"%s:",funcname);
53      }      if ((filename!=NULL) || (line!=0) || (funcname!=NULL))res += ASC_FPRINTF(ASCERR," ");
     if(line!=0){  
         res += ASC_FPRINTF(ASCERR,"%d:",line);  
     }  
     if(funcname!=NULL){  
         res += ASC_FPRINTF(ASCERR,"%s:",funcname);  
     }  
     if ((filename!=NULL) || (line!=0) || (funcname!=NULL)){  
         res += ASC_FPRINTF(ASCERR," ");  
     }  
   
54      res += ASC_VFPRINTF(ASCERR,fmt,args);      res += ASC_VFPRINTF(ASCERR,fmt,args);
55      res += ASC_FPRINTF(ASCERR,"%s",endtxt);      res += ASC_FPRINTF(ASCERR,"%s",endtxt);
   
56      return res;      return res;
57  }  }
58    
# Line 86  int error_reporter_default_callback(ERRO Line 62  int error_reporter_default_callback(ERRO
62    
63  #ifdef ERROR_REPORTER_TREE_ACTIVE  #ifdef ERROR_REPORTER_TREE_ACTIVE
64    
 static error_reporter_tree_t *g_error_reporter_tree = NULL;  
65  static error_reporter_tree_t *g_error_reporter_tree_current = NULL;  static error_reporter_tree_t *g_error_reporter_tree_current = NULL;
66    
67  # define TREECURRENT g_error_reporter_tree_current  static error_reporter_meta_t *error_reporter_meta_new(){
68  # define TREE g_error_reporter_tree      error_reporter_meta_t *e;
69        e = ASC_NEW(error_reporter_meta_t);
70        e->sev = ASC_USER_SUCCESS;
71        e->iscaching = 0;
72        e->filename = NULL;
73        e->func = NULL;
74        e->line = 0;
75        e->msg[0] = '\0';
76        return e;
77    }
78    
79    # define CURRENT g_error_reporter_tree_current
80    
81  static int error_reporter_tree_write(error_reporter_tree_t *t);  static int error_reporter_tree_write(error_reporter_tree_t *t);
82  static void error_reporter_tree_free(error_reporter_tree_t *t);  static void error_reporter_tree_free(error_reporter_tree_t *t);
83    
84  static error_reporter_tree_t *error_reporter_tree_new(){  /// deprecated function for testing purpose only
85    error_reporter_tree_t *error_reporter_get_tree_current(){
86        return CURRENT;
87    }
88    
89    static error_reporter_tree_t *error_reporter_tree_new(int iscaching){
90      error_reporter_tree_t *tnew = ASC_NEW(error_reporter_tree_t);      error_reporter_tree_t *tnew = ASC_NEW(error_reporter_tree_t);
91        tnew->iscaching = iscaching;
92      tnew->next = NULL;      tnew->next = NULL;
93      tnew->head = NULL;      tnew->head = NULL;
94      tnew->tail = NULL;      tnew->tail = NULL;
95      tnew->err = NULL;      tnew->err = NULL;
96        tnew->parent = NULL;
97      return tnew;      return tnew;
98  }  }
99    
100  int error_reporter_tree_start(){  static int error_reporter_tree_has_caching_parent(error_reporter_tree_t *t){
101      error_reporter_tree_t *tnew;      assert(t);
102      tnew = error_reporter_tree_new();      if(NULL == t->parent)return 0;
103        error_reporter_tree_t *t1 = t->parent;
104  #if 0      int iscaching = 0;
105      fprintf(stderr,"TREE = %p",TREE);      while(t1){
106      fprintf(stderr,"TREECURRENT = %p",TREECURRENT);          iscaching = iscaching || t1->iscaching;
107            assert(t1->parent != t1);
108      if(TREE != NULL && TREECURRENT == NULL){          t1 = t1->parent;
109          CONSOLE_DEBUG("CALLED WITH NULL TREECURRENT BUT NON-NULL TREE");      }
110          error_reporter_tree_write(TREE);      return iscaching;
111          error_reporter_tree_free(TREE);  }
112          TREE = NULL;  
113      }  int error_reporter_tree_start(int iscaching){
114  #endif      error_reporter_tree_t *tnew = error_reporter_tree_new(iscaching);
115        if(CURRENT == NULL){
116      if(TREE == NULL){          CONSOLE_DEBUG("creating tree (caching=%d)",iscaching);
117          //CONSOLE_DEBUG("CREATING ROOT");          CURRENT = tnew;
         /* we're creating the root */  
         tnew->parent = NULL;  
         TREE = tnew;  
         TREECURRENT = tnew;  
         /* CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */  
118      }else{      }else{
119          asc_assert(TREECURRENT != NULL);          CONSOLE_DEBUG("creating sub-tree (caching=%d)",iscaching);
120          //CONSOLE_DEBUG("CREATING SUBTREE");          if(CURRENT->head == NULL){
         if(TREECURRENT->head == NULL){  
121              /* if the current tree has no elements, add it as the head */              /* if the current tree has no elements, add it as the head */
122              TREECURRENT->head = tnew;              CURRENT->head = tnew;
123          }else{          }else{
124              /* link the new tree to the last in the child list */              /* link the new tree to the last in the child list */
125              TREECURRENT->tail->next = tnew;              CURRENT->tail->next = tnew;
126          }          }
127          /* update the tail of the list */          /* update the tail of the list */
128          TREECURRENT->tail = tnew;          CURRENT->tail = tnew;
   
129          /* now switch the context to the sub-tree */          /* now switch the context to the sub-tree */
130          tnew->parent = TREECURRENT;          tnew->parent = CURRENT;
131          /* CONSOLE_DEBUG("SET TREECURRENT TO %p",TREECURRENT); */          CURRENT = tnew;
         TREECURRENT = tnew;  
132      }      }
133      return 0;      return 0;
134  }  }
135    
136  int error_reporter_tree_end(){  int error_reporter_tree_end(){
137      //CONSOLE_DEBUG("TREE END");      assert(CURRENT);
138      if(!TREECURRENT){      if(CURRENT->iscaching){
139          ERROR_REPORTER_HERE(ASC_PROG_ERR,"'end' without TREECURRENT set");          if(error_reporter_tree_has_caching_parent(CURRENT)){
140          return 1;              CONSOLE_DEBUG("no output; caching parent");
141            }else{
142                CONSOLE_DEBUG("outputting now, no caching parent");
143                error_reporter_tree_write(CURRENT);
144            }
145        }
146        if(CURRENT->parent){
147            CONSOLE_DEBUG("ending sub-tree");
148            CURRENT = CURRENT->parent;
149        }else{
150            CONSOLE_DEBUG("ending top tree");
151            CURRENT = NULL;
152      }      }
     TREECURRENT = TREECURRENT->parent;  
     //CONSOLE_DEBUG("SET TREECURRENT TO %p",TREECURRENT);  
153      return 0;      return 0;
154  }  }
155    
# Line 171  static void error_reporter_tree_free(err Line 165  static void error_reporter_tree_free(err
165  }  }
166    
167  void error_reporter_tree_clear(){  void error_reporter_tree_clear(){
168      /* recursively free anything beneath the TREECURRENT node, return to the parent context */      /* recursively free anything beneath the CURRENT node, return to the parent context */
169      error_reporter_tree_t *t;      error_reporter_tree_t *t1;
170      if(!TREECURRENT){      if(!CURRENT){
171          /* CONSOLE_DEBUG("NOTHING TO CLEAR!"); */          /* CONSOLE_DEBUG("NOTHING TO CLEAR!"); */
172          return;          return;
173      }      }
174      if(TREECURRENT->parent){      if(CURRENT->parent){
175          t = TREECURRENT->parent;          t1 = CURRENT->parent;
176      }else{      }else{
177          TREE = NULL;          t1 = NULL;
         t = NULL;  
178      }      }
179      error_reporter_tree_free(TREECURRENT);      error_reporter_tree_free(CURRENT);
180      TREECURRENT = t;      CURRENT = t1;
181  }  }
182    
183  static int error_reporter_tree_match_sev(error_reporter_tree_t *t, unsigned match){  static int error_reporter_tree_match_sev(error_reporter_tree_t *t, unsigned match){
# Line 210  static int error_reporter_tree_match_sev Line 203  static int error_reporter_tree_match_sev
203  */  */
204  int error_reporter_tree_has_error(){  int error_reporter_tree_has_error(){
205      int res;      int res;
206      if(TREECURRENT){      if(CURRENT){
207          res = error_reporter_tree_match_sev(TREECURRENT,ASC_ERR_ERR);          res = error_reporter_tree_match_sev(CURRENT,ASC_ERR_ERR);
208          if(res){          if(res){
209              /* CONSOLE_DEBUG("ERROR(S) FOUND IN TREECURRENT %p",TREECURRENT); */              /* CONSOLE_DEBUG("ERROR(S) FOUND IN CURRENT %p",CURRENT); */
210          }          }
211          return res;          return res;
212      }else{      }else{
# Line 224  int error_reporter_tree_has_error(){ Line 217  int error_reporter_tree_has_error(){
217    
218  static int error_reporter_tree_write(error_reporter_tree_t *t){  static int error_reporter_tree_write(error_reporter_tree_t *t){
219      int res = 0;      int res = 0;
220        assert(t != NULL);
     asc_assert(TREE==NULL); /* else recursive calls will occur */  
   
221      if(t->err){      if(t->err){
222          res += error_reporter(t->err->sev, t->err->filename, t->err->line, t->err->func, t->err->msg);          // an a simple node -- just an error
223            assert(t->head == NULL);
224            assert(t->tail == NULL);
225            error_reporter_callback_t cb = g_error_reporter_callback ?
226                g_error_reporter_callback : error_reporter_default_callback;
227            res += (*cb)(t->err->sev,t->err->filename,t->err->line,t->err->func,t->err->msg,NULL);
228      }else{      }else{
229          /* CONSOLE_DEBUG("TREE HAS NO TOP-LEVEL ERROR"); */          // a parent node -- traverse the sub-nodes
230      }          assert(t->head);
231            assert(t->tail);
232      if(t->head){          error_reporter_tree_t *t1 = t->head;
233          res += error_reporter_tree_write(t->head);          while(t1){
234      }              res += error_reporter_tree_write(t1);
235      if(t->next){              t1 = t1->next;
236          res += error_reporter_tree_write(t->next);          }
237      }      }
238      return res;      return res;
239  }  }
# Line 250  int error_reporter_tree_start(){ Line 246  int error_reporter_tree_start(){
246  int error_reporter_tree_end(){return 0;}  int error_reporter_tree_end(){return 0;}
247  void error_reporter_tree_clear(){}  void error_reporter_tree_clear(){}
248  int error_reporter_tree_has_error(){  int error_reporter_tree_has_error(){
249      ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Attempt to check 'tree_has_error' when 'tree' turned off at compile time");      ERROR_REPORTER_HERE(ASC_PROG_FATAL,"Attempt to check 'tree_has_error' when 'tree' turned off at compile time");
250      return 0;      return 0;
251  }  }
252  #endif /* ERROR_REPORTER_TREE_ACTIVE */  #endif /* ERROR_REPORTER_TREE_ACTIVE */
# Line 268  va_error_reporter( Line 264  va_error_reporter(
264      , const char *fmt      , const char *fmt
265      , va_list args      , va_list args
266  ){  ){
267      int res;      int res = 0;
268    
269  #ifdef ERROR_REPORTER_TREE_ACTIVE  #ifdef ERROR_REPORTER_TREE_ACTIVE
270      error_reporter_tree_t *t;      error_reporter_tree_t *t;
271      if(sev != ASC_PROG_FATAL){      if(sev != ASC_PROG_FATAL){
272          if(TREECURRENT){          if(CURRENT){
273              /* add the error to the tree, don't output anything now */              /* add the error to the tree, don't output anything now */
274              t = error_reporter_tree_new();              t = error_reporter_tree_new(0);
275              t->err = error_reporter_meta_new();              t->err = error_reporter_meta_new();
276              res = vsnprintf(t->err->msg,ERROR_REPORTER_MAX_MSG,fmt,args);              res = vsnprintf(t->err->msg,ERROR_REPORTER_MAX_MSG,fmt,args);
277              t->err->filename = errfile;              t->err->filename = errfile;
278              t->err->func = errfunc;              t->err->func = errfunc;
279              t->err->line = errline;              t->err->line = errline;
280              t->err->sev = sev;              t->err->sev = sev;
281              if(!TREECURRENT->head){              if(!CURRENT->head){
282                  TREECURRENT->head = TREECURRENT->tail = t;                  CURRENT->head = CURRENT->tail = t;
283              }else{              }else{
284                  TREECURRENT->tail->next = t;                  CURRENT->tail->next = t;
285                  TREECURRENT->tail = t;                  CURRENT->tail = t;
286                }
287                CONSOLE_DEBUG("message '%s' added to tree",t->err->msg);
288    
289                if(CURRENT->iscaching || error_reporter_tree_has_caching_parent(CURRENT)){
290                    CONSOLE_DEBUG("caching; no output");
291                    return res;
292              }              }
             /* CONSOLE_DEBUG("Message (%d chars) added to tree",res); */  
             return res;  
         }else if(TREE){  
             /* flush the tree before outputting current message */  
             /* CONSOLE_DEBUG("WRITING OUT TREE CONTENTS"); */  
             t = TREE;  
             TREE = NULL;  
             error_reporter_tree_write(t);  
             //CONSOLE_DEBUG("DONE WRITING TREE");  
             TREECURRENT = t;  
             error_reporter_tree_clear();  
             /* CONSOLE_DEBUG("DONE FREEING TREE");  
             CONSOLE_DEBUG("TREE = %p",TREE);  
             CONSOLE_DEBUG("TREECURRENT = %p",TREECURRENT); */  
293          }          }
294      }      }
295  #endif  #endif
296    
297      if(g_error_reporter_callback==NULL){      CONSOLE_DEBUG("outputting message (format) '%s'",fmt);
298          /* fprintf(stderr,"CALLING VFPRINTF\n"); */  
299          res = error_reporter_default_callback(sev,errfile,errline,errfunc,fmt,args);      error_reporter_callback_t cb = g_error_reporter_callback;
300      }else{      if(cb == NULL)cb = error_reporter_default_callback;
301          /* fprintf(stderr,"CALLING G_ERROR_REPORTER_CALLBACK\n"); */  
302          res = g_error_reporter_callback(sev,errfile,errline,errfunc,fmt,args);      res += (*cb)(sev,errfile,errline,errfunc,fmt,args);
     }  
303    
304      return res;      return res;
305  }  }
# Line 385  fflush_error_reporter(FILE *file){ Line 372  fflush_error_reporter(FILE *file){
372    CACHING of multiple-FPRINTF error messages    CACHING of multiple-FPRINTF error messages
373  */  */
374    
375  int  int error_reporter_start(const error_severity_t sev, const char *filename
376  error_reporter_start(const error_severity_t sev, const char *filename, const int line, const char *func){      , const int line, const char *func
377    ){
378      if(g_error_reporter_cache.iscaching){      if(g_error_reporter_cache.iscaching){
379          error_reporter_end_flush();          error_reporter_end_flush();
380      }      }
# Line 401  error_reporter_start(const error_severit Line 388  error_reporter_start(const error_severit
388      return 1;      return 1;
389  }  }
390    
391  int  /**
392  error_reporter_end_flush(){      This function will flush the output of a multi-line error message
393        (as written with multiple calls to FPRINTF(stderr,...))
394    */
395    int error_reporter_end_flush(){
396      if(g_error_reporter_cache.iscaching){      if(g_error_reporter_cache.iscaching){
397          error_reporter(          error_reporter(
398              g_error_reporter_cache.sev              g_error_reporter_cache.sev
# Line 444  error_reporter( Line 434  error_reporter(
434  /*-------------------------  /*-------------------------
435    SET the callback function    SET the callback function
436  */  */
437  void  void error_reporter_set_callback(
 error_reporter_set_callback(  
438          const error_reporter_callback_t new_callback          const error_reporter_callback_t new_callback
439  ){  ){
440      g_error_reporter_callback = new_callback;      g_error_reporter_callback = new_callback;
# Line 453  error_reporter_set_callback( Line 442  error_reporter_set_callback(
442    
443  /*-------------------------  /*-------------------------
444    OPTIONAL code for systems not supporting variadic macros.    OPTIONAL code for systems not supporting variadic macros.
445    You know, your system probably does support variadic macros, it's just    Your system probably does support variadic macros, it's just
446    a question of checking what your particular syntax is...    a question of checking what your particular syntax is, and possibly
447      adding some stuff in error.h.
448  */  */
449    
450  #ifdef NO_VARIADIC_MACROS  #ifdef NO_VARIADIC_MACROS
451  /* Following are only required on compilers without variadic macros: */  /** error reporter for compilers not supporting variadic macros */
   
452  int error_reporter_note_no_line(const char *fmt,...){  int error_reporter_note_no_line(const char *fmt,...){
453      int res;      int res;
454      va_list args;      va_list args;
# Line 471  int error_reporter_note_no_line(const ch Line 460  int error_reporter_note_no_line(const ch
460      return res;      return res;
461  }  }
462    
463  /**  /** error reporter 'here' for compilers not supporting variadic macros */
     Error reporter 'here' function for compilers not supporting  
     variadic macros.  
 */  
464  ASC_DLLSPEC int error_reporter_here(const error_severity_t sev, const char *fmt,...){  ASC_DLLSPEC int error_reporter_here(const error_severity_t sev, const char *fmt,...){
465      int res;      int res;
466      va_list args;      va_list args;
# Line 486  ASC_DLLSPEC int error_reporter_here(cons Line 472  ASC_DLLSPEC int error_reporter_here(cons
472      return res;      return res;
473  }  }
474    
475    /** error reporter for compilers not supporting variadic macros */
 /**  
     Error reporter 'no line' function for compilers not supporting  
     variadic macros.  
 */  
476  int error_reporter_noline(const error_severity_t sev, const char *fmt,...){  int error_reporter_noline(const error_severity_t sev, const char *fmt,...){
477      int res;      int res;
478      va_list args;      va_list args;
# Line 502  int error_reporter_noline(const error_se Line 484  int error_reporter_noline(const error_se
484      return res;      return res;
485  }  }
486    
487    /** console debugging for compilers not supporting variadic macros */
488  int console_debug(const char *fmt,...){  int console_debug(const char *fmt,...){
489      int res;      int res;
490      va_list args;      va_list args;
# Line 512  int console_debug(const char *fmt,...){ Line 495  int console_debug(const char *fmt,...){
495    
496      return res;      return res;
497  }  }
   
498  #endif /* NO_VARIADIC_MACROS */  #endif /* NO_VARIADIC_MACROS */

Legend:
Removed from v.3195  
changed lines
  Added in v.3196

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