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