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
00339 #ifdef HAVE_STRERROR
00340 err
00341 #else
00342 #endif
00343 , char *buf, int bufsize)
00344 {
00345 #ifdef HAVE_STRERROR
00346 char *s = strerror(err);
00347 #else
00348 const 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