00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 #include "w_defines.h"
00054 
00055 
00056 
00057 #ifdef __GNUC__
00058 #pragma implementation "w_error.h"
00059 #endif
00060 
00061 #include <cstring>
00062 
00063 #define W_SOURCE
00064 #include <w_base.h>
00065 const
00066 #include <fc_einfo_gen.h>
00067 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00068 #include "block_alloc.h"
00069 #endif
00070 
00071 
00072 
00073 
00074 const 
00075 w_error_t::info_t*        w_error_t::_range_start[w_error_t::max_range] = {
00076     w_error_t::error_info, 0 
00077 };
00078 w_base_t::uint4_t        w_error_t::_range_cnt[w_error_t::max_range] = {
00079     fcERRMAX - fcERRMIN + 1, 0
00080 };
00081 
00082 const char *w_error_t::_range_name[w_error_t::max_range]= { 
00083     "Foundation Classes",
00084     0
00085 };
00086 w_base_t::uint4_t        w_error_t::_nreg = 1;
00087 
00088 
00089 const w_error_t w_error_t::no_error_instance(__FILE__, __LINE__, 0, 0, 0);
00090 w_error_t* const w_error_t::no_error = const_cast<w_error_t *>(&no_error_instance);
00091 
00092 static void w_error_t_no_error_code()
00093 {
00094 }
00095 
00096 #if W_DEBUG_LEVEL > 3
00097 #define CHECKIT do {\
00098         w_error_t*    my = _next; \
00099         w_error_t*    p = my; \
00100         while(p) { \
00101         if (p == p->_next || my == p->_next) { \
00102             cerr << "Recursive error detected:" << endl << *this << endl;\
00103             W_FATAL(fcINTERNAL); \
00104         } \
00105         p = p->_next; \
00106         } \
00107   } while(0)
00108 
00109 #else
00110 #define CHECKIT
00111 #endif
00112 
00113 w_error_t&
00114 w_error_t::add_trace_info(
00115         const char* const    filename,
00116         uint4_t        line_num)
00117 {
00118     verify_owner();
00119     if (_trace_cnt < max_trace)  {
00120         _trace_file[_trace_cnt] = filename;
00121         _trace_line[_trace_cnt] = line_num;
00122         ++_trace_cnt;
00123     }
00124 
00125     return *this;
00126 }
00127 
00128 #if W_DEBUG_LEVEL > 1
00129 #define CHECK_STRING(x) if((x) != NULL) w_assert2(*(x) != 0)
00130 #else
00131 #define CHECK_STRING(x) 
00132 #endif
00133 
00134 w_error_t&
00135 w_error_t::clear_more_info_msg()
00136 {
00137     delete[] more_info_msg;
00138     more_info_msg = NULL;
00139     return *this;
00140 }
00141 
00142 w_error_t&
00143 w_error_t::append_more_info_msg(const char* more_info)
00144 {
00145     CHECK_STRING(more_info);
00146     verify_owner();
00147     if (more_info)  
00148     {
00149         int more_info_len = strlen(more_info);
00150         if(more_info_len > 0)
00151         {
00152             if(more_info[more_info_len-1] == '\n') more_info_len--;
00153 
00154             int more_info_msg_len = more_info_msg?strlen(more_info_msg):0;
00155             char* new_more_info_msg = new 
00156                 char[more_info_len + more_info_msg_len + 2];
00157             if(more_info_msg) { 
00158                 strcpy(new_more_info_msg, more_info_msg);
00159             }
00160             strcpy(new_more_info_msg + more_info_msg_len, more_info);
00161             new_more_info_msg[more_info_msg_len + more_info_len] = '\n';
00162             new_more_info_msg[more_info_msg_len + more_info_len + 1] = '\0';
00163 
00164             if(more_info_msg) delete[] more_info_msg;
00165             more_info_msg = new_more_info_msg;
00166 
00167             CHECK_STRING(more_info_msg);
00168         }
00169     }
00170 
00171     return *this;
00172 }
00173 
00174 const char*
00175 w_error_t::get_more_info_msg() const
00176 { 
00177     CHECK_STRING(more_info_msg);
00178     return more_info_msg;
00179 }
00180 
00181 
00182 inline w_base_t::uint4_t w_error_t::classify(int er)
00183 {
00184     uint4_t    sys = 0;
00185     switch (er) {
00186     case fcOS:
00187         sys = errno;
00188         break;
00189     }
00190     return sys;
00191 }
00192 
00193 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00194 DEFINE_TLS_SWATCHZ(block_alloc<w_error_t>, w_error_alloc);
00195 void w_error_t::operator delete(void* p) {
00196   block_alloc<w_error_t>::destroy_object((w_error_t*) p);
00197 }
00198 #endif
00199 
00200 
00201 inline
00202 w_error_t::w_error_t(const char* const        fi,
00203                  uint4_t        li,
00204                  err_num_t        er,
00205                  w_error_t*        list,
00206                  const char*    more_info)
00207 : err_num(er),
00208   file(fi),
00209   line(li), 
00210   sys_err_num(classify(er)),
00211   more_info_msg(more_info),
00212   _trace_cnt(0),
00213   _next(list)
00214 {
00215     CHECK_STRING(more_info_msg);
00216     claim();
00217     CHECKIT;
00218 }
00219 
00220 
00221 w_error_t*
00222 w_error_t::make(
00223         const char* const    filename,
00224         uint4_t              line_num,
00225         err_num_t            err_num,
00226         w_error_t*           list,
00227         const char*          more_info)
00228 {
00229 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00230     return new (*w_error_alloc) w_error_t(filename, line_num, err_num, list, more_info);
00231 #else
00232     return new  w_error_t(filename, line_num, err_num, list, more_info);
00233 #endif
00234 
00235 }
00236 
00237 inline NORET
00238 w_error_t::w_error_t(
00239         const char* const    fi,
00240         uint4_t        li,
00241         err_num_t      er,
00242         uint4_t        sys_er,
00243         w_error_t*        list,
00244         const char*        more_info)
00245         : err_num(er),
00246           file(fi), line(li), 
00247           sys_err_num(sys_er),
00248           more_info_msg(more_info),
00249           _trace_cnt(0),
00250           _next(list)
00251 {
00252     CHECK_STRING(more_info_msg);
00253     claim();
00254     CHECKIT;
00255 }
00256 
00257 w_error_t*
00258 w_error_t::make(
00259         const char* const    filename,
00260         uint4_t              line_num,
00261         err_num_t            err_num,
00262         uint4_t              sys_err,
00263         w_error_t*           list,
00264         const char*          more_info)
00265 {
00266     CHECK_STRING(more_info);
00267 
00268 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00269   return  new (*w_error_alloc) w_error_t(filename, line_num, 
00270           err_num, sys_err, list, more_info);
00271   
00272   
00273 #else
00274     return new  w_error_t(filename, line_num, err_num, sys_err, list, more_info);
00275 #endif
00276 }
00277 
00278 
00279 
00280 
00281 
00282 bool
00283 w_error_t::insert(
00284         const char *        modulename,
00285         const info_t    info[],
00286         uint4_t        count)
00287 {
00288     if (_nreg >= max_range)
00289         return false;
00290 
00291     err_num_t start = info[0].err_num;
00292 
00293     for (uint4_t i = 0; i < _nreg; i++)  {
00294         if (start >= _range_start[i]->err_num && start < _range_cnt[i])
00295             return false;
00296         uint4_t end = start + count;
00297         if (end >= _range_start[i]->err_num && end < _range_cnt[i])
00298             return false;
00299     }
00300     _range_start[_nreg] = info;
00301     _range_cnt[_nreg] = count;
00302     _range_name[_nreg] = modulename;
00303 
00304     ++_nreg;
00305     return true;
00306 }
00307 
00308 const char* 
00309 w_error_t::error_string(err_num_t err_num)
00310 {
00311     if(err_num ==  w_error_t::no_error->err_num ) {
00312         return "no error";
00313     }
00314     uint4_t i;
00315     for (i = 0; i < _nreg; i++)  {
00316         if (err_num >= _range_start[i]->err_num && 
00317             err_num <= _range_start[i]->err_num + _range_cnt[i]) {
00318             break;
00319         }
00320     }
00321         
00322     if (i == _nreg)  {
00323         w_error_t_no_error_code();
00324         return error_string( fcNOSUCHERROR );
00325         
00326     }
00327 
00328     const uint4_t j = CAST(int, err_num - _range_start[i]->err_num);
00329     return _range_start[i][j].errstr;
00330 }
00331 
00332 const char*
00333 w_error_t::module_name(err_num_t err_num)
00334 {
00335     if(err_num ==  w_error_t::no_error->err_num ) {
00336             return "all modules";
00337     }
00338     uint4_t i;
00339     for (i = 0; i < _nreg; i++)  {
00340         if (err_num >= _range_start[i]->err_num && 
00341             err_num <= _range_start[i]->err_num + _range_cnt[i]) {
00342             break;
00343         }
00344     }
00345     
00346     if (i == _nreg)  {
00347         return "unknown module";
00348     }
00349     return _range_name[i];
00350 }
00351 
00352 void format_unix_error(int err, char *buf, int bufsize)
00353 {
00354 #ifdef HAVE_STRERROR
00355     char    *s = strerror(err);
00356 #else
00357     char    *s = "No strerror function. Cannot format unix error.";
00358 #endif
00359     strncpy(buf, s, bufsize);
00360     buf[bufsize-1] = '\0';
00361 }
00362 
00363 ostream& w_error_t::print_error(ostream &o) const
00364 {
00365     if (this == w_error_t::no_error) {
00366         return o << "no error";
00367     }
00368 
00369     int cnt = 1;
00370     for (const w_error_t* p = this; p; p = p->_next, ++cnt)  {
00371 
00372         const char* f = strrchr(p->file, '/');
00373         f ? ++f : f = p->file;
00374         o << cnt << ". error in " << f << ':' << p->line << " ";
00375         if(cnt > 1) {
00376             if(p == this) {
00377                 o << "Error recurses, stopping" << endl;
00378                 break;
00379             } 
00380             if(p->_next == p) {
00381                 o << "Error next is same, stopping" << endl;
00382             break;
00383             }
00384         }
00385         if(cnt > 20) {
00386             o << "Error chain >20, stopping" << endl;
00387             break;
00388         }
00389         o << p->error_string(p->err_num);
00390         o << " [0x" << hex << p->err_num << dec << "]";
00391 
00392         
00393 
00394         switch (p->err_num) {
00395         case fcOS: {
00396             char buf[1024];
00397             format_unix_error(p->sys_err_num, buf, sizeof(buf));
00398             o << " --- " << buf;
00399             break;
00400             } 
00401         }
00402 
00403         o << endl;
00404 
00405         if (more_info_msg)  {
00406             o << "\tadditional information: " << more_info_msg << endl;
00407         }
00408 
00409         if (p->_trace_cnt)  {
00410             o << "\tcalled from:" << endl;
00411             for (unsigned i = 0; i < p->_trace_cnt; i++)  {
00412                 f = strrchr(p->_trace_file[i], '/');
00413                 f ? ++f : f = p->_trace_file[i];
00414                 o << "\t" << i << ") " << f << ':' 
00415                   << p->_trace_line[i] << endl;
00416             }
00417         }
00418     }
00419 
00420     return o;
00421 }
00422 
00423 ostream &operator<<(ostream &o, const w_error_t &obj)
00424 {
00425         return obj.print_error(o);
00426 }
00427 
00428 ostream &
00429 w_error_t::print(ostream &out)
00430 {
00431     for (unsigned i = 0; i < _nreg; i++)  {
00432         err_num_t first    = _range_start[i]->err_num;
00433         unsigned int last    = first + _range_cnt[i] - 1;
00434 
00435         for (unsigned j = first; j <= last; j++)  {
00436             const char *c = module_name(j);
00437             const char *s = error_string(j);
00438 
00439             out <<  c << ":" << j << ":" << s << endl;
00440         }
00441     }
00442         
00443     return out;
00444 }
00445 
00446 
00447 
00448 
00449 
00450 
00451 
00452 
00453 
00454 
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468 
00469 
00470 
00471 
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497 
00498 
00499 
00500 
00501 
00502 
00503 
00504 
00505 
00506 
00507 
00508 
00509 
00510 
00511 
00512 
00513 
00514 
00515 
00516 
00517 
00518 
00519 
00520 
00521 
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 
00535 
00536 
00537 
00538 
00539 
00540 
00541 
00542 
00543 
00544 
00545 
00546 
00547 
00548 
00549 
00550 
00551 
00552 
00553 
00554 
00555 
00556 
00557 
00558 
00559 
00560 
00561 
00562 
00563 
00564 
00565 
00566 
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 
00576 
00577 
00578 
00579 
00580 
00581 
00582 
00583 
00584 
00585 
00586 
00587 
00588 
00589 
00590 
00591 
00592 
00593 
00594 
00595 
00596 
00597 
00598 
00599 
00600 
00601 
00602 
00603 
00604 
00605 
00606 
00607