Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

dtool/src/dconfig/notify.cxx

Go to the documentation of this file.
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 }

Generated on Thu May 1 22:12:57 2003 for DTool by doxygen1.3