misc.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file misc.cpp
00003  * This file contains a miscellaneous collection of global data
00004  * functions and text for the globalData module (see \ref globalData), the
00005  * logs module (see \ref logs), and the HTML_logs module (see \ref HTML_logs).
00006  *
00007  * These modules are defined here:
00008  *      globalData 
00009  *      logs
00010  *      HTML_logs
00011  */
00012 /*
00013  *  $Id: misc.cpp 397 2010-02-09 19:57:02Z hkmoffa $
00014  */
00015 
00016 #ifdef WIN32
00017 #pragma warning(disable:4786)
00018 #pragma warning(disable:4503)
00019 #pragma warning(disable:4996)
00020 #endif
00021 
00022 // RFB:TODO May need OS specifc include to use varargs.h instead
00023 #include <stdarg.h>
00024 
00025 #include "global.h"
00026 #include "ctexceptions.h"
00027 #include "stringUtils.h"
00028 #include "units.h"
00029 #include "xml.h"
00030 #include "ctml.h"
00031 #include "FactoryBase.h"
00032 #include "logger.h"
00033 
00034 
00035 #include <fstream>
00036 #include <memory>
00037 
00038 #ifdef WIN32
00039 #include <algorithm>
00040 #include <functional>
00041 #include <new>
00042 #endif
00043 
00044 using namespace std;
00045 
00046 // RFB :  If running multiple threads in a cpp application,
00047 // the Application class is the only internal object
00048 // that is single instance with static data.  Synchronize access to those data
00049 // structures.
00050 // Using macros to avoid polluting code with alot of ifdef's
00051 
00052 #ifdef THREAD_SAFE_CANTERA
00053 
00054 #include <boost/shared_ptr.hpp>
00055 #include <boost/thread/mutex.hpp>
00056 static boost::mutex  dir_mutex;  // For input directory access
00057 static boost::mutex  msg_mutex;  // For access to string messages
00058 static boost::mutex  app_mutex;  // Application state including creating singleton
00059 //static boost::mutex  log_mutex;  // Logger pointer
00060 static boost::mutex  xml_mutex;  // XML file storage
00061 
00062 //! Macro for locking input directory access
00063 #define DIR_LOCK() boost::mutex::scoped_lock   d_lock(dir_mutex)
00064 
00065 //! Macro for locking access to string messages
00066 #define MSG_LOCK() boost::mutex::scoped_lock   m_lock(msg_mutex)
00067 
00068 //! Macro for locking creating singletons in the application state
00069 #define APP_LOCK() boost::mutex::scoped_lock   a_lock(app_mutex)
00070 
00071 //! Macro for locking XML file writing
00072 #define XML_LOCK() boost::mutex::scoped_lock   x_lock(xml_mutex)
00073 
00074    #ifdef WITH_HTML_LOGS
00075       //static boost::mutex  html_mutex; // html logs
00076       //#define HTML_LOCK() boost::mutex::scoped_lock   h_lock(html_mutex)
00077    #endif
00078 
00079    #if defined(BOOST_HAS_WINTHREADS)
00080       #include <windows.h>
00081       typedef unsigned int cthreadId_t ;
00082       class thread_equal 
00083       {
00084       public:
00085          bool operator()(cthreadId_t L, cthreadId_t R)
00086          {
00087             return L == R ;
00088          }
00089       } ;
00090       cthreadId_t getThisThreadId()
00091       {
00092          return ::GetCurrentThreadId() ;
00093       }
00094    #elif defined(BOOST_HAS_PTHREADS)
00095 
00096       typedef pthread_t cthreadId_t ;
00097       class thread_equal 
00098       {
00099       public:
00100          bool operator()(cthreadId_t L, cthreadId_t R)
00101          {
00102             return pthread_equal(L, R) ;
00103          }
00104       } ;
00105       cthreadId_t getThisThreadId()
00106       {
00107          return pthread_self() ;
00108       }
00109    #elif defined(BOOST_HAS_MPTASKS)
00110       typedef MPTaskID  cthreadId_t ;
00111       class thread_equal 
00112       {
00113       public:
00114          bool operator()(cthreadId_t L, cthreadId_t R)
00115          {
00116             return L == R ;
00117          }
00118       } ;
00119       cthreadId_t getThisThreadId()
00120       {
00121          return MPCurrentTaskID() ;
00122       }
00123    #endif
00124 
00125 #else
00126    #define DIR_LOCK() 
00127    #define MSG_LOCK() 
00128    #define APP_LOCK() 
00129    //#define LOG_LOCK() 
00130    #define XML_LOCK() 
00131 
00132    #ifdef WITH_HTML_LOGS
00133       //#define HTML_LOCK() 
00134    #endif
00135 
00136 #endif
00137 
00138 namespace Cantera {
00139 
00140   /*!
00141    * @defgroup globalData Global Data
00142    *
00143    * Global data are available anywhere. There are two kinds.
00144    * Cantera has an assortment of constant values for physical parameters.
00145    * Also, Cantera maintains a collection of global data which is specific
00146    * to each process that invokes Cantera functions. This process-specific
00147    * data is storred in the class Application.
00148    */
00149   //@{
00150   //@}
00151     
00152   //!  Class to hold global data. 
00153   /*!
00154    * Class Application is the top-level
00155    * class that stores data that should persist for the duration of
00156    * the process. The class should not be instantiated directly;
00157    * instead, it is instantiated as needed by the functions declared
00158    * here. At most one instance is created, and it is not destroyed
00159    * until the process terminates.
00160    *
00161    * @ingroup HTML_logs
00162    * @ingroup textlogs
00163    * @ingroup globalData
00164    */
00165   class Application {
00166 
00167   protected:
00168     //! Class to carry out messages
00169     /*!
00170      * @ingroup HTML_logs
00171      */
00172     class Messages {
00173     public:
00174       //! Constructor for the Messages class
00175       /*!
00176        * constructor for the Messages class which is a subclass
00177        * of the Application class.
00178        */
00179       Messages() {
00180         // install a default logwriter that writes to standard
00181         // output / standard error
00182         logwriter = new Logger();
00183 #ifdef WITH_HTML_LOGS
00184         xmllog = 0; 
00185         current = 0;
00186         loglevel = 0;
00187 #endif
00188       }
00189 
00190       //! Destructor for the Messages class
00191       ~Messages() {
00192         delete logwriter;
00193 #ifdef WITH_HTML_LOGS
00194         if (xmllog) {
00195           write_logfile("orphan");
00196         }
00197 #endif
00198       }
00199       
00200       //! Set an error condition in the application class without 
00201       //! throwing an exception.
00202       /*!
00203        * This routine adds an error message to the end of the stack
00204        * of errors that Cantera accumulates in the Application
00205        * class.
00206        * @param r   location
00207        * @param msg  Description of the error
00208        * @ingroup errorhandling
00209        */
00210       void addError(std::string r, std::string msg) ;
00211     
00212       //! Return the number of errors that have been encountered so far.
00213       /*!
00214        * @ingroup errorhandling
00215        */
00216       int getErrorCount() ;
00217 
00218       //! Discard the last error message
00219       /*!
00220        * %Cantera saves a stack of exceptions that it
00221        * has caught in the Application class. This routine eliminates
00222        * the last exception to be added to that stack.
00223        *
00224        * @ingroup errorhandling
00225        */
00226       void popError() ;
00227    
00228       //! Retrieve the last error message in a string
00229       /*!
00230        * This routine will retrieve the last error message and return
00231        * it in the return string.
00232        *
00233        * @ingroup errorhandling
00234        */
00235       std::string lastErrorMessage() ;
00236 
00237       //!  Prints all of the error messages to an ostream
00238       /*!
00239        * Print all of the error messages using function writelog.
00240        * Write out all of the saved error messages to the ostream f
00241        * Cantera saves a stack of exceptions that it
00242        * has caught in the Application class. This routine writes
00243        * out all of the error messages to the ostream
00244        * and then clears them from internal storage.
00245        *
00246        * @param f ostream which will receive the error messages
00247        *
00248        * @ingroup errorhandling
00249        */
00250       void getErrors(std::ostream& f) ;
00251 
00252       //!  Prints all of the error messages using writelog
00253       /*!
00254        * Print all of the error messages using function writelog.
00255        * Cantera saves a stack of exceptions that it
00256        * has caught in the Application class. This routine writes
00257        * out all of the error messages
00258        * and then clears them from internal storage.
00259        *
00260        * @ingroup errorhandling
00261        */
00262       void logErrors();
00263       
00264       //!  Write a message to the screen.
00265       /*!
00266        * The string may be of any
00267        * length, and may contain end-of-line characters. This method is
00268        * used throughout %Cantera to write log messages.
00269        *
00270        * @param msg  c++ string to be written to the screen
00271        * @ingroup textlogs
00272        */
00273       void writelog(const std::string& msg);
00274 
00275       //! Write an end of line and flush output
00276       void writelogendl();
00277 
00278       //!  Write a message to the screen.
00279       /*!
00280        * The string may be of any
00281        * length, and may contain end-of-line characters. This method is
00282        * used throughout %Cantera to write log messages.
00283        *
00284        * @param pszmsg  c character string to be written to the screen
00285        * @ingroup textlogs
00286        */
00287       void writelog(const char* pszmsg) ;
00288 
00289       //! Write an error message and quit.
00290       /*!
00291        *  The default behavior is
00292        *  to write to the standard eror stream, and then call
00293        *  exit(). Note that no end-of-line character is appended to
00294        *  the message, and so if one is desired it must be included
00295        *  in the string. Note that this default behavior will
00296        *  terminate the application Cantera is invoked from (MATLAB,
00297        *  Excel, etc.) If this is not desired, then derive a class
00298        *  and reimplement this method.
00299        *
00300        * @param msg    Error message to be written to cerr.
00301        */
00302       void logerror(const std::string& msg) ;
00303 
00304       //! Returns an integer specifying the application environment
00305       int getUserEnv() ;
00306 
00307       //! Install a logger.
00308       /*!
00309        *  Called by the language interfaces to install an appropriate logger.
00310        *  The logger is used for the writelog() function
00311        *
00312        * @param logwriter Pointer to a logger object
00313        * @see Logger.
00314        * @ingroup textlogs
00315        */
00316       void setLogger(Logger* logwriter) ;
00317       
00318 #ifdef WITH_HTML_LOGS
00319 
00320       //!Create a new group for log messages.
00321       /*!
00322        *  Usually this is called
00323        *  upon entering the function, with the title parameter equal to
00324        *  the name of the function or method. Subsequent messages
00325        *  written with addLogEntry will appear grouped under this
00326        *  heading, until endLogGroup() is called.
00327        *
00328        *  @param title String name of the LogGroup
00329        *  @param loglevel loglevel of the group.
00330        *  @ingroup HTML_logs
00331        */
00332       void beginLogGroup(std::string title, int loglevel) ;
00333 
00334       //! Add an entry to an HTML log file.
00335       /*!
00336        *  Entries appear in the form "tag:value".
00337        *
00338        * @param tag      tag
00339        * @param value    double value
00340        *
00341        * @ingroup HTML_logs
00342        */
00343       void addLogEntry(std::string tag, std::string value) ;
00344 
00345       //! Add an entry to an HTML log file.
00346       /*!
00347        *  Entries appear in the form "tag:value".
00348        *
00349        * @param tag      tag
00350        * @param value    double value
00351        *
00352        * @ingroup HTML_logs
00353        */
00354       void addLogEntry(std::string tag, doublereal value) ;
00355 
00356       //! Add an entry to an HTML log file.
00357       /*!
00358        *  Entries appear in the form "tag:value".
00359        *
00360        * @param tag      tag
00361        * @param value    double value
00362        *
00363        * @ingroup HTML_logs
00364        */
00365       void addLogEntry(std::string tag, int value) ;
00366 
00367       //! Add an entry to an HTML log file.
00368       /*!
00369        *  Entries appear in the form "msg".
00370        *
00371        * @param msg  Message to be added
00372        *
00373        * @ingroup HTML_logs
00374        */
00375       void addLogEntry(std::string msg) ;
00376 
00377       //! Close the current group of log messages.
00378       /*!
00379        *  This is typically
00380        *  called just before leaving a function or method, to close the
00381        *  group of messages that were output from this
00382        *  function. Subsequent messages written with addLogEntry() will
00383        *  appear at the next-higher level in the outline, unless
00384        *  beginLogGroup() is called first to create a new group.
00385        *
00386        * @param title Name of the log group. It defaults to the most recent
00387        *              log group created.
00388        */
00389       void endLogGroup(std::string title) ;
00390 
00391       //! Write the HTML log file.
00392       /*!
00393        *  Log entries are stored in memory in
00394        *  an XML tree until this function is called, which writes the
00395        *  tree to a file and clears the entries stored in memory.  The
00396        *  output file will have the name specified in the 'file'
00397        *  argument.  If this argument has no extension, the extension
00398        *  '.html' will be appended. Also, if the file already exists, an
00399        *  integer will be appended to the name so that no existing log
00400        *  file will be overwritten.
00401        *  WITH_HTML_LOGS must be defined.
00402        *
00403        *  @param  file Name of the file to be written
00404        */
00405       void write_logfile(std::string file);
00406 #endif
00407       
00408     protected:
00409       //! Current list of error messages 
00410       vector<string> errorMessage;
00411      
00412       //! Current error Routine
00413       vector<string> errorRoutine;
00414    
00415       //! Current pointer to the logwriter
00416       Logger* logwriter;
00417 #ifdef WITH_HTML_LOGS
00418       //! Current pointer to the top of the XML_Node tree for the current HTML log
00419       XML_Node *xmllog;
00420 
00421       //! Pointer to the last current position in the XML_Node tree for the current HTML log
00422       XML_Node *current;
00423 
00424       //! Current value of the loglevel
00425       int loglevel;
00426 
00427       //! Vector of loglevels for loggroups that are open
00428       vector<int> loglevels;
00429 
00430       //! Current vector of loggroups that are open
00431       vector<string> loggroups;
00432 #endif
00433     } ;
00434     
00435 #ifdef THREAD_SAFE_CANTERA
00436       //! Typedef for thread specific messages
00437       typedef boost::shared_ptr< Messages >   pMessages_t ;
00438 
00439       //! Typedef for map between a thread and the message
00440       typedef std::map< cthreadId_t, pMessages_t > threadMsgMap_t ;
00441 
00442       //! Class that stores thread messages for each thread, and retrieves them
00443       //! based on the thread id.
00444       class ThreadMessages
00445       {
00446       public:
00447         //! Constructor
00448         ThreadMessages()
00449         {
00450         }
00451         
00452         //! Provide a pointer deferencing overloaded operator
00453         /*!
00454          * @return  returns a pointer to Messages
00455          */
00456         Messages* operator->()
00457         {
00458           MSG_LOCK() ;
00459           cthreadId_t curId = getThisThreadId() ;
00460           threadMsgMap_t::iterator iter = m_threadMsgMap.find( curId ) ;
00461           if ( iter != m_threadMsgMap.end() )
00462             {
00463               return (iter->second.get()) ;
00464             }
00465           pMessages_t pMsgs( new Messages() ) ;
00466           m_threadMsgMap.insert( std::pair< cthreadId_t, pMessages_t >( curId, pMsgs ) ) ;
00467           return pMsgs.get() ;
00468         }
00469 
00470         //! Remove a local thread message
00471         void removeThreadMessages() {
00472           MSG_LOCK() ;
00473           cthreadId_t curId = getThisThreadId() ;
00474           threadMsgMap_t::iterator iter = m_threadMsgMap.find( curId ) ;
00475           if ( iter != m_threadMsgMap.end() ) {
00476             m_threadMsgMap.erase( iter ) ;
00477           }
00478         }
00479 
00480       private:
00481         //! Thread Msg Map
00482          threadMsgMap_t   m_threadMsgMap ;
00483       } ;
00484     #endif
00485 
00486 
00487   protected:   //RFB Protected ctor access thru static member function Instance
00488     //! Constructor for class sets up the initial conditions
00489     Application() : /*linelen(0),*/ stop_on_error(false),
00490                                     tmp_dir("."), m_sleep("1")              
00491     {
00492 #if !defined( THREAD_SAFE_CANTERA )
00493      pMessenger = std::auto_ptr<Messages>(new Messages());
00494 #endif
00495       // if TMP or TEMP is set, use it for the temporary
00496       // directory
00497       char* ctmpdir = getenv("CANTERA_TMPDIR");
00498       if (ctmpdir != 0) {
00499         tmp_dir = string(ctmpdir);
00500       } else {
00501         char* tmpdir = getenv("TMP");
00502         if (tmpdir == 0) 
00503           tmpdir = getenv("TEMP");
00504         if (tmpdir != 0)
00505           tmp_dir = string(tmpdir);
00506       }
00507 
00508       // if SLEEP is set, use it as the sleep time
00509       char* sleepstr = getenv("SLEEP");
00510       if (sleepstr != 0) {
00511         m_sleep = string(sleepstr);
00512       }
00513 
00514       // install a default logwriter that writes to standard
00515       // output / standard error
00516       //      logwriter = new Logger();
00517       //#ifdef WITH_HTML_LOGS
00518       //      // HTML log files
00519       //      xmllog = 0; 
00520       //      current = 0;
00521       //      loglevel = 0;
00522       //#endif
00523       setDefaultDirectories();
00524 #if defined(THREAD_SAFE_CANTERA)
00525       Unit::units() ;
00526 #endif
00527     }
00528 
00529   public:
00530     //! Return a pointer to the one and only instance of class Application
00531     /*
00532      * If the an Application object has not yet been created it is created
00533      */
00534     static Application* Instance() {
00535       APP_LOCK();
00536       if (Application::s_app == 0) {
00537         Application::s_app = new Application();
00538       }
00539       return s_app;
00540     }
00541     
00542     //! Destructor for class deletes global data
00543     /*!
00544      * Delete any open XML trees, the logwriter, and
00545      * the XML log, if any.
00546      */
00547     virtual ~Application() {
00548       std::map<std::string, XML_Node*>::iterator pos;
00549       for (pos = xmlfiles.begin(); pos != xmlfiles.end(); ++pos) {
00550         pos->second->unlock();
00551         delete pos->second;
00552         pos->second = 0;
00553       }
00554     }
00555 
00556     //! Static function that destroys the application class's data
00557     static void ApplicationDestroy() {
00558        APP_LOCK() ;
00559        if (Application::s_app != 0) {
00560          delete Application::s_app;
00561          Application::s_app = 0;
00562        }
00563     }
00564 
00565     //! Set the directory where temporary files may be written.
00566     /*!
00567      * @param tmp Name of the directory
00568      */
00569     void setTmpDir(std::string tmp) ;
00570 
00571     //! get the name of a directory where temporary files may be written.
00572     std::string getTmpDir() ;
00573 
00574     //! Pause the application for a certain amount
00575     /*!
00576      * This has been needed in the past for some network file systems.
00577      */
00578     std::string sleep() ;
00579 
00580     //! Set an error condition in the application class without 
00581     //! throwing an exception.
00582     /*!
00583      * This routine adds an error message to the end of the stack
00584      * of errors that Cantera accumulates in the Application
00585      * class.
00586      * @param r   location
00587      * @param msg  Description of the error
00588      * @ingroup errorhandling
00589      */
00590     void addError(std::string r, std::string msg) { pMessenger->addError(r, msg) ; }
00591 
00592     //! Return the number of errors that have been encountered so far.
00593     /*!
00594      * @ingroup error handling
00595      */
00596     int getErrorCount() { return pMessenger->getErrorCount() ; }
00597 
00598     //! Discard the last error message
00599     /*!
00600      * %Cantera saves a stack of exceptions that it
00601      * has caught in the Application class. This routine eliminates
00602      * the last exception to be added to that stack.
00603      *
00604      * @ingroup errorhandling
00605      */
00606     void popError() { pMessenger->popError() ; }
00607 
00608     //! Retrieve the last error message in a string
00609     /*!
00610      * This routine will retrieve the last error message and return
00611      * it in the return string.
00612      *
00613      * @ingroup errorhandling
00614      */
00615     std::string lastErrorMessage() { return pMessenger->lastErrorMessage() ; }
00616 
00617     //!  Prints all of the error messages to an ostream
00618     /*!
00619      * Print all of the error messages using function writelog.
00620      * Write out all of the saved error messages to the ostream f
00621      * Cantera saves a stack of exceptions that it
00622      * has caught in the Application class. This routine writes
00623      * out all of the error messages to the ostream
00624      * and then clears them from internal storage.
00625      *
00626      * @param f ostream which will receive the error messages
00627      *
00628      * @ingroup errorhandling
00629      */
00630     void getErrors( std::ostream& f) { pMessenger->getErrors(f) ; }
00631 
00632     //!  Prints all of the error messages using writelog
00633     /*!
00634      * Print all of the error messages using function writelog.
00635      * Cantera saves a stack of exceptions that it
00636      * has caught in the Application class. This routine writes
00637      * out all of the error messages
00638      * and then clears them from internal storage.
00639      *
00640      * @ingroup errorhandling
00641      */
00642     void logErrors() { pMessenger->logErrors() ; }
00643 
00644     //!  Add a directory to the data file search path.
00645     /*!
00646      * @ingroup inputfiles
00647      *
00648      * @param dir  String name for the directory to be added to the search path
00649      */
00650     void addDataDirectory( std::string dir ) ;
00651     
00652     //! Find an input file.
00653     /*!
00654      *    This routine will search for a file in the default
00655      *    locations specified for the application.
00656      *    See the routine setDefaultDirectories() listed above.
00657      *
00658      *    The default set of directories specified for the application
00659      *    will be searched if a '/' or an '\\' is found in the
00660      *    name. If either is found then a relative path name is
00661      *    presumed, and the default directories are not searched.
00662      *
00663      *    The presence of the file is determined by whether the file
00664      *    can be opened for reading by the current user.
00665      *
00666      *  @param name Name of the input file to be searched for
00667      *
00668      *    @return
00669      *    
00670      *      The absolute path name of the first matching
00671      *      file is returned. If a relative path name
00672      *      is indicated, the relative path name is returned.
00673      *  
00674      *      If the file is not found, a message is written to 
00675      *      stdout and  a CanteraError exception is thrown.
00676      *
00677      * @ingroup inputfiles
00678      */
00679     std::string findInputFile(std::string name) ;
00680 
00681     //! Return a pointer to the XML tree for a Cantera input file. 
00682     /*!
00683      *  This routine will find the file and read the XML file into an
00684      *  XML tree structure. Then, a pointer will be returned. If the
00685      *  file has already been processed, then just the pointer will
00686      *  be returned.
00687      * 
00688      * @param file String containing the relative or absolute file name
00689      * @param debug Debug flag
00690      */
00691     XML_Node* get_XML_File(std::string file, int debug=0) ;
00692 
00693     //! Close an XML File 
00694     /*!
00695      * Close a file that is opened by this application object
00696      *
00697      * @param file String containing the relative or absolute file name
00698      */
00699     void close_XML_File(std::string file) ;
00700 
00701     //!  Write a message to the screen.
00702     /*!
00703      * The string may be of any
00704      * length, and may contain end-of-line characters. This method is
00705      * used throughout %Cantera to write log messages.
00706      *
00707      * @param msg  c++ string to be written to the screen
00708      * @ingroup textlogs
00709      */
00710     void writelog(const std::string& msg) { pMessenger->writelog(msg); }
00711 
00712 
00713     //! Write an endl to the screen and flush output
00714     /*!
00715      * @ingroup textlogs
00716      */
00717     void writelogendl() { pMessenger->writelogendl(); }
00718 
00719     //!  Write a message to the screen.
00720     /*!
00721      * The string may be of any
00722      * length, and may contain end-of-line characters. This method is
00723      * used throughout %Cantera to write log messages.
00724      *
00725      * @param pszmsg  c null terminated string to be written to the screen
00726      * @ingroup textlogs
00727      */
00728     void writelog(const char* pszmsg) { pMessenger->writelog(pszmsg); }
00729 
00730     //! Write an error message and quit.
00731     /*!
00732      *  The default behavior is
00733      *  to write to the standard eror stream, and then call
00734      *  exit(). Note that no end-of-line character is appended to
00735      *  the message, and so if one is desired it must be included
00736      *  in the string. Note that this default behavior will
00737      *  terminate the application Cantera is invoked from (MATLAB,
00738      *  Excel, etc.) If this is not desired, then derive a class
00739      *  and reimplement this method.
00740      *
00741      * @param msg    Error message to be written to cerr.
00742      */
00743     void logerror(const std::string& msg) {pMessenger->logerror(msg); }
00744 
00745     //! Returns an integer specifying the application environment.
00746     int getUserEnv() { return pMessenger->getUserEnv() ; }
00747 
00748     //!  Install a logger -  Called by the language interfaces to install an
00749     //!  appropriate logger. 
00750     /*!
00751      * @param logwriter Pointer to a logger object
00752      *  @see Logger.
00753      *  @ingroup textlogs
00754      */
00755     void setLogger(Logger* logwriter) {pMessenger->setLogger(logwriter);}
00756    
00757     //! Delete Messenger object allocated per thread.
00758     void thread_complete() ;
00759 
00760 #ifdef WITH_HTML_LOGS
00761     //!Create a new group for log messages.
00762     /*!
00763      *  Usually this is called
00764      *  upon entering the function, with the title parameter equal to
00765      *  the name of the function or method. Subsequent messages
00766      *  written with addLogEntry will appear grouped under this
00767      *  heading, until endLogGroup() is called.
00768      *
00769      *  @param title String name of the LogGroup
00770      *  @param loglevel loglevel of the group.
00771      *  @ingroup HTML_logs
00772      */ 
00773     void beginLogGroup(std::string title, int loglevel) { pMessenger->beginLogGroup(title,loglevel);} 
00774 
00775     //! Add an entry to an HTML log file.
00776     /*!
00777      *  Entries appear in the form "tag:value".
00778      *
00779      * @param tag      tag
00780      * @param value    double value
00781      *
00782      * @ingroup HTML_logs
00783      */
00784     void addLogEntry(std::string tag, std::string value) { pMessenger->addLogEntry(tag, value);}
00785 
00786     //! Add an entry to an HTML log file.
00787     /*!
00788      *  Entries appear in the form "tag:value".
00789      *
00790      * @param tag      tag
00791      * @param value    double value
00792      *
00793      * @ingroup HTML_logs
00794      */
00795     void addLogEntry(std::string tag, doublereal value) { pMessenger->addLogEntry(tag, value);}
00796 
00797     //! Add an entry to an HTML log file.
00798     /*!
00799      *  Entries appear in the form "tag:value".
00800      *
00801      * @param tag      tag
00802      * @param value    double value
00803      *
00804      * @ingroup HTML_logs
00805      */
00806     void addLogEntry(std::string tag, int value) { pMessenger->addLogEntry(tag, value);}
00807 
00808     //! Add an entry to an HTML log file.
00809     /*!
00810      *  Entries appear in the form "msg".
00811      *
00812      * @param msg      Message to be added to file
00813      *
00814      * @ingroup HTML_logs
00815      */
00816     void addLogEntry(std::string msg) { pMessenger->addLogEntry(msg); }
00817 
00818     //! Close the current group of log messages.
00819     /*!
00820      *  This is typically
00821      *  called just before leaving a function or method, to close the
00822      *  group of messages that were output from this
00823      *  function. Subsequent messages written with addLogEntry() will
00824      *  appear at the next-higher level in the outline, unless
00825      *  beginLogGroup() is called first to create a new group.
00826      *
00827      * @param title Name of the log group. It defaults to the most recent
00828      *              log group created.
00829      * @ingroup HTML_logs
00830      */
00831     void endLogGroup(std::string title) { pMessenger->endLogGroup(title) ;}
00832 
00833     //! Write the HTML log file.
00834     /*!
00835      *  Log entries are stored in memory in
00836      *  an XML tree until this function is called, which writes the
00837      *  tree to a file and clears the entries stored in memory.  The
00838      *  output file will have the name specified in the 'file'
00839      *  argument.  If this argument has no extension, the extension
00840      *  '.html' will be appended. Also, if the file already exists, an
00841      *  integer will be appended to the name so that no existing log
00842      *  file will be overwritten.
00843      *  WITH_HTML_LOGS must be defined.
00844      *
00845      *  @param  file Name of the file to be written
00846      */
00847     void write_logfile(std::string file) { pMessenger->write_logfile(file) ; }
00848 #endif
00849 
00850 protected:
00851     void setDefaultDirectories();
00852 
00853     //! Current vector of input directories to search for input files
00854     vector<string> inputDirs;
00855     //! Current list of error messages 
00856     //vector<string> errorMessage;
00857     //! Current list of warning messages
00858     //vector<string> warning;
00859     //! Current error Routine
00860     //vector<string> errorRoutine;
00861     //! Last error message
00862     //string msglog;
00863     //! Current line length
00864    // size_t linelen;
00865     //! Current value of stop_on_error
00866     bool stop_on_error;
00867     //! Current map of options
00868     map<string, string>     options;
00869     //! Current value of tmp_dir
00870     string tmp_dir;
00871     //! Current vector of xml file trees that have been previously parsed
00872     map<string, XML_Node*> xmlfiles;
00873     //! Current sleep command.
00874     string m_sleep;
00875     //! Current pointer to the logwriter
00876     //Logger* logwriter;
00877  #ifdef WITH_HTML_LOGS
00878     //! Current pointer to the top of the XML_Node tree for the current HTML log
00879     //XML_Node *xmllog;
00880     //! Pointer to the last current position in the XML_Node tree for the current HTML log
00881     //XML_Node *current;
00882     //! Current value of loglevel
00883     //int loglevel;
00884     //! Vector of loglevels for loggroups that are open
00885     //vector<int> loglevels;
00886     //! Current vector of loggroups that are open
00887     //vector<string> loggroups;
00888  #endif
00889 
00890 #if defined(THREAD_SAFE_CANTERA)
00891       ThreadMessages   pMessenger ;
00892 #else
00893       auto_ptr< Messages >   pMessenger ;
00894 #endif
00895     
00896   private:
00897      static Application* s_app ;
00898   };
00899             
00900   //! Return a pointer to the application object
00901   inline Application* app() {
00902     return Application::Instance() ;
00903   }
00904 
00905 
00906   /// Pointer to the single Application instance
00907   Application* Application::s_app = 0;
00908 
00909     /**
00910      * Definition of the static member of the Unit class.
00911      */
00912     Unit* Unit::s_u = 0;
00913       #if defined(THREAD_SAFE_CANTERA)
00914         boost::mutex Unit::units_mutex ;
00915       #endif
00916 
00917 
00918     /*
00919      * Delete all global data.  It should be called at the end of the
00920      * application if leak checking is to be done.
00921      */
00922     void appdelete() {
00923         Application::ApplicationDestroy() ;
00924         FactoryBase::deleteFactories();
00925         Unit::deleteUnit();
00926     }
00927 
00928     /*
00929      * Delete Messenger object allocated per thread.
00930      */
00931     void thread_complete() {
00932        app()->thread_complete() ;
00933     }
00934   
00935     void Application::thread_complete() {
00936 #if defined(THREAD_SAFE_CANTERA)
00937          pMessenger.removeThreadMessages() ;
00938 #endif
00939     }
00940 
00941     XML_Node* get_XML_File(std::string file, int debug) {
00942        XML_Node* xtmp = app()->get_XML_File(file, debug) ;
00943        //writelog("get_XML_File: returned from app:get_XML_FILE " + int2str(int(xtmp)) + "\n");
00944        return xtmp;
00945     }
00946 
00947     XML_Node* Application::get_XML_File(std::string file, int debug) {
00948         XML_LOCK();
00949                 std::string path = "";
00950         /*
00951         try {
00952             path = findInputFile(file);
00953         }
00954         catch (CanteraError) {
00955             string::size_type idot = file.rfind('.');
00956             string ext = "";
00957             if (idot != string::npos) {
00958                 ext = file.substr(idot, file.size());
00959                 string ctifile = file.substr(0,idot)+".cti";
00960                 try {
00961                     path = findInputFile(ctifile);
00962                 }
00963                 catch (CanteraError) {
00964                     path = findInputFile(file);
00965                 }
00966             }
00967             else
00968                 path = findInputFile(file);
00969         }
00970         */
00971         // The code above will try to process a cti file if the xml
00972         // file is not found. But I (dgg) don't think it makes much sense,
00973         // so it is replaced by:
00974         path = findInputFile(file);
00975         // 
00976 #ifdef WIN32
00977         // RFB: For Windows make the path POSIX compliant so code looking for directory 
00978         // separators is simpler.  Just look for '/' not both '/' and '\\'
00979         replace_if( path.begin(), path.end(), bind2nd( equal_to<char>(), '\\'), '/' ) ; 
00980 #endif
00981 
00982         string ff = path;
00983         if (xmlfiles.find(path) 
00984             == xmlfiles.end()) {
00985             /*
00986              * Check whether or not the file is XML. If not, it will
00987              * be first processed with the preprocessor. We determine
00988              * whether it is an XML file by looking at the file extension.
00989              */
00990             string::size_type idot = path.rfind('.');
00991             string ext;
00992             if (idot != string::npos) {
00993                 ext = path.substr(idot, path.size());
00994             } else {
00995                 ext = "";
00996                 idot = path.size();
00997             }
00998             if (ext != ".xml" && ext != ".ctml") {
00999                 /*
01000                  * We will assume that we are trying to open a cti file.
01001                  * First, determine the name of the xml file, ff, derived from
01002                  * the cti file.
01003                  * In all cases, we will write the xml file to the current
01004                  * directory.
01005                  */
01006                 string::size_type islash = path.rfind('/');
01007                 if (islash != string::npos) 
01008                     ff = string("./")+path.substr(islash+1,idot-islash - 1) + ".xml";
01009                 else {
01010                     ff = string("./")+path.substr(0,idot) + ".xml";
01011                 }
01012 #ifdef DEBUG_PATHS
01013                 cout << "get_XML_File(): Expected location of xml file = "
01014                      << ff << endl;
01015 #endif
01016                 /*
01017                  * Do a search of the existing XML trees to determine if we have
01018                  * already processed this file. If we have, return a pointer to
01019                  * the processed xml tree.
01020                  */
01021                 if (xmlfiles.find(ff) != xmlfiles.end()) {
01022 #ifdef DEBUG_PATHS
01023                     cout << "get_XML_File(): File, " << ff << ", was previously read."
01024                          << " Retrieving the storred xml tree." << endl;
01025 #endif
01026                     return xmlfiles[ff];      
01027                 }
01028                 /*
01029                  * Ok, we didn't find the processed XML tree. Do the conversion
01030                  * to xml, possibly overwriting the file, ff, in the process.
01031                  */
01032                 ctml::ct2ctml(path.c_str(),debug);
01033             }
01034             else {
01035                 ff = path;
01036             }
01037             /*
01038              * Take the XML file ff, open it, and process it, creating an
01039              * XML tree, and then adding an entry in the map. We will store
01040              * the absolute pathname as the key for this map.
01041              */
01042             ifstream s(ff.c_str());
01043 
01044             XML_Node* x = new XML_Node("doc");
01045             if (s) {
01046                 x->build(s);
01047                 x->lock();
01048                 xmlfiles[ff] = x;
01049             }
01050             else {
01051                 string estring = "cannot open "+ff+" for reading.";
01052                 estring += "Note, this error indicates a possible configuration problem."; 
01053                 throw CanteraError("get_XML_File", estring);
01054             }
01055         }
01056 
01057         /*
01058          * Return the XML node pointer. At this point, we are sure that the
01059          * lookup operation in the return statement will return a valid
01060          * pointer. 
01061          */
01062         return xmlfiles[ff];
01063     }
01064 
01065   // Close an XML File 
01066   /*
01067    * Close a file that is openned by the application object
01068    *
01069    * @param file string name of the file
01070    */
01071   void close_XML_File(std::string file) {
01072     app()->close_XML_File(file) ;
01073   }
01074 
01075   void Application::close_XML_File(std::string file) {
01076     XML_LOCK();
01077     if (file == "all") {
01078       map<string, XML_Node*>::iterator 
01079         b = xmlfiles.begin(), 
01080         e = xmlfiles.end();
01081       for(; b != e; ++b) {
01082         b->second->unlock();
01083         delete b->second;
01084         xmlfiles.erase(b->first);
01085       }
01086     }
01087     else if (xmlfiles.find(file) != xmlfiles.end()) {
01088       xmlfiles[file]->unlock();
01089       delete xmlfiles[file];
01090       xmlfiles.erase(file);
01091     }
01092   }
01093 
01094     void setTmpDir(std::string tmp) { app()->setTmpDir(tmp); }
01095     void Application::setTmpDir(std::string tmp) {
01096        APP_LOCK();
01097        tmp_dir = tmp ;
01098     }
01099     
01100     string tmpDir() { return app()->getTmpDir(); }
01101     std::string Application::getTmpDir() {
01102        APP_LOCK();
01103        return tmp_dir ;
01104     }
01105     
01106     string sleep() { return app()->sleep(); }
01107     std::string Application::sleep() {
01108        APP_LOCK();
01109        return m_sleep ;
01110     }
01111 
01112 
01113   /*
01114    * Return the number of errors that have been encountered so far.
01115    * \ingroup errorhandling
01116    */
01117   int nErrors() {
01118     return app()->getErrorCount();
01119   }
01120   
01121   // Return the number of errors encountered so far
01122   int Application::Messages::getErrorCount() {
01123     return static_cast<int>(errorMessage.size()) ;
01124   }
01125 
01126   /*
01127    * popError eliminates the last error message that Cantera
01128    * has saved. Cantera saves a stack of exceptions that it
01129    * has caught in the Application class. This routine eliminates
01130    * the last exception to be added to that stack.
01131    * \ingroup errorhandling
01132    */
01133   void popError() {
01134     app()->popError() ;
01135   }
01136 
01137   // Eliminate the last error message
01138   void Application::Messages::popError() {
01139     if ( static_cast<int>(errorMessage.size()) > 0) {
01140       errorRoutine.pop_back() ;
01141       errorMessage.pop_back() ;
01142     }
01143   }
01144 
01145   /*
01146    * Retrieve the last error message.
01147    * This routine will retrieve the last error message and return
01148    * it in the return string.
01149    * \ingroup errorhandling
01150    */
01151   string lastErrorMessage() {
01152     return app()->lastErrorMessage() ;
01153   }
01154 
01155   // Retrieve the last error message
01156   std::string Application::Messages::lastErrorMessage() {
01157     if ( static_cast<int>(errorMessage.size()) > 0) {
01158       string head = 
01159         "\n\n************************************************\n"
01160         "                Cantera Error!                  \n"
01161                 "************************************************\n\n";
01162       return head+string("\nProcedure: ")+errorRoutine.back()
01163                 +string("\nError:   ")+errorMessage.back();
01164     } else  {
01165       return "<no Cantera error>";
01166     }
01167   }
01168 
01169     /*
01170      * Prints all of the error messages to stream f.
01171      * Write out to ostream, f, all of the saved error messages.
01172      * Cantera saves a stack of exceptions that it
01173      * has caught in the Application class. This routine writes
01174      * out all of the error messages to ostream f, and then
01175      * clears them from internal storage.
01176      * \ingroup errorhandling
01177      */
01178     void showErrors(std::ostream& f) {
01179         app()->getErrors(f) ;
01180     }
01181 
01182   // Prints all error messages to stream f
01183   void Application::Messages::getErrors( std::ostream& f) {
01184     int i = static_cast<int>(errorMessage.size());
01185     if (i == 0) return;
01186     f << endl << endl;
01187     f << "************************************************" << endl;
01188     f << "                   Cantera Error!                  " << endl;
01189     f << "************************************************" << endl
01190       << endl;
01191     int j;
01192     for (j = 0; j < i; j++) {
01193       f << endl;
01194       f << "Procedure: " << errorRoutine[j] << endl;
01195       f << "Error:     " << errorMessage[j] << endl;
01196     } 
01197     f << endl << endl;
01198     errorMessage.clear();
01199     errorRoutine.clear();
01200   }
01201   
01202     /*
01203      * Print all of the error messages using function writelog.
01204      * Write out all of the saved error messages to the log device.
01205      * Cantera saves a stack of exceptions that it
01206      * has caught in the Application class. This routine writes
01207      * out all of the error messages to the log, usually stdout,
01208      *  and then clears them from internal storage.
01209      * \ingroup errorhandling
01210      */
01211     void showErrors() {
01212         app()->logErrors() ;
01213     }
01214 
01215   // Print out all of the error messages
01216   void Application::Messages::logErrors() {
01217     int i = static_cast<int>(errorMessage.size());
01218     if (i == 0) return;
01219     writelog("\n\n");
01220     writelog("************************************************\n");
01221     writelog("                   Cantera Error!                  \n");
01222     writelog("************************************************\n\n");
01223     int j;
01224     for (j = 0; j < i; j++) {
01225       writelog("\n");
01226             writelog(string("Procedure: ")+ errorRoutine[j]+" \n");
01227             writelog(string("Error:     ")+ errorMessage[j]+" \n");
01228     } 
01229     writelog("\n\n");
01230     errorMessage.clear();
01231     errorRoutine.clear();
01232   }
01233 
01234   /*
01235    * Set an error condition in the application class without 
01236    * throwing an exception.
01237    * This routine adds an error message to the end of the stack
01238    * of errors that Cantera accumulates in the Application
01239    * class.
01240    * \ingroup errorhandling
01241    */
01242   void setError(std::string r, std::string msg) {
01243     app()->addError(r, msg) ;
01244   }
01245 
01246   // Set an error condition in the application class without throwing an exception
01247   void Application::Messages::addError(std::string r, std::string msg) {
01248     errorMessage.push_back(msg);
01249     errorRoutine.push_back(r);
01250   }
01251   
01252    
01253     //! Set the default directories for input files.
01254     /*!
01255      * %Cantera searches
01256      * for input files along a path that includes platform-specific
01257      * default locations, and possibly user-specified locations.  This
01258      * function installs the platform-specific directories on the
01259      * search path. It is invoked at startup by appinit(), and never
01260      * should need to be called by user programs.
01261      *
01262      * The current directory (".") is always searched first. Then, on
01263      * Windows platforms, if environment variable COMMONPROGRAMFILES
01264      * is set (which it should be on Win XP or Win 2000), then
01265      * directories under this one will be added to the search
01266      * path. The %Cantera Windows installer installs data files to this
01267      * location.
01268      * 
01269      * On the Mac, directory '/Applications/Cantera/data' is added to the
01270      * search path. 
01271      * 
01272      * On any platform, if environment variable CANTERA_DATA is set to a 
01273      * directory name, then this directory is added to the search path. 
01274      *
01275      * Finally, the location where the data files were installed when
01276      * %Cantera was built is added to the search path.
01277      * 
01278      * Additional directories may be added by calling function addDirectory.
01279      * @ingroup inputfiles
01280      */
01281     void Application::setDefaultDirectories() {
01282         vector<string>& dirs = inputDirs;
01283 
01284         // always look in the local directory first
01285         dirs.push_back(".");
01286 
01287 
01288 #ifdef WIN32
01289         //
01290         // Under Windows, the Cantera setup utility puts data files in
01291         // a directory 'Cantera\data' below the one the environment
01292         // variable COMMONPROGRAMFILES points to. (This is usually
01293         // C:\Program Files\Common Files.) If this environment
01294         // variable is defined, then this directory is assumed to
01295         // exist and is added to the search path.
01296         //
01297         const char* comfiles = getenv("COMMONPROGRAMFILES");
01298         if (comfiles != 0) {
01299             string cfiles = string(comfiles);
01300 
01301             // remove quotes if necessary
01302             if (cfiles[0] == '\'') 
01303                 cfiles = cfiles.substr(1,1000);
01304             if (cfiles[cfiles.size()-1] == '\'') cfiles[cfiles.size()-1] = '\n';
01305 
01306             string datadir = string(comfiles) + "/Cantera/data";
01307             string tmpldir = string(comfiles) + "/Cantera/templates";
01308             dirs.push_back(datadir);
01309             dirs.push_back(tmpldir);
01310         }
01311 #endif
01312 
01313 #ifdef DARWIN
01314         //
01315         // add a default data location for Mac OS X
01316         //
01317         dirs.push_back("/Applications/Cantera/data");
01318 #endif
01319 
01320         //
01321         // if environment variable CANTERA_DATA is defined, then add
01322         // it to the search path
01323         //
01324         if (getenv("CANTERA_DATA") != 0) {
01325             string datadir = string(getenv("CANTERA_DATA"));
01326             dirs.push_back(datadir);
01327         }
01328 
01329         // CANTERA_DATA is defined in file config.h. This file is written
01330         // during the build process (unix), and points to the directory
01331         // specified by the 'prefix' option to 'configure', or else to
01332         // /usr/local/cantera. 
01333 #ifdef CANTERA_DATA
01334         string datadir = string(CANTERA_DATA);
01335         dirs.push_back(datadir);
01336 #endif
01337     }
01338 
01339 
01340   // Add a directory to the input file search path.
01341   // @ingroup inputfiles
01342   void addDirectory(std::string dir) {
01343     app()->addDataDirectory( dir ) ;
01344   }
01345   void Application::addDataDirectory( std::string dir ) {
01346     DIR_LOCK() ;
01347     if (inputDirs.size() == 0) setDefaultDirectories();
01348     string d = stripnonprint(dir);
01349     size_t m, n = inputDirs.size();
01350     
01351     // don't add if already present
01352     for (m = 0; m < n; m++) {
01353       if (d == inputDirs[m]) return;
01354     }
01355     
01356     inputDirs.push_back(d);
01357   }
01358   
01359   /*    
01360    *    This routine will search for a file in the default
01361    *    locations specified for the application.
01362    *    See the routine setDefaultDirectories() listed above.
01363    *
01364    *    The default set of directories specified for the application
01365    *    will be searched if a '/' or an '\\' is found in the
01366    *    name. If either is found then a relative path name is
01367    *    presumed, and the default directories are not searched.
01368    *
01369    *    The presence of the file is determined by whether the file
01370    *    can be opened for reading by the current user.
01371    *
01372    *    \return
01373    *    
01374    *      The absolute path name of the first matching
01375    *      file is returned. If a relative path name
01376    *      is indicated, the relative path name is returned.
01377    *  
01378    *      If the file is not found, a message is written to 
01379    *      stdout and  a CanteraError exception is thrown.
01380    */
01381   std::string findInputFile(std::string name) {
01382     return app()->findInputFile(name) ;
01383   }
01384   
01385   std::string Application::findInputFile(std::string name) {
01386     DIR_LOCK() ;
01387     string::size_type islash = name.find('/');
01388     string::size_type ibslash = name.find('\\');
01389     string inname;
01390     vector<string>& dirs = inputDirs;
01391  
01392     int nd;
01393     if (islash == string::npos && ibslash == string::npos) {
01394       nd = static_cast<int>(dirs.size());
01395       int i;
01396       inname = "";
01397       for (i = 0; i < nd; i++) {
01398         inname = dirs[i] + "/" + name;
01399         ifstream fin(inname.c_str());
01400         if (fin) {
01401           fin.close();
01402           return inname;
01403         }
01404       }
01405       string msg;
01406       msg = "\nInput file " + name 
01407         + " not found in director";
01408       msg += (nd == 1 ? "y " : "ies ");
01409       for (i = 0; i < nd; i++) {
01410         msg += "\n'" + dirs[i] + "'";
01411         if (i < nd-1) msg += ", ";
01412       }
01413       msg += "\n\n";
01414       msg += "To fix this problem, either:\n";
01415       msg += "    a) move the missing files into the local directory;\n";
01416       msg += "    b) define environment variable CANTERA_DATA to\n";
01417       msg += "         point to the directory containing the file.";
01418       throw CanteraError("findInputFile", msg);
01419     }
01420 
01421     return name;
01422   }
01423 
01424     doublereal toSI(std::string unit) {
01425         doublereal f = Unit::units()->toSI(unit);
01426         if (f) {
01427           return f;
01428         } else {
01429           throw CanteraError("toSI","unknown unit string: "+unit);
01430         }
01431         return 1.0;
01432     }
01433 
01434     doublereal actEnergyToSI(std::string unit) {
01435         doublereal f = Unit::units()->actEnergyToSI(unit);
01436         if (f) {
01437           return f;
01438         }
01439         return 1.0;
01440     }
01441 
01442     string canteraRoot() {
01443         char* ctroot = 0;
01444         ctroot = getenv("CANTERA_ROOT");
01445         if (ctroot != 0) { 
01446           return string(ctroot);
01447         } 
01448 #ifdef CANTERA_ROOT
01449         return string(CANTERA_ROOT);
01450 #else
01451         return "";
01452 #endif
01453         
01454     }
01455 
01456     // exceptions
01457 
01458     CanteraError::CanteraError(std::string proc, std::string msg) {
01459         app()->addError(proc, msg);
01460     }
01461     
01462     ArraySizeError::ArraySizeError(std::string proc, int sz, int reqd) :
01463         CanteraError(proc, "Array size ("+int2str(sz)+
01464             ") too small. Must be at least "+int2str(reqd)) {}
01465 
01466     ElementRangeError::ElementRangeError(std::string func, int m, int mmax) :
01467         CanteraError(func, "Element index " + int2str(m) + 
01468             " outside valid range of 0 to " + int2str(mmax-1)) {}
01469 
01470 
01471 
01472     ///////////////////////////////////////////////////////////
01473     //
01474     //  Warnings 
01475     //
01476     //////////////////////////////////////////////////////////
01477 
01478     // Print a warning when a deprecated method is called.
01479     // @param classnm Class the method belongs to
01480     // @param oldnm Name of the deprecated method
01481     // @param newnm Name of the method users should use instead
01482     void deprecatedMethod(std::string classnm, std::string oldnm, std::string newnm) {
01483         writelog(">>>> WARNING: method "+oldnm+" of class "+classnm
01484             +" is deprecated.\n");
01485         writelog("         Use method "+newnm+" instead.\n");
01486         writelog("         (If you want to rescue this method from deprecated\n");
01487         writelog("         status, see http://www.cantera.org/deprecated.html)");
01488     }
01489 
01490 
01491     void removeAtVersion(std::string func, std::string version) {
01492       //if (version >= "CANTERA_VERSION") {
01493       writelog("Removed procedure: "+func+"\n");
01494       writelog("Removed in version: "+version+"\n");
01495       throw CanteraError("removeAtVersion: "+ func,"procedure has been removed.");
01496       // }
01497     }
01498 
01499 
01500   // defgroup logs Diagnostic Output (global.h)
01501   //
01502   // Writing diagnostic information to the screen or to a file.
01503   // It is often useful to be able to write diagnostic messages to
01504   // the screen or to a file. Cantera provides two sets of
01505   // procedures for this purpose. The first set is designed to
01506   // write text messages to the screen to document the progress of
01507   // a complex calculation, such as a flame simulation.The second
01508   // set writes nested lists in HTML format. This is useful to
01509   // print debugging output for a complex calculation that calls
01510   // many different procedures.
01511   
01512   
01513   // defgroup textlogs Writing messages to the screen (global.h)
01514   // ingroup logs
01515   //
01516   // Write a message to the screen. The string may be of any
01517   // length, and may contain end-of-line characters. This method is
01518   // used throughout Cantera to write log messages. It can also be
01519   // called by user programs.  The advantage of using writelog over
01520   // writing directly to the standard output is that messages
01521   // written with writelog will display correctly even when Cantera
01522   // is used from MATLAB or other application that do not have a
01523   // standard output stream. @ingroup textlogs
01524 
01525   // Write a message to the screen
01526    void writelog(const std::string& msg) {
01527      app()->writelog(msg);
01528    }
01529 
01530   // Write a message to the screen
01531   void Application::Messages::writelog(const std::string& msg) {
01532     logwriter->write(msg);
01533   }
01534 
01535   // Write a message to the screen.
01536   void writelog(const char* msg) {
01537     app()->writelog(msg);
01538   }
01539 
01540   // Write a message to the screen
01541   void Application::Messages::writelog(const char* pszmsg) {
01542     logwriter->write( pszmsg ) ;
01543   }
01544 
01545   // Write an endl to the screen and flush output
01546   void Application::Messages::writelogendl() {
01547     logwriter->writeendl();
01548   }
01549  
01550   // Write a message to the screen using printf format
01551   void writelogf(const char* fmt,...) {
01552     enum { BUFSIZE = 2048 } ;
01553     char sbuf[BUFSIZE] ;
01554        
01555     va_list args ;
01556        
01557     va_start( args, fmt ) ;
01558        
01559 #if defined(WIN32) && defined(MSC_VER)
01560     _vsnprintf( sbuf, BUFSIZE, fmt, args ) ; 
01561 #else
01562     vsprintf( sbuf, fmt, args ) ;
01563 #endif
01564        
01565     writelog( sbuf ) ;
01566        
01567     va_end(args) ;
01568   }
01569 
01570   void writelogendl() {
01571     app()->writelogendl();
01572   }
01573 
01574   // Write an error message and terminate execution. test.
01575   // @ingroup textlogs
01576   void error(const std::string& msg) {
01577     app()->logerror(msg);
01578   }
01579 
01580   // Write an error message and terminate execution
01581   void Application::Messages::logerror(const std::string& msg) {
01582     logwriter->error(msg) ;
01583   }
01584 
01585     // @ingroup textlogs
01586    int userInterface() {
01587        return app()->getUserEnv();
01588    }
01589 
01590   // Return an integer specifying the application environment.
01591   int Application::Messages::getUserEnv() {
01592     return logwriter->env() ;
01593   }
01594 
01595   // Install a logger. Called by the language interfaces to install an
01596   // appropriate logger. 
01597   // @see Logger.
01598   // @ingroup textlogs
01599   void setLogger(Logger* logwriter) {
01600                 try {
01601           app()->setLogger(logwriter) ;
01602                 }
01603                 catch (std::bad_alloc) {
01604           logwriter->error("bad alloc thrown by app()");
01605                 }
01606   }
01607 
01608     void Application::Messages::setLogger(Logger* _logwriter) {
01609        if ( logwriter == _logwriter ) return ;
01610        if (logwriter != 0 ) {
01611          delete logwriter;
01612          logwriter = 0 ;
01613        }
01614        logwriter = _logwriter;
01615     }
01616 
01617 
01618 #ifdef WITH_HTML_LOGS
01619 
01620   ////////////////////////////////////////////////////////////////
01621   // 
01622   // defgroup HTML_logs Writing HTML Logfiles
01623   // ingroup logs
01624   // 
01625   //  These functions are designed to allow writing HTML diagnostic
01626   //  messages in a manner that allows users to control how much
01627   //  diagnostic output to print. It works like this: Suppose you
01628   //  have function A that invokes function B that invokes function
01629   //  C. You want to be able to print diagnostic messages just from
01630   //  function A, or from A and B, or from A, B, and C, or to turn
01631   //  off printing diagnostic messages altogether. All you need to
01632   //  do is call 'beginLogGroup' within function A, and specify a
01633   //  loglevel value. Then in B, call beginLogGroup again, but
01634   //  without an explicit value for loglevel. By default, the
01635   //  current level is decremented by one in beginLogGroup. If it
01636   //  is <= 0, no log messages are written. Thus, if each function
01637   //  begins with beginLogGroup and calls endLogGroup before
01638   //  returning, then setting loglevel = 3 will cause messages from
01639   //  A, B, and C to be written (in nested HTML lists), loglevel =
01640   //  2 results in messages only being written from A and B, etc.
01641   //
01642   /////////////////////////////////////////////////////////////////
01643 
01644 
01645   // Create a new group for log messages.  Usually this is called
01646   // upon entering the function, with the title parameter equal to
01647   // the name of the function or method. Subsequent messages
01648   // written with addLogEntry will appear grouped under this
01649   // heading, until endLogGroup() is called.
01650   // @ingroup HTML_logs
01651   void beginLogGroup(std::string title, int loglevel) {
01652     app()->beginLogGroup(title, loglevel) ;
01653   }
01654 
01655   void Application::Messages::beginLogGroup(std::string title, int _loglevel /*=-99*/) {
01656     // loglevel is a member of the Messages class.
01657     if (_loglevel != -99) {
01658       loglevel = _loglevel;
01659     } else {
01660       loglevel--;
01661     }
01662     if (loglevel <= 0) return;
01663     // Add the current loglevel to the vector of loglevels
01664     loglevels.push_back(loglevel);
01665     // Add the title of the current logLevel to the vector of titles
01666     loggroups.push_back(title);
01667     // If we haven't started an XML tree for the log file, do so here
01668     if (xmllog == 0) {
01669       // The top of this tree will have a zero pointer.
01670       xmllog = new XML_Node("html");
01671       current = &xmllog->addChild("ul");
01672     }
01673     // Add two children to the XML tree.
01674     current = &current->addChild("li","<b>"+title+"</b>");
01675     current = &current->addChild("ul");
01676   }
01677 
01678   // Add an entry to the log file. Entries appear in the form "tag:
01679   // value".
01680   // @ingroup HTML_logs
01681   void addLogEntry(std::string tag, std::string value) {
01682     app()->addLogEntry(tag, value) ;
01683   }
01684 
01685   void Application::Messages::addLogEntry(std::string tag, std::string value) {
01686     if (loglevel > 0 && current) 
01687       current->addChild("li",tag+": "+value);
01688   }
01689 
01690   // Add an entry to the log file. Entries appear in the form "tag:
01691   // value".
01692   // @ingroup HTML_logs
01693   void addLogEntry(std::string tag, doublereal value) {
01694     app()->addLogEntry( tag, value ) ;
01695   }
01696 
01697   void Application::Messages::addLogEntry(std::string tag, doublereal value) {
01698     if (loglevel > 0 && current) 
01699       current->addChild("li",tag+": "+fp2str(value));
01700   }
01701 
01702   // Add an entry to the log file. Entries appear in the form "tag:
01703   // value".
01704   // @ingroup HTML_logs
01705   void addLogEntry(std::string tag, int value) {
01706     app()->addLogEntry( tag, value ) ;
01707   }
01708 
01709   void Application::Messages::addLogEntry(std::string tag, int value) {
01710     if (loglevel > 0 && current) 
01711       current->addChild("li",tag+": "+int2str(value));
01712   }
01713 
01714   // Add an entry to the log file.
01715   // @ingroup HTML_logs
01716   void addLogEntry(std::string msg) {
01717     app()->addLogEntry(msg) ;
01718   }
01719 
01720   void Application::Messages::addLogEntry(std::string msg) {
01721     if (loglevel > 0 && current)
01722       current->addChild("li",msg);
01723   }
01724 
01725   // Close the current group of log messages. This is typically
01726   // called just before leaving a function or method, to close the
01727   // group of messages that were output from this
01728   // function. Subsequent messages written with addLogEntry will
01729   // appear at the next-higher level in the outline, unless
01730   // beginLogGroup is called first to create a new group.  
01731   // @ingroup HTML_logs
01732   void endLogGroup(std::string title) {
01733     app()->endLogGroup(title) ;
01734   }
01735 
01736   void Application::Messages::endLogGroup(std::string title) {
01737     if (loglevel <= 0) return;
01738     AssertThrowMsg(current, "Application::Messages::endLogGroup",
01739                    "Error while ending a LogGroup. This is probably due to an unmatched"
01740                    " beginnning and ending group");
01741     current = current->parent();
01742     AssertThrowMsg(current, "Application::Messages::endLogGroup",
01743                    "Error while ending a LogGroup. This is probably due to an unmatched"
01744                    " beginnning and ending group");
01745     current = current->parent();
01746     // Get the loglevel of the previous level and get rid of 
01747     // vector entry in loglevels.
01748     loglevel = loglevels.back();
01749     loglevels.pop_back();
01750     if (title != "" && title != loggroups.back()) {
01751       writelog("Logfile error."
01752                "\n   beginLogGroup: "+ loggroups.back()+
01753                "\n   endLogGroup:   "+title+"\n");
01754       write_logfile("logerror"); 
01755     } else if (loggroups.size() == 1) {
01756       write_logfile(loggroups.back()+"_log"); 
01757       loggroups.clear();
01758       loglevels.clear();
01759     } else {
01760       loggroups.pop_back();
01761     }
01762   }
01763 
01764 
01765   // Write the HTML log file.
01766   /*
01767    *  Log entries are stored in memory in
01768    *  an XML tree until this function is called, which writes the
01769    *  tree to a file and clears the entries stored in memory.  The
01770    *  output file will have the name specified in the 'file'
01771    *  argument.  If this argument has no extension, the extension
01772    *  '.html' will be appended. Also, if the file already exists, an
01773    *  integer will be appended to the name so that no existing log
01774    *  file will be overwritten.
01775    *  WITH_HTML_LOGS must be defined.
01776    *
01777    *  @param  file Name of the file to be written
01778    *  @ingroup HTML_logs
01779    */
01780   void write_logfile(std::string file) {
01781     app()->write_logfile(file) ;
01782   }
01783 
01784   // Write the HTML log file.
01785   void Application::Messages::write_logfile(std::string file) {
01786     if (!xmllog) {
01787       return;
01788     }
01789     string::size_type idot = file.rfind('.');
01790     string ext = "";
01791     string nm = file;
01792     if (idot != string::npos) {
01793       ext = file.substr(idot, file.size());
01794       nm = file.substr(0,idot);
01795     }
01796     else {
01797       ext = ".html";
01798       nm = file;
01799     }
01800 
01801     // see if file exists. If it does, find an integer that
01802     // can be appended to the name to create the name of a file
01803     // that does not exist.
01804     string fname = nm + ext;
01805     ifstream f(fname.c_str());
01806     if (f) {
01807       int n = 0;
01808       while (1 > 0) {
01809         n++;
01810         fname = nm + int2str(n) + ext;
01811         ifstream f(fname.c_str());
01812         if (!f) break;
01813       }
01814     }
01815 
01816     // Now we have a file name that does not correspond to any 
01817     // existing file. Open it as an output stream, and dump the 
01818     // XML (HTML) tree to it.
01819 
01820     if (xmllog) {
01821       ofstream f(fname.c_str());
01822       // go to the top of the tree, and write it all.
01823       xmllog->root().write(f);
01824       f.close();
01825       writelog("Log file " + fname + " written.\n");
01826       delete xmllog;
01827       xmllog = 0;
01828       current = 0;
01829     }
01830   }
01831 
01832 #endif // WITH_HTML_LOGS
01833 
01834 
01835   /// split a string at a '#' sign. Used to separate a file name
01836   /// from an id string.
01837   static void split_at_pound(const std::string& src, std::string& file, std::string& id) { 
01838     string::size_type ipound = src.find('#');
01839     if (ipound != string::npos) {
01840       id = src.substr(ipound+1,src.size());
01841       file = src.substr(0,ipound);
01842     }
01843     else {
01844       id = "";
01845       file = src;
01846     }
01847   }
01848   /*
01849    * This routine will locate an XML node in either the input
01850    * XML tree or in another input file specified by the file
01851    * part of the file_ID string. Searches are based on the
01852    * ID attribute of the XML element only.
01853    *
01854    * param file_ID This is a concatenation of two strings seperated
01855    *                by the "#" character. The string before the
01856    *                pound character is the file name of an xml
01857    *                file to carry out the search. The string after
01858    *                the # character is the ID attribute 
01859    *                of the xml element to search for. 
01860    *                The string is interpreted as a file string if
01861    *                no # character is in the string.
01862    *
01863    * param root    If the file string is empty, searches for the
01864    *                xml element with matching ID attribute are
01865    *                carried out from this XML node.
01866    */
01867   XML_Node* get_XML_Node(const std::string& file_ID, XML_Node* root) {
01868     std::string fname, idstr;
01869     XML_Node *db, *doc;
01870     split_at_pound(file_ID, fname, idstr);
01871     if (fname == "") {
01872       if (!root) throw CanteraError("get_XML_Node",
01873                                     "no file name given. file_ID = "+file_ID);
01874       db = root->findID(idstr, 3);
01875     } 
01876     else {
01877       doc = get_XML_File(fname);
01878       if (!doc) throw CanteraError("get_XML_Node", 
01879                                    "get_XML_File failed trying to open "+fname);
01880       db = doc->findID(idstr, 3);
01881     }
01882     if (!db) {
01883       throw CanteraError("get_XML_Node", 
01884                          "id tag '"+idstr+"' not found.");
01885     }
01886     return db;
01887   }
01888 
01889 
01890   /*
01891    * This routine will locate an XML node in either the input
01892    * XML tree or in another input file specified by the file
01893    * part of the file_ID string. Searches are based on the
01894    * XML element name and the ID attribute of the XML element.
01895    * An exact match of both is usually required. However, the
01896    * ID attribute may be set to "", in which case the first
01897    * xml element with the correct element name will be returned.
01898    *
01899    * @param nameTarget This is the XML element name to look for.
01900    *                   
01901    * @param file_ID This is a concatenation of two strings seperated
01902    *                by the "#" character. The string before the
01903    *                pound character is the file name of an xml
01904    *                file to carry out the search. The string after
01905    *                the # character is the ID attribute 
01906    *                of the xml element to search for. 
01907    *                The string is interpreted as a file string if
01908    *                no # character is in the string.
01909    *
01910    * @param root    If the file string is empty, searches for the
01911    *                xml element with matching ID attribute are
01912    *                carried out from this XML node.
01913    */
01914   XML_Node* get_XML_NameID(const std::string& nameTarget,
01915                            const std::string& file_ID, 
01916                            XML_Node* root) {
01917     string fname, idTarget;
01918     XML_Node *db, *doc;
01919     split_at_pound(file_ID, fname, idTarget);
01920     if (fname == "") {
01921       if (!root) return 0;
01922       db = root->findNameID(nameTarget, idTarget);
01923     } else {
01924       doc = get_XML_File(fname);
01925       if (!doc) return 0;
01926       db = doc->findNameID(nameTarget, idTarget);
01927     }
01928     return db;
01929   }
01930 
01931   //! Assigned storage for the static member of the FactoryBase class
01932   std::vector<FactoryBase*> FactoryBase::s_vFactoryRegistry;
01933 }
01934 
01935 
Generated by  doxygen 1.6.3