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 #if defined(__GNUC__)
00058 #pragma implementation "w_error.h"
00059 #endif
00060 
00061 #include <cstring>
00062 
00063 #include <w_base.h>
00064 const
00065 #include <fc_einfo_gen.h>
00066 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00067 #include "block_alloc.h"
00068 #endif
00069 
00070 
00071 
00072 
00073 const 
00074 w_error_t::info_t*        w_error_t::_range_start[w_error_t::max_range] = {
00075     w_error_t::error_info, 0 
00076 };
00077 w_base_t::uint4_t        w_error_t::_range_cnt[w_error_t::max_range] = {
00078     fcERRMAX - fcERRMIN + 1, 0
00079 };
00080 
00081 const char *w_error_t::_range_name[w_error_t::max_range]= { 
00082     "Foundation Classes",
00083     0
00084 };
00085 w_base_t::uint4_t        w_error_t::_nreg = 1;
00086 
00087 const w_error_t w_error_t::no_error_instance(__FILE__, __LINE__, 0, 0, 0);
00088 
00089 w_error_t* const w_error_t::no_error = const_cast<w_error_t *>(&no_error_instance);
00090 
00091 static void w_error_t_no_error_code()
00092 {
00093 }
00094 w_error_t&
00095 w_error_t::add_trace_info(
00096         const char* const    filename,
00097         uint4_t        line_num)
00098 {
00099     if (_trace_cnt < max_trace)  {
00100         _trace_file[_trace_cnt] = filename;
00101         _trace_line[_trace_cnt] = line_num;
00102         ++_trace_cnt;
00103     }
00104 
00105     return *this;
00106 }
00107 
00108 #if W_DEBUG_LEVEL > 1
00109 #define CHECK_STRING(x) if((x) != NULL) w_assert2(*(x) != 0)
00110 #else
00111 #define CHECK_STRING(x) 
00112 #endif
00113 
00114 w_error_t&
00115 w_error_t::clear_more_info_msg()
00116 {
00117     delete[] more_info_msg;
00118     more_info_msg = NULL;
00119     return *this;
00120 }
00121 
00122 w_error_t&
00123 w_error_t::append_more_info_msg(const char* more_info)
00124 {
00125     CHECK_STRING(more_info);
00126     if (more_info)  
00127     {
00128         int more_info_len = strlen(more_info);
00129         if(more_info_len > 0)
00130         {
00131             if(more_info[more_info_len-1] == '\n') more_info_len--;
00132 
00133             int more_info_msg_len = more_info_msg?strlen(more_info_msg):0;
00134             char* new_more_info_msg = new 
00135                 char[more_info_len + more_info_msg_len + 2];
00136             if(more_info_msg) { 
00137                 strcpy(new_more_info_msg, more_info_msg);
00138             }
00139             strcpy(new_more_info_msg + more_info_msg_len, more_info);
00140             new_more_info_msg[more_info_msg_len + more_info_len] = '\n';
00141             new_more_info_msg[more_info_msg_len + more_info_len + 1] = '\0';
00142 
00143             if(more_info_msg) delete[] more_info_msg;
00144             more_info_msg = new_more_info_msg;
00145 
00146             CHECK_STRING(more_info_msg);
00147         }
00148     }
00149 
00150     return *this;
00151 }
00152 
00153 const char*
00154 w_error_t::get_more_info_msg() const
00155 { 
00156     CHECK_STRING(more_info_msg);
00157     return more_info_msg;
00158 }
00159 
00160 
00161 inline w_base_t::uint4_t w_error_t::classify(int er)
00162 {
00163     uint4_t    sys = 0;
00164     switch (er) {
00165     case fcOS:
00166         sys = errno;
00167         break;
00168     }
00169     return sys;
00170 }
00171 
00172 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00173 DEFINE_TLS_SCHWARZ(block_alloc<w_error_t>, w_error_alloc);
00174 
00175 
00176 
00177 
00178 
00179 
00180 
00181 
00182 void w_error_t::operator delete(void* p) {
00183     DEBUG_BLOCK_ALLOC_MARK_FOR_DELETION((w_error_t *)p)
00184     block_alloc<w_error_t>::destroy_object((w_error_t*) p);
00185 }
00186 #endif
00187 
00188 
00189 inline
00190 w_error_t::w_error_t(const char* const        fi,
00191                  uint4_t        li,
00192                  err_num_t        er,
00193                  w_error_t*        list,
00194                  const char*    more_info)
00195 : err_num(er),
00196   file(fi),
00197   line(li), 
00198   sys_err_num(classify(er)),
00199   more_info_msg(more_info),
00200   _trace_cnt(0),
00201   _next(list)
00202 {
00203     CHECK_STRING(more_info_msg);
00204     CHECKIT;
00205 }
00206 
00207 
00208 w_error_t*
00209 w_error_t::make(
00210         const char* const    filename,
00211         uint4_t              line_num,
00212         err_num_t            err_num,
00213         w_error_t*           list,
00214         const char*          more_info)
00215 {
00216 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00217     return new (*w_error_alloc) w_error_t(filename, line_num, err_num, list, more_info);
00218 #else
00219     return new  w_error_t(filename, line_num, err_num, list, more_info);
00220 #endif
00221 
00222 }
00223 
00224 inline NORET
00225 w_error_t::w_error_t(
00226         const char* const    fi,
00227         uint4_t        li,
00228         err_num_t      er,
00229         uint4_t        sys_er,
00230         w_error_t*        list,
00231         const char*        more_info)
00232         : err_num(er),
00233           file(fi), line(li), 
00234           sys_err_num(sys_er),
00235           more_info_msg(more_info),
00236           _trace_cnt(0),
00237           _next(list)
00238 {
00239     CHECK_STRING(more_info_msg);
00240     CHECKIT;
00241 }
00242 
00243 w_error_t*
00244 w_error_t::make(
00245         const char* const    filename,
00246         uint4_t              line_num,
00247         err_num_t            err_num,
00248         uint4_t              sys_err,
00249         w_error_t*           list,
00250         const char*          more_info)
00251 {
00252     CHECK_STRING(more_info);
00253 
00254 #if USE_BLOCK_ALLOC_FOR_W_ERROR_T
00255   return  new (*w_error_alloc) w_error_t(filename, line_num, 
00256           err_num, sys_err, list, more_info);
00257   
00258   
00259 #else
00260     return new  w_error_t(filename, line_num, err_num, sys_err, list, more_info);
00261 #endif
00262 }
00263 
00264 
00265 
00266 
00267 
00268 bool
00269 w_error_t::insert(
00270         const char *        modulename,
00271         const info_t    info[],
00272         uint4_t        count)
00273 {
00274     if (_nreg >= max_range)
00275         return false;
00276 
00277     err_num_t start = info[0].err_num;
00278 
00279     for (uint4_t i = 0; i < _nreg; i++)  {
00280         if (start >= _range_start[i]->err_num && start < _range_cnt[i])
00281             return false;
00282         uint4_t end = start + count;
00283         if (end >= _range_start[i]->err_num && end < _range_cnt[i])
00284             return false;
00285     }
00286     _range_start[_nreg] = info;
00287     _range_cnt[_nreg] = count;
00288     _range_name[_nreg] = modulename;
00289 
00290     ++_nreg;
00291     return true;
00292 }
00293 
00294 const char* 
00295 w_error_t::error_string(err_num_t err_num)
00296 {
00297     if(err_num ==  w_error_t::no_error->err_num ) {
00298         return "no error";
00299     }
00300     uint4_t i;
00301     for (i = 0; i < _nreg; i++)  {
00302         if (err_num >= _range_start[i]->err_num && 
00303             err_num <= _range_start[i]->err_num + _range_cnt[i]) {
00304             break;
00305         }
00306     }
00307         
00308     if (i == _nreg)  {
00309         w_error_t_no_error_code();
00310         return error_string( fcNOSUCHERROR );
00311         
00312     }
00313 
00314     const uint4_t j = CAST(int, err_num - _range_start[i]->err_num);
00315     return _range_start[i][j].errstr;
00316 }
00317 
00318 const char*
00319 w_error_t::module_name(err_num_t err_num)
00320 {
00321     if(err_num ==  w_error_t::no_error->err_num ) {
00322             return "all modules";
00323     }
00324     uint4_t i;
00325     for (i = 0; i < _nreg; i++)  {
00326         if (err_num >= _range_start[i]->err_num && 
00327             err_num <= _range_start[i]->err_num + _range_cnt[i]) {
00328             break;
00329         }
00330     }
00331     
00332     if (i == _nreg)  {
00333         return "unknown module";
00334     }
00335     return _range_name[i];
00336 }
00337 
00338 void format_unix_error(int err, char *buf, int bufsize)
00339 {
00340 #ifdef HAVE_STRERROR
00341     char    *s = strerror(err);
00342 #else
00343     char    *s = "No strerror function. Cannot format unix error.";
00344 #endif
00345     strncpy(buf, s, bufsize);
00346     buf[bufsize-1] = '\0';
00347 }
00348 
00349 ostream& w_error_t::print_error(ostream &o) const
00350 {
00351     if (this == w_error_t::no_error) {
00352         return o << "no error";
00353     }
00354 
00355     int cnt = 1;
00356     for (const w_error_t* p = this; p; p = p->_next, ++cnt)  {
00357 
00358         const char* f = strrchr(p->file, '/');
00359         f ? ++f : f = p->file;
00360         o << cnt << ". error in " << f << ':' << p->line << " ";
00361         if(cnt > 1) {
00362             if(p == this) {
00363                 o << "Error recurses, stopping" << endl;
00364                 break;
00365             } 
00366             if(p->_next == p) {
00367                 o << "Error next is same, stopping" << endl;
00368             break;
00369             }
00370         }
00371         if(cnt > 20) {
00372             o << "Error chain >20, stopping" << endl;
00373             break;
00374         }
00375         o << p->error_string(p->err_num);
00376         o << " [0x" << hex << p->err_num << dec << "]";
00377 
00378         
00379 
00380         switch (p->err_num) {
00381         case fcOS: {
00382             char buf[1024];
00383             format_unix_error(p->sys_err_num, buf, sizeof(buf));
00384             o << " --- " << buf;
00385             break;
00386             } 
00387         }
00388 
00389         o << endl;
00390 
00391         if (more_info_msg)  {
00392             o << "\tadditional information: " << more_info_msg << endl;
00393         }
00394 
00395         if (p->_trace_cnt)  {
00396             o << "\tcalled from:" << endl;
00397             for (unsigned i = 0; i < p->_trace_cnt; i++)  {
00398                 f = strrchr(p->_trace_file[i], '/');
00399                 f ? ++f : f = p->_trace_file[i];
00400                 o << "\t" << i << ") " << f << ':' 
00401                   << p->_trace_line[i] << endl;
00402             }
00403         }
00404     }
00405 
00406     return o;
00407 }
00408 
00409 ostream &operator<<(ostream &o, const w_error_t &obj)
00410 {
00411         return obj.print_error(o);
00412 }
00413 
00414 ostream &
00415 w_error_t::print(ostream &out)
00416 {
00417     for (unsigned i = 0; i < _nreg; i++)  {
00418         err_num_t first    = _range_start[i]->err_num;
00419         unsigned int last    = first + _range_cnt[i] - 1;
00420 
00421         for (unsigned j = first; j <= last; j++)  {
00422             const char *c = module_name(j);
00423             const char *s = error_string(j);
00424 
00425             out <<  c << ":" << j << ":" << s << endl;
00426         }
00427     }
00428         
00429     return out;
00430 }
00431 
00432 
00433 
00434 
00435 
00436 
00437 
00438 
00439 
00440 
00441 
00442 
00443 
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