Panda3D
|
00001 // Filename: notify.cxx 00002 // Created by: drose (28Feb00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pnotify.h" 00016 #include "notifyCategory.h" 00017 #include "configPageManager.h" 00018 #include "configVariableFilename.h" 00019 #include "configVariableBool.h" 00020 #include "filename.h" 00021 #include "config_prc.h" 00022 00023 #include <ctype.h> 00024 00025 #ifdef BUILD_IPHONE 00026 #include <fcntl.h> 00027 #endif 00028 00029 Notify *Notify::_global_ptr = (Notify *)NULL; 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: Notify::Constructor 00033 // Access: Public 00034 // Description: 00035 //////////////////////////////////////////////////////////////////// 00036 Notify:: 00037 Notify() { 00038 _ostream_ptr = &cerr; 00039 _owns_ostream_ptr = false; 00040 _null_ostream_ptr = new fstream; 00041 00042 _assert_handler = (AssertHandler *)NULL; 00043 _assert_failed = false; 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: Notify::Destructor 00048 // Access: Public 00049 // Description: 00050 //////////////////////////////////////////////////////////////////// 00051 Notify:: 00052 ~Notify() { 00053 if (_owns_ostream_ptr) { 00054 delete _ostream_ptr; 00055 } 00056 delete _null_ostream_ptr; 00057 } 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Function: Notify::set_ostream_ptr 00061 // Access: Public 00062 // Description: Changes the ostream that all subsequent Notify 00063 // messages will be written to. If the previous ostream 00064 // was set with delete_later = true, this will delete 00065 // the previous ostream. If ostream_ptr is NULL, this 00066 // resets the default to cerr. 00067 //////////////////////////////////////////////////////////////////// 00068 void Notify:: 00069 set_ostream_ptr(ostream *ostream_ptr, bool delete_later) { 00070 if (_owns_ostream_ptr && ostream_ptr != _ostream_ptr) { 00071 delete _ostream_ptr; 00072 } 00073 00074 if (ostream_ptr == (ostream *)NULL) { 00075 _ostream_ptr = &cerr; 00076 _owns_ostream_ptr = false; 00077 } else { 00078 _ostream_ptr = ostream_ptr; 00079 _owns_ostream_ptr = delete_later; 00080 } 00081 } 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: Notify::get_ostream_ptr 00085 // Access: Public 00086 // Description: Returns the system-wide ostream for all Notify 00087 // messages. 00088 //////////////////////////////////////////////////////////////////// 00089 ostream *Notify:: 00090 get_ostream_ptr() const { 00091 return _ostream_ptr; 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: Notify::get_literal_flag 00096 // Access: Public 00097 // Description: Returns a flag that may be set on the Notify stream 00098 // via setf() that, when set, enables "literal" mode, 00099 // which means the Notify stream will not attempt to do 00100 // any fancy formatting (like word-wrapping). 00101 // 00102 // Notify does not itself respect this flag; this is 00103 // left up to the ostream that Notify writes to. Note 00104 // that Notify just maps to cerr by default, in which 00105 // case this does nothing. But the flag is available in 00106 // case any extended types want to make use of it. 00107 //////////////////////////////////////////////////////////////////// 00108 ios_fmtflags Notify:: 00109 get_literal_flag() { 00110 static bool got_flag = false; 00111 static ios_fmtflags flag; 00112 00113 if (!got_flag) { 00114 #ifndef PHAVE_IOSTREAM 00115 flag = ios::bitalloc(); 00116 #else 00117 // We lost bitalloc in the new iostream? Ok, this feature will 00118 // just be disabled for now. No big deal. 00119 flag = (ios_fmtflags)0; 00120 #endif 00121 got_flag = true; 00122 } 00123 00124 return flag; 00125 } 00126 00127 //////////////////////////////////////////////////////////////////// 00128 // Function: Notify::set_assert_handler 00129 // Access: Public 00130 // Description: Sets a pointer to a C function that will be called 00131 // when an assertion test fails. This function may 00132 // decide what to do when that happens: it may choose to 00133 // abort or return. If it returns, it should return 00134 // true to indicate that the assertion should be 00135 // respected (and the calling function should return out 00136 // of its block of code), or false to indicate that the 00137 // assertion should be completely ignored. 00138 // 00139 // If an assert handler is installed, it completely 00140 // replaces the default behavior of nassertr() and 00141 // nassertv(). 00142 //////////////////////////////////////////////////////////////////// 00143 void Notify:: 00144 set_assert_handler(Notify::AssertHandler *assert_handler) { 00145 _assert_handler = assert_handler; 00146 } 00147 00148 //////////////////////////////////////////////////////////////////// 00149 // Function: Notify::clear_assert_handler 00150 // Access: Public 00151 // Description: Removes the installed assert handler and restores 00152 // default behavior of nassertr() and nassertv(). 00153 //////////////////////////////////////////////////////////////////// 00154 void Notify:: 00155 clear_assert_handler() { 00156 _assert_handler = (AssertHandler *)NULL; 00157 } 00158 00159 //////////////////////////////////////////////////////////////////// 00160 // Function: Notify::has_assert_handler 00161 // Access: Public 00162 // Description: Returns true if a user assert handler has been 00163 // installed, false otherwise. 00164 //////////////////////////////////////////////////////////////////// 00165 bool Notify:: 00166 has_assert_handler() const { 00167 return (_assert_handler != (AssertHandler *)NULL); 00168 } 00169 00170 //////////////////////////////////////////////////////////////////// 00171 // Function: Notify::get_assert_handler 00172 // Access: Public 00173 // Description: Returns a pointer to the user-installed assert 00174 // handler, if one was installed, or NULL otherwise. 00175 //////////////////////////////////////////////////////////////////// 00176 Notify::AssertHandler *Notify:: 00177 get_assert_handler() const { 00178 return _assert_handler; 00179 } 00180 00181 //////////////////////////////////////////////////////////////////// 00182 // Function: Notify::has_assert_failed 00183 // Access: Public 00184 // Description: Returns true if an assertion test has failed (and not 00185 // been ignored) since the last call to 00186 // clear_assert_failed(). 00187 // 00188 // When an assertion test fails, the assert handler 00189 // may decide either to abort, return, or ignore the 00190 // assertion. Naturally, if it decides to abort, this 00191 // flag is irrelevant. If it chooses to ignore the 00192 // assertion, the flag is not set. However, if the 00193 // assert handler chooses to return out of the 00194 // function (the normal case), it will also set this 00195 // flag to indicate that an assertion failure has 00196 // occurred. 00197 // 00198 // This will also be the behavior in the absence of a 00199 // user-defined assert handler. 00200 //////////////////////////////////////////////////////////////////// 00201 bool Notify:: 00202 has_assert_failed() const { 00203 return _assert_failed; 00204 } 00205 00206 //////////////////////////////////////////////////////////////////// 00207 // Function: Notify::get_assert_error_message 00208 // Access: Public 00209 // Description: Returns the error message that corresponds to the 00210 // assertion that most recently failed. 00211 //////////////////////////////////////////////////////////////////// 00212 const string &Notify:: 00213 get_assert_error_message() const { 00214 return _assert_error_message; 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: Notify::clear_assert_failed 00219 // Access: Public 00220 // Description: Resets the assert_failed flag that is set whenever an 00221 // assertion test fails. See has_assert_failed(). 00222 //////////////////////////////////////////////////////////////////// 00223 void Notify:: 00224 clear_assert_failed() { 00225 _assert_failed = false; 00226 } 00227 00228 00229 //////////////////////////////////////////////////////////////////// 00230 // Function: Notify::get_top_category 00231 // Access: Public 00232 // Description: Returns the topmost Category in the hierarchy. This 00233 // may be used to traverse the hierarchy of available 00234 // Categories. 00235 //////////////////////////////////////////////////////////////////// 00236 NotifyCategory *Notify:: 00237 get_top_category() { 00238 return get_category(string()); 00239 } 00240 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: Notify::get_category 00243 // Access: Public 00244 // Description: Finds or creates a new Category given the basename of 00245 // the category and its parent in the category 00246 // hierarchy. The parent pointer may be NULL to 00247 // indicate this is a top-level Category. 00248 //////////////////////////////////////////////////////////////////// 00249 NotifyCategory *Notify:: 00250 get_category(const string &basename, NotifyCategory *parent_category) { 00251 // The string should not contain colons. 00252 nassertr(basename.find(':') == string::npos, (NotifyCategory *)NULL); 00253 00254 string fullname; 00255 if (parent_category != (NotifyCategory *)NULL) { 00256 fullname = parent_category->get_fullname() + ":" + basename; 00257 } else { 00258 // The parent_category is NULL. If basename is empty, that means 00259 // we refer to the very top-level category (with an empty 00260 // fullname); otherwise, it's a new category just below that top 00261 // level. 00262 if (!basename.empty()) { 00263 parent_category = get_top_category(); 00264 fullname = ":" + basename; 00265 } 00266 } 00267 00268 pair<Categories::iterator, bool> result = 00269 _categories.insert(Categories::value_type(fullname, (NotifyCategory *)NULL)); 00270 00271 bool inserted = result.second; 00272 NotifyCategory *&category = (*result.first).second; 00273 00274 if (inserted) { 00275 // If we just inserted a new record, then we have to create a new 00276 // Category pointer. Otherwise, there was already one created 00277 // from before. 00278 category = new NotifyCategory(fullname, basename, parent_category); 00279 } 00280 00281 return category; 00282 } 00283 00284 //////////////////////////////////////////////////////////////////// 00285 // Function: Notify::get_category 00286 // Access: Public 00287 // Description: Finds or creates a new Category given the basename of 00288 // the category and the fullname of its parent. This is 00289 // another way to create a category when you don't have 00290 // a pointer to its parent handy, but you know the name 00291 // of its parent. If the parent Category does not 00292 // already exist, it will be created. 00293 //////////////////////////////////////////////////////////////////// 00294 NotifyCategory *Notify:: 00295 get_category(const string &basename, const string &parent_fullname) { 00296 return get_category(basename, get_category(parent_fullname)); 00297 } 00298 00299 //////////////////////////////////////////////////////////////////// 00300 // Function: Notify::get_category 00301 // Access: Public 00302 // Description: Finds or creates a new Category given the fullname of 00303 // the Category. This name should be a sequence of 00304 // colon-separated names of parent Categories, ending in 00305 // the basename of this Category, 00306 // e.g. display:glxdisplay. This is a shorthand way to 00307 // define a Category when a pointer to its parent is not 00308 // handy. 00309 //////////////////////////////////////////////////////////////////// 00310 NotifyCategory *Notify:: 00311 get_category(const string &fullname) { 00312 Categories::const_iterator ci; 00313 ci = _categories.find(fullname); 00314 if (ci != _categories.end()) { 00315 return (*ci).second; 00316 } 00317 00318 // No such Category; create one. First identify the parent name, 00319 // based on the rightmost colon. 00320 NotifyCategory *parent_category = (NotifyCategory *)NULL; 00321 string basename = fullname; 00322 00323 size_t colon = fullname.rfind(':'); 00324 if (colon != string::npos) { 00325 parent_category = get_category(fullname.substr(0, colon)); 00326 basename = fullname.substr(colon + 1); 00327 00328 } else if (!fullname.empty()) { 00329 // The fullname didn't begin with a colon. Infer one. 00330 parent_category = get_top_category(); 00331 } 00332 00333 return get_category(basename, parent_category); 00334 } 00335 00336 //////////////////////////////////////////////////////////////////// 00337 // Function: Notify::out 00338 // Access: Public, Static 00339 // Description: A convenient way to get the ostream that should be 00340 // written to for a Notify-type message. Also see 00341 // Category::out() for a message that is specific to a 00342 // particular Category. 00343 //////////////////////////////////////////////////////////////////// 00344 ostream &Notify:: 00345 out() { 00346 return *(ptr()->_ostream_ptr); 00347 } 00348 00349 //////////////////////////////////////////////////////////////////// 00350 // Function: Notify::null 00351 // Access: Public, Static 00352 // Description: A convenient way to get an ostream that doesn't do 00353 // anything. Returned by Category::out() when a 00354 // particular Category and/or Severity is disabled. 00355 //////////////////////////////////////////////////////////////////// 00356 ostream &Notify:: 00357 null() { 00358 return *(ptr()->_null_ostream_ptr); 00359 } 00360 00361 //////////////////////////////////////////////////////////////////// 00362 // Function: Notify::write_string 00363 // Access: Public, Static 00364 // Description: A convenient way for scripting languages, which may 00365 // know nothing about ostreams, to write to Notify. 00366 // This writes a single string, followed by an implicit 00367 // newline, to the Notify output stream. 00368 //////////////////////////////////////////////////////////////////// 00369 void Notify:: 00370 write_string(const string &str) { 00371 out() << str << "\n"; 00372 } 00373 00374 //////////////////////////////////////////////////////////////////// 00375 // Function: Notify::ptr 00376 // Access: Public, Static 00377 // Description: Returns the pointer to the global Notify object. 00378 // There is only one of these in the world. 00379 //////////////////////////////////////////////////////////////////// 00380 Notify *Notify:: 00381 ptr() { 00382 if (_global_ptr == (Notify *)NULL) { 00383 init_memory_hook(); 00384 _global_ptr = new Notify; 00385 } 00386 return _global_ptr; 00387 } 00388 00389 //////////////////////////////////////////////////////////////////// 00390 // Function: Notify::assert_failure 00391 // Access: Public 00392 // Description: This function is not intended to be called directly 00393 // by user code. It's called from the nassertr() and 00394 // assertv() macros when an assertion test fails; it 00395 // handles the job of printing the warning message and 00396 // deciding what to do about it. 00397 // 00398 // If this function returns true, the calling function 00399 // should return out of its function; if it returns 00400 // false, the calling function should ignore the 00401 // assertion. 00402 //////////////////////////////////////////////////////////////////// 00403 bool Notify:: 00404 assert_failure(const string &expression, int line, 00405 const char *source_file) { 00406 return assert_failure(expression.c_str(), line, source_file); 00407 } 00408 00409 //////////////////////////////////////////////////////////////////// 00410 // Function: Notify::assert_failure 00411 // Access: Public 00412 // Description: This function is not intended to be called directly 00413 // by user code. It's called from the nassertr() and 00414 // assertv() macros when an assertion test fails; it 00415 // handles the job of printing the warning message and 00416 // deciding what to do about it. 00417 // 00418 // If this function returns true, the calling function 00419 // should return out of its function; if it returns 00420 // false, the calling function should ignore the 00421 // assertion. 00422 //////////////////////////////////////////////////////////////////// 00423 bool Notify:: 00424 assert_failure(const char *expression, int line, 00425 const char *source_file) { 00426 ostringstream message_str; 00427 message_str 00428 << expression << " at line " << line << " of " << source_file; 00429 string message = message_str.str(); 00430 00431 if (!_assert_failed) { 00432 // We only save the first assertion failure message, as this is 00433 // usually the most meaningful when several occur in a row. 00434 _assert_failed = true; 00435 _assert_error_message = message; 00436 } 00437 00438 if (has_assert_handler()) { 00439 return (*_assert_handler)(expression, line, source_file); 00440 } 00441 00442 nout << "Assertion failed: " << message << "\n"; 00443 00444 // This is redefined here, shadowing the defining in config_prc.h, 00445 // so we can guarantee it has already been constructed. 00446 ConfigVariableBool assert_abort("assert-abort", false); 00447 if (assert_abort) { 00448 #ifdef WIN32 00449 // How to trigger an exception in VC++ that offers to take us into 00450 // the debugger? abort() doesn't do it. We used to be able to 00451 // assert(false), but in VC++ 7 that just throws an exception, and 00452 // an uncaught exception just exits, without offering to open the 00453 // debugger. 00454 00455 // DebugBreak() seems to be provided for this purpose, but it 00456 // doesn't seem to work properly either, since we don't seem to 00457 // get a reliable stack trace. 00458 00459 // The old reliable int 3 works (at least on an Intel platform) if 00460 // you are already running within a debugger. But it doesn't 00461 // offer to bring up a debugger otherwise. 00462 00463 // So we'll force a segfault, which works every time. 00464 int *ptr = (int *)NULL; 00465 *ptr = 1; 00466 00467 #else // WIN32 00468 abort(); 00469 #endif // WIN32 00470 } 00471 00472 return true; 00473 } 00474 00475 //////////////////////////////////////////////////////////////////// 00476 // Function: Notify::string_severity 00477 // Access: Public 00478 // Description: Given a string, one of "debug", "info", "warning", 00479 // etc., return the corresponding Severity level, or 00480 // NS_unspecified if none of the strings matches. 00481 //////////////////////////////////////////////////////////////////// 00482 NotifySeverity Notify:: 00483 string_severity(const string &str) { 00484 // Convert the string to lowercase for a case-insensitive 00485 // comparison. 00486 string lstring; 00487 for (string::const_iterator si = str.begin(); 00488 si != str.end(); 00489 ++si) { 00490 lstring += tolower(*si); 00491 } 00492 00493 if (lstring == "spam") { 00494 return NS_spam; 00495 00496 } else if (lstring == "debug") { 00497 return NS_debug; 00498 00499 } else if (lstring == "info") { 00500 return NS_info; 00501 00502 } else if (lstring == "warning") { 00503 return NS_warning; 00504 00505 } else if (lstring == "error") { 00506 return NS_error; 00507 00508 } else if (lstring == "fatal") { 00509 return NS_fatal; 00510 00511 } else { 00512 return NS_unspecified; 00513 } 00514 } 00515 00516 //////////////////////////////////////////////////////////////////// 00517 // Function: Notify::config_initialized 00518 // Access: Public 00519 // Description: Intended to be called only by Config, this is a 00520 // callback that indicates to Notify when Config has 00521 // done initializing and Notify can safely set up some 00522 // internal state variables that depend on Config 00523 // variables. 00524 //////////////////////////////////////////////////////////////////// 00525 void Notify:: 00526 config_initialized() { 00527 static bool already_initialized = false; 00528 if (already_initialized) { 00529 nout << "Notify::config_initialized() called more than once.\n"; 00530 return; 00531 } 00532 already_initialized = true; 00533 00534 if (_ostream_ptr == &cerr) { 00535 ConfigVariableFilename notify_output 00536 ("notify-output", "", 00537 "The filename to which to write all the output of notify"); 00538 00539 if (!notify_output.empty()) { 00540 if (notify_output == "stdout") { 00541 cout.setf(ios::unitbuf); 00542 set_ostream_ptr(&cout, false); 00543 00544 } else if (notify_output == "stderr") { 00545 set_ostream_ptr(&cerr, false); 00546 00547 } else { 00548 Filename filename = notify_output; 00549 filename.set_text(); 00550 #ifdef BUILD_IPHONE 00551 // On the iPhone, route everything through cerr, and then send 00552 // cerr to the log file, since we can't get the cerr output 00553 // otherwise. 00554 string os_specific = filename.to_os_specific(); 00555 int logfile_fd = open(os_specific.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666); 00556 if (logfile_fd < 0) { 00557 nout << "Unable to open file " << filename << " for output.\n"; 00558 } else { 00559 dup2(logfile_fd, STDOUT_FILENO); 00560 dup2(logfile_fd, STDERR_FILENO); 00561 close(logfile_fd); 00562 00563 set_ostream_ptr(&cerr, false); 00564 } 00565 #else 00566 pofstream *out = new pofstream; 00567 if (!filename.open_write(*out)) { 00568 nout << "Unable to open file " << filename << " for output.\n"; 00569 delete out; 00570 } else { 00571 out->setf(ios::unitbuf); 00572 set_ostream_ptr(out, true); 00573 } 00574 #endif // BUILD_IPHONE 00575 } 00576 } 00577 } 00578 }