1 /*
2  * error.cpp
3  * by pts@fazekas.hu at Fri Mar  1 11:46:27 CET 2002
4  * added policies at Sat Sep  7 18:28:30 CEST 2002
5  */
6 
7 #ifdef __GNUC__
8 #ifndef __clang__
9 #pragma implementation
10 #endif
11 #endif
12 
13 #include "error.hpp"
14 #include "gensio.hpp"
15 #include <stdio.h>
16 #include <stdlib.h> /* exit() */
17 #include <string.h> /* strlen() */
18 #if _MSC_VER > 1000
19 #  include "windows.h" /* ExitThread() */
20 #endif
21 
22 char const* Error::argv0=(char const*)NULLP;
23 char const* Error::long_argv0=(char const*)NULLP;
24 char const* Error::banner0=(char const*)NULLP;
25 char const* Error::tmpargv0=(char const*)"pRg_tMp";
26 
27 static Filter::NullE devNull;
28 Files::FILEW serr_default(stderr);
29 GenBuffer::Writable * Error::serr = &serr_default;
30 static Error::Policy defaultPolicy={
31   (SimBuffer::B*)NULLP, /* record */
32   (Error::level_t)-9999, /* topSecret */
33   (Error::level_t)-9999, /* topRecorded */
34   (Error::level_t)0, /* killer (level>=0) */
35   (Error::level_t)-99, /* printed */
36   (Error::level_t)-199, /* recorded */
37   Error::serr, /* err */
38   (Error::Policy*)NULLP, /* prev */
39   (Error::Policy*)NULLP, /* next */
40   (Error::level_t)-9999, /* curlev */
41 };
42 Error::Policy *Error::policy_top=&defaultPolicy, *Error::policy_bottom=&defaultPolicy;
43 
level2str(level_t level)44 char const*Error::level2str(level_t level) {
45   return level==ASSERT ? "failed_assertion" : /* Imp: make assert() produce this */
46          level==FATAL ? "Fatal Error" :
47          level==ERROR_CONT ? "Error" :
48          level==EERROR ? "Error" :
49          level==WARNING_DEFER ? "Warning" :
50          level==WARNING ? "Warning" :
51          level==NOTICE ? "Notice" :
52          level==NOTICE_DEFER ? "Notice" :
53          level==INFO ? "Info" :
54          level==DEBUG ? "DEBUG" :
55          "??level" ;
56 }
57 
sev(level_t level)58 GenBuffer::Writable& Error::sev(level_t level) {
59   /* So they are trying to make an error? Let's see whether they can. */
60   GenBuffer::Writable *err=policy_top->err;
61   // printf("curlev=%d\n", policy_top->curlev);
62   assert(policy_top->curlev==-9999 && "nested error/ unfinished prev err");
63   policy_top->curlev=level;
64   /* printf("level=%d\n", level); */
65   if (level>=policy_top->printed) { /* printed or killer */
66     #if 0 /* Disables printing of "using template: " */
67       /* vvv Delay printing this message after all recorded messages */
68       if (policy_top->record!=NULLP) err=policy_top->record;
69     #endif
70   } else if (level>=policy_top->recorded) { /* recorded */
71     if (NULLP==(err=policy_top->record)) err=policy_top->record=new SimBuffer::B();
72     if (level>policy_top->topRecorded) policy_top->topRecorded=level;
73   } else { /* secret */
74     if (level>policy_top->topSecret) policy_top->topSecret=level;
75     return devNull;
76   }
77   return *err << (argv0==(char const*)NULLP?"??argv0":argv0) << ": " << level2str(level) << ": ";
78   /* Processing will continue soon by GenBuffer::Writable& operator <<(GenBuffer::Writable& gb,Error*) */
79 }
80 
operator <<(GenBuffer::Writable & err,Error *)81 GenBuffer::Writable& operator <<(GenBuffer::Writable& err,Error*) {
82   err << '\n';
83   Error::level_t level=Error::policy_top->curlev;
84   if (level>=Error::policy_top->killer) { /* killer */
85     /* Also print recorded messages throughout the the policy stack */
86     Error::Policy *p=Error::policy_bottom;
87     while (p!=NULLP) {
88       if (NULLP!=p->record) Error::policy_top->err->vi_write(p->record->begin_(), p->record->getLength());
89       p=p->next;
90     }
91     // if (level>=Error::policy_top->killer)
92     Error::cexit(level);
93   }
94   /* Note that the order of error messages might be scrambled, i.e `printed'
95    * is printed before `recorded'.
96    */
97   Error::policy_top->curlev=(Error::level_t)-9999; /* pedantic but useless because of nesting */
98   return err;
99 }
100 
pushPolicy(level_t killer_,level_t printed_,level_t recorded_,GenBuffer::Writable * err)101 void Error::pushPolicy(level_t killer_, level_t printed_, level_t recorded_, GenBuffer::Writable *err) {
102   Policy *p=new Policy();
103   p->record=(SimBuffer::B*)NULLP;
104   p->topSecret=p->topRecorded=(Error::level_t)-9999;
105   p->killer=killer_;
106   p->printed=printed_;
107   p->recorded=recorded_;
108   p->err=(err==NULLP) ? policy_top->err : err;
109   p->prev=policy_top;
110   p->next=(Policy*)NULLP;
111   policy_top=p->prev->next=p;
112   p->curlev=(Error::level_t)-9999; /* pedantic but useless because of nesting */
113 }
114 
getRecorded()115 SimBuffer::B *Error::getRecorded() {
116   SimBuffer::B *ret=policy_top->record;
117   policy_top->record=(SimBuffer::B*)NULLP;
118   return ret;
119 }
120 
setTopPrinted(level_t printed_)121 void Error::setTopPrinted(level_t printed_) {
122   policy_top->printed=printed_;
123 }
124 
getTopPrinted()125 Error::level_t Error::getTopPrinted() { return policy_top->printed; }
126 
popPolicy()127 void Error::popPolicy() {
128   if (policy_top==policy_bottom) {
129     Error::sev(Error::ASSERT) << "popPolicy: underflow" << (Error*)0;
130   } else {
131     if (NULLP!=policy_top->record) {
132       (*Error::policy_top->err) << "-- recorded messages:\n";
133       Error::policy_top->err->vi_write(policy_top->record->begin_(), policy_top->record->getLength());
134       delete policy_top->record;
135     }
136     policy_top=policy_top->prev;
137     delete policy_top->next;
138     policy_top->next=(Policy*)NULLP;
139   }
140 }
141 
142 /* --- */
143 
144 Error::Cleanup *Error::first_cleanup=(Error::Cleanup*)NULLP;
145 
runCleanups(int exitCode)146 int Error::runCleanups(int exitCode) {
147   /* Flush buffered messages and revert to the default policy so subsequent
148    * errors can be logged.
149    */
150   while (policy_top != policy_bottom)
151     popPolicy();
152 
153   Cleanup *next;
154   int exit2;
155   while (first_cleanup!=NULLP) {
156     // fprintf(stderr, "hand %p\n", first_cleanup);
157     if (exitCode<(exit2=first_cleanup->handler(first_cleanup))) exitCode=exit2;
158     next=first_cleanup->next;
159     /* Allocated from as an array of char (to make space for
160      * first_cleanup->getBuf()), but has no destructors.
161      */
162     delete [] (char*)first_cleanup;
163     first_cleanup=next;
164   }
165   return exitCode;
166 }
167 
cexit(int exitCode)168 void Error::cexit(int exitCode) {
169   #if _MSC_VER > 1000
170     ExitThread(exitCode);
171   #else
172     exit(exitCode); /* <stdlib.h> */
173   #endif
174 }
175 
newCleanup(Error::Cleanup::handler_t handler,void * data,slen_t bufSize)176 Error::Cleanup* Error::newCleanup(Error::Cleanup::handler_t handler, void *data, slen_t bufSize) {
177   param_assert(handler!=0);
178   // slen_t num_packets=(bufSize+sizeof(Cleanup)-1)/sizeof(Cleanup);
179   Cleanup *new_=(Cleanup*)new char[bufSize+sizeof(Cleanup)]; /* new Cleanup[1+num_packets]; */
180   /* ^^^ should be a new Cleanup + new char[bufSize]; now we can avoid alignment
181    *     problems
182    */
183   new_->handler=handler;
184   new_->bufSize=bufSize;
185   new_->data=data;
186   new_->next=first_cleanup;
187   first_cleanup=new_;
188   return new_;
189 }
190 
newCleanup(Error::Cleanup::handler_t handler,void * data,char const * bufCstr)191 Error::Cleanup* Error::newCleanup(Error::Cleanup::handler_t handler, void *data, char const*bufCstr) {
192   const slen_t bufSize=strlen(bufCstr)+1;
193   Cleanup *new_=newCleanup(handler, data, bufSize);
194   memcpy(new_->getBuf(), bufCstr, bufSize);
195   return new_;
196 }
197 
198 /* __END__ */
199