File: logexc.h

package info (click to toggle)
lammps 0~20181211.gitad1b1897d%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 318,860 kB
  • sloc: cpp: 729,569; python: 40,508; xml: 14,919; fortran: 12,142; ansic: 7,454; sh: 5,565; perl: 4,105; f90: 2,700; makefile: 2,117; objc: 238; lisp: 163; tcl: 61; csh: 16; awk: 14
file content (316 lines) | stat: -rw-r--r-- 10,195 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# ifndef LOGEXC_H
# define LOGEXC_H

#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <stdexcept>
#include <string>

#if !defined(_WIN32) || defined(__MINGW32__)
# include <typeinfo>
#endif


/// this specifies whether to put file/line info in error messages
# ifndef LINFO
# define LINFO 1
# endif

using namespace std;

/// verbosity levels
enum vbLEVELS{
  vblNONE   = 0,  ///< completely silent
  vblFATAL  = 0x1,  ///< report fatal errors
  vblOERR   = 0x2, ///< report other errors
  vblERR    = vblFATAL|vblOERR, ///< report all errors
  vblWARN   = 0x4, ///< report warnings
  vblALLBAD = vblWARN|vblERR, ///< report all errors and warnings
  vblMESS1  = 0x8, ///< report messages of level 1 (important)
  vblMESS2  = 0x10, ///< report messages of level 2 (less important)
  vblMESS3  = 0x20, ///< report messages of level 3 (not important)
  vblMESS4  = 0x40, ///< report messages of level 4 (anything possible)
  vblALLMESS = vblMESS1|vblMESS2|vblMESS3|vblMESS4, ///< report all messages
  vblPROGR  = 0x80,           ///< report progress 
  vblALL    = 0xffff
};



/// traits structure to deduce exception level and name from exception class
/// by default all exceptions have vblFATAL level
template<class exc_t>
struct log_exception_traits{
  /// exeption level according to the vbLEVELS
  static int level(const exc_t &signal){ return vblFATAL; } 
  /// the string name of exception category
  static string name(const exc_t &signal){ return typeid(exc_t).name();}
  /// adds some more explanations to the description
  /// default behaviour: nothing done
  static exc_t add_words(const exc_t &orig, const char *words){
    return orig;
  }
};




/// integer exceptions have the level equal to their value
template<>
struct log_exception_traits<int>{
  /// exeption level according to the vbLEVELS
  static int level(const int &signal){ return signal; } 
  /// the string name of exception category
  static string name(const int &signal){ 
    if(signal&vblFATAL)
      return "fatal error";
    else if(signal&vblOERR)
      return "error";
    else if(signal&vblWARN)
      return "warning";
    else
      return "";
    /*
    else if(signal&vblALLMESS)
      return "message";
    else if(signal&vblPROGR)
      return "progress report";
    else
      return "integer exception";*/
  }
  /// default behaviour: nothing done
  static int add_words(const int &orig, const char *words){
    return orig;
  }
};

/// vbLEVELS exceptions act as integers
template<>
struct log_exception_traits<enum vbLEVELS>{
  static int level(const enum vbLEVELS &signal){ return log_exception_traits<int>::level(signal); } 
  static string name(const enum vbLEVELS &signal){ return log_exception_traits<int>::name(signal); } 
  static enum vbLEVELS add_words(const enum vbLEVELS &orig, const char *words){
    return orig;
  }
};




/// Logger class to control (computational) function behaviour when something requiring user attention has happened.
/// message(signal,errcode, text) is used to either throw an exception or return errorcode
/// At first, the the level of error is determined via log_exception_traits<>::level(signal)
/// For integer (enum) signals the level is the signal itself.
/// Then text is printed, if signal level is listed in output levels or (or in extra outlevels, if they are set) 
/// via log_text() function.
/// If level has vblERR bit, the behaviour is controlled by the flag specified in set_throw(flag):
/// flag=0:   nothing done;
/// flag=1:   calls add_words() for signal and throws signal;
/// flag=2:   throws pair<>(errcode, text);
/// flag=3:   throws errcode.
/// Then, if the level is listed in stop_levels (or in extra stop levels, if they are set), the program is aborted,
/// otherwise errcode is returned;
/// The function set_levels(out_levels,stop_levels) is used to specify bitflags for the levels which
/// require message output or/and program termination. Stop level has effect only when exceptions are not thrown.
/// The function extra_levels(eout_levels,estop_levels) is used to temporarily set the corresponding levels,
/// they are unset (the original levels are restored) by calling extra_levels(0,0).
class message_logger {
  // global message is a friend
  template<class exc_t>
  friend int message(const exc_t &signal, int errcode, const char *what, ...);
protected:
  string descriptor;
  int throw_ex;
  int outlevel, eoutlevel;
  int stoplevel, estoplevel;
  
  static message_logger *glogp;
  /// used to restore the previous global logger
  message_logger *prev, *next;
public:
  
  message_logger(const string &descriptor_="", int out_level=vblALLBAD|vblMESS1, 
                 int stop_level=vblFATAL, int throw_exceptions=0, int use_globally=0)
    :descriptor(descriptor_),prev(NULL),next(NULL){
    set_throw(throw_exceptions);
    set_levels(out_level,stop_level);
    extra_levels(0,0);
    if(use_globally){
      set_global(true);
    }
  }
  
  /// returns a reference to global logger
  /// if not set, links with default message_logger
  static message_logger &global();
  
  /// sets/unsets this logger as the global logger
  int set_global(bool set){
    if(set){
      if(prev) // already set
        return -1;
      if(glogp)
        glogp->next=this;
      prev=glogp;
      glogp=this;
    }
    else{
      if(glogp!=this) // was not set as the global
        return -1; 
      glogp=prev;
      if(glogp)
        glogp->next=NULL;
      prev=NULL;
    }
    return 1;
  }
  
  virtual void set_throw(int throw_exceptions){
    throw_ex=throw_exceptions;
  }

  virtual void set_levels(int out_level=vblALLBAD|vblMESS1, int stop_level=vblFATAL){
    outlevel=out_level;
    stoplevel=stop_level;
  }

  /// nonzero extra levels are applied instead of set ones
  virtual void extra_levels(int out_level=vblALLBAD|vblMESS1, int stop_level=vblFATAL){
    eoutlevel=out_level;
    estoplevel=stop_level;
  }
  
  template<class exc_t>
  int message(const exc_t &signal, int errcode, const char *what, ...){
    int level=log_exception_traits<exc_t>::level(signal);
    char buff[1024];
    if(level&(eoutlevel ? eoutlevel : outlevel)){ //needs to print a message
      va_list args;
      va_start(args,what);
      vsnprintf(buff,1024,what,args);
      log_text(level,log_exception_traits<exc_t>::name(signal).c_str(),buff);
    }
    if(level&vblERR){
      if(throw_ex==1) // throws exc_t exception 
        throw log_exception_traits<exc_t>::add_words(signal,buff);
      else if(throw_ex==2) // throws pair<>(int,const char*) exception 
        throw make_pair(errcode,what);
      else if(throw_ex==3) // throws int exception 
        throw errcode;
    } 
    if(level&(estoplevel ? estoplevel: stoplevel) ){ // needs to stop
      exit(errcode); 
    }
    return errcode;
  }

  virtual void log_text(int level, const char *messtype, const char *messtext){
    if(descriptor!="") // descriptor is used as header
      printf("%s:\n",descriptor.c_str());
    if(string(messtype)!=string(""))
      printf("%s: ",messtype);
    printf("%s\n",messtext);
  }

  /// checks that the deleted one is not in global logger chain 
  ~message_logger(){
    if(prev){
      prev->next=next;
      if(next)
        next->prev=prev;
    }
    set_global(false);
  }
};

/// global message function
template<class exc_t>
int message(const exc_t &signal, int errcode, const char *what, ...){
  if(message_logger::glogp){
    va_list args;
    va_start(args,what);
    char buff[1024];
    vsnprintf(buff,1024,what,args);
    return message_logger::glogp->message(signal,errcode,buff);
  }
  else 
    return -1;
}

/// message logger for which std and error streams may be specified
class stdfile_logger: public message_logger {
protected:
  FILE *fout, *ferr;
public:
  stdfile_logger(const string &descriptor_="", int throw_exceptions=0, 
                  FILE *out=stdout, FILE *err=stderr, 
                  int out_level=vblALLBAD|vblMESS1,int stop_level=vblFATAL,
                  int use_globally=0)
                  : message_logger(descriptor_,out_level,stop_level,throw_exceptions,use_globally),fout(NULL), ferr(NULL){
    set_out(out);
    set_err(err);
  }
  virtual void set_out(FILE *out, int close_prev=0){
    if(close_prev && fout && fout!=stderr && fout !=stdout)
      fclose(fout);
    fout=out;
  }
  
  virtual void set_err(FILE *err, int close_prev=0){
    if(close_prev && ferr && ferr!=stderr && ferr !=stdout)
      fclose(ferr);
    ferr=err;
  }

  virtual void log_text(int level, const char *messtype, const char *messtext){
    FILE *f= (level&vblALLBAD ? ferr : fout);
    if(!f)
      return;
    if(descriptor!="") // descriptor is used as header
      fprintf(f,"%s:\n",descriptor.c_str());
    if(string(messtype)!="")
      fprintf(f,"%s: ",messtype);
    fprintf(f,"%s\n",messtext);
  }
};

/// format a string 
const char *fmt(const char *format,...);

/// macros with common usage
#define LOGFATAL(code,text,lineinfo) ((lineinfo) ? ::message(vblFATAL,(code)," %s at %s:%d",(text),__FILE__,__LINE__) : \
                                   (::message(vblFATAL,(code)," %s",(text))) )


#define LOGERR(code,text,lineinfo) ((lineinfo) ? ::message(vblOERR,(code)," %s at %s:%d",(text),__FILE__,__LINE__) : \
                                   (::message(vblOERR,(code)," %s",(text))) )


#define LOGMSG(cat,text,lineinfo) ((lineinfo) ? ::message((cat),0," %s at %s:%d",(text),__FILE__,__LINE__) : \
                                  (::message((cat),0," %s",(text))) )



# if 0 /// did not work

/// this may be used to inherit exceptions
/// where level and name are defined whithin a class
struct log_exception {
   /// exeption level according to the vbLEVELS
  static int level(const log_exception &signal){ return vblFATAL; } 
  /// the string name of exception category
  static string name(const log_exception &signal){ return "undefined exception";}
};

/// log_exceptions act as themselves
template<>
struct log_exception_traits<log_exception>{
  static int level(const log_exception &signal){ return log_exception::level(signal); } 
  static string name(const log_exception &signal){ return log_exception::name(signal); } 
};

# endif


# endif