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