Panda3D

notify.cxx

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 }
 All Classes Functions Variables Enumerations