Contents of misc.cpp relocated

The functions formerly defined in misc.cpp are now defined in the
source files corresponding to the header files where they were
declared.
This commit is contained in:
Ray Speth 2012-03-05 20:45:31 +00:00
parent 8150f49c2c
commit e3b5ee802e
7 changed files with 1952 additions and 2164 deletions

View file

@ -12,9 +12,6 @@
#include <string>
#include <exception>
// See file misc.cpp for implementations of methods/functions declared
// here.
namespace Cantera
{
@ -75,8 +72,7 @@ class CanteraError : public std::exception
public:
//! Normal Constructor for the CanteraError base class
/*!
* This class doesn't have any storage associated with it. In its
* constructor, a call to the Application class is made to store
* In the constructor, a call to the Application class is made to store
* the strings associated with the generated error condition.
*
* @param procedure String name for the function within which the error was
@ -86,14 +82,15 @@ public:
CanteraError(std::string procedure, std::string msg);
//! Destructor for base class does nothing
virtual ~CanteraError() throw();
virtual ~CanteraError() throw() {};
protected:
//! Empty base constructor is made protected so that it may be used only by
//! inherited classes.
/*!
* We want to discourage throwing an error containing no information.
*/
CanteraError();
CanteraError() {};
};
//! Array size error.

View file

@ -405,9 +405,6 @@ void close_XML_File(std::string file);
* A, B, and C to be written (in nested HTML lists), loglevel =
* 2 results in messages only being written from A and B, etc.
*/
//@{
//@}
//!Create a new group for log messages.
/*!
@ -508,7 +505,6 @@ inline void endLogGroup(std::string title="") {}
inline void write_logfile(std::string file = "log.html") {}
#endif
//! This routine will locate an XML node in either the input
//! XML tree or in another input file specified by the file
//! part of the file_ID string.

810
src/base/application.cpp Normal file
View file

@ -0,0 +1,810 @@
#include "application.h"
#include "cantera/base/ctexceptions.h"
#include "cantera/base/ctml.h"
#include "cantera/base/stringUtils.h"
#include "cantera/base/xml.h"
#include <map>
#include <string>
#include <fstream>
using std::string;
using std::endl;
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef _MSC_VER
#pragma comment(lib, "advapi32")
#endif
// If running multiple threads in a cpp application, the Application class
// is the only internal object that is single instance with static data.
// Synchronize access to those data structures Using macros to avoid
// polluting code with a lot of ifdef's
#ifdef THREAD_SAFE_CANTERA
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
//! Mutex for input directory access
static boost::mutex dir_mutex;
//! Mutex for access to string messages
static boost::mutex msg_mutex;
//! Mutex for creating singeltons within the application object
static boost::mutex app_mutex;
// Mutex for controlling access to the log file
//static boost::mutex log_mutex;
//! Mutex for controlling access to XML file storage
static boost::mutex xml_mutex;
//! Macro for locking input directory access
#define DIR_LOCK() boost::mutex::scoped_lock d_lock(dir_mutex)
//! Macro for locking access to string messages
#define MSG_LOCK() boost::mutex::scoped_lock m_lock(msg_mutex)
//! Macro for locking creating singletons in the application state
#define APP_LOCK() boost::mutex::scoped_lock a_lock(app_mutex)
//! Macro for locking XML file writing
#define XML_LOCK() boost::mutex::scoped_lock x_lock(xml_mutex)
#ifdef WITH_HTML_LOGS
//static boost::mutex html_mutex; // html logs
//#define HTML_LOCK() boost::mutex::scoped_lock h_lock(html_mutex)
#endif
#if defined(BOOST_HAS_WINTHREADS)
#include <windows.h>
typedef unsigned int cthreadId_t ;
class thread_equal
{
public:
bool operator()(cthreadId_t L, cthreadId_t R) {
return L == R ;
}
} ;
cthreadId_t getThisThreadId()
{
return ::GetCurrentThreadId() ;
}
#elif defined(BOOST_HAS_PTHREADS)
typedef pthread_t cthreadId_t ;
class thread_equal
{
public:
bool operator()(cthreadId_t L, cthreadId_t R) {
return pthread_equal(L, R) ;
}
} ;
cthreadId_t getThisThreadId()
{
return pthread_self() ;
}
#elif defined(BOOST_HAS_MPTASKS)
typedef MPTaskID cthreadId_t ;
class thread_equal
{
public:
bool operator()(cthreadId_t L, cthreadId_t R) {
return L == R ;
}
} ;
cthreadId_t getThisThreadId()
{
return MPCurrentTaskID() ;
}
#endif
#else
#define DIR_LOCK()
#define MSG_LOCK()
#define APP_LOCK()
//#define LOG_LOCK()
#define XML_LOCK()
#ifdef WITH_HTML_LOGS
//#define HTML_LOCK()
#endif
#endif
namespace Cantera {
Application::Messages::Messages() :
errorMessage(0),
errorRoutine(0),
logwriter(0)
#ifdef WITH_HTML_LOGS
,xmllog(0),
current(0),
loglevel(0),
loglevels(0),
loggroups(0)
#endif
{
// install a default logwriter that writes to standard
// output / standard error
logwriter = new Logger();
}
Application::Messages::Messages(const Messages& r) :
errorMessage(r.errorMessage),
errorRoutine(r.errorRoutine),
logwriter(0)
#ifdef WITH_HTML_LOGS
, xmllog(r.xmllog),
current(r.current),
loglevel(r.loglevel),
loglevels(r.loglevels),
loggroups(r.loggroups)
#endif
{
// install a default logwriter that writes to standard
// output / standard error
logwriter = new Logger(*(r.logwriter));
}
Application::Messages& Application::Messages::operator=(const Messages& r) {
if (this == &r) {
return *this;
}
errorMessage = r.errorMessage;
errorRoutine = r.errorRoutine;
logwriter = new Logger(*(r.logwriter));
#ifdef WITH_HTML_LOGS
xmllog = r.xmllog;
current = r.current;
loglevel = r.loglevel;
loglevels = r.loglevels;
loggroups = r.loggroups;
#endif
return *this;
}
Application::Messages::~Messages() {
delete logwriter;
#ifdef WITH_HTML_LOGS
if (xmllog) {
write_logfile("orphan");
}
#endif
}
// Set an error condition in the application class without throwing an exception
void Application::Messages::addError(std::string r, std::string msg)
{
errorMessage.push_back(msg);
errorRoutine.push_back(r);
}
// Return the number of errors encountered so far
int Application::Messages::getErrorCount()
{
return static_cast<int>(errorMessage.size()) ;
}
void Application::Messages::setLogger(Logger* _logwriter)
{
if (logwriter == _logwriter) {
return ;
}
if (logwriter != 0) {
delete logwriter;
logwriter = 0 ;
}
logwriter = _logwriter;
}
// Return an integer specifying the application environment.
int Application::Messages::getUserEnv()
{
return logwriter->env() ;
}
// Write an error message and terminate execution
void Application::Messages::logerror(const std::string& msg)
{
logwriter->error(msg) ;
}
#ifdef WITH_HTML_LOGS
// Write a message to the screen
void Application::Messages::writelog(const char* pszmsg)
{
logwriter->write(pszmsg) ;
}
// Write a message to the screen
void Application::Messages::writelog(const std::string& msg)
{
logwriter->write(msg);
}
// Write an endl to the screen and flush output
void Application::Messages::writelogendl()
{
logwriter->writeendl();
}
void Application::Messages::beginLogGroup(std::string title, int _loglevel /*=-99*/)
{
// loglevel is a member of the Messages class.
if (_loglevel != -99) {
loglevel = _loglevel;
} else {
loglevel--;
}
if (loglevel <= 0) {
return;
}
// Add the current loglevel to the vector of loglevels
loglevels.push_back(loglevel);
// Add the title of the current logLevel to the vector of titles
loggroups.push_back(title);
// If we haven't started an XML tree for the log file, do so here
if (xmllog == 0) {
// The top of this tree will have a zero pointer.
xmllog = new XML_Node("html");
current = &xmllog->addChild("ul");
}
// Add two children to the XML tree.
current = &current->addChild("li","<b>"+title+"</b>");
current = &current->addChild("ul");
}
void Application::Messages::addLogEntry(std::string tag, std::string value)
{
if (loglevel > 0 && current) {
current->addChild("li",tag+": "+value);
}
}
void Application::Messages::addLogEntry(std::string tag, doublereal value)
{
if (loglevel > 0 && current) {
current->addChild("li",tag+": "+fp2str(value));
}
}
void Application::Messages::addLogEntry(std::string tag, int value)
{
if (loglevel > 0 && current) {
current->addChild("li",tag+": "+int2str(value));
}
}
void Application::Messages::addLogEntry(std::string msg)
{
if (loglevel > 0 && current) {
current->addChild("li",msg);
}
}
void Application::Messages::endLogGroup(std::string title)
{
if (loglevel <= 0) {
return;
}
AssertThrowMsg(current, "Application::Messages::endLogGroup",
"Error while ending a LogGroup. This is probably due to an unmatched"
" beginnning and ending group");
current = current->parent();
AssertThrowMsg(current, "Application::Messages::endLogGroup",
"Error while ending a LogGroup. This is probably due to an unmatched"
" beginnning and ending group");
current = current->parent();
// Get the loglevel of the previous level and get rid of
// vector entry in loglevels.
loglevel = loglevels.back();
loglevels.pop_back();
if (title != "" && title != loggroups.back()) {
writelog("Logfile error."
"\n beginLogGroup: "+ loggroups.back()+
"\n endLogGroup: "+title+"\n");
write_logfile("logerror");
} else if (loggroups.size() == 1) {
write_logfile(loggroups.back()+"_log");
loggroups.clear();
loglevels.clear();
} else {
loggroups.pop_back();
}
}
void Application::Messages::write_logfile(std::string file)
{
if (!xmllog) {
return;
}
std::string::size_type idot = file.rfind('.');
std::string ext = "";
std::string nm = file;
if (idot != std::string::npos) {
ext = file.substr(idot, file.size());
nm = file.substr(0,idot);
} else {
ext = ".html";
nm = file;
}
// see if file exists. If it does, find an integer that
// can be appended to the name to create the name of a file
// that does not exist.
std::string fname = nm + ext;
std::ifstream f(fname.c_str());
if (f) {
int n = 0;
while (1 > 0) {
n++;
fname = nm + int2str(n) + ext;
std::ifstream f(fname.c_str());
if (!f) {
break;
}
}
}
// Now we have a file name that does not correspond to any
// existing file. Open it as an output stream, and dump the
// XML (HTML) tree to it.
if (xmllog) {
std::ofstream f(fname.c_str());
// go to the top of the tree, and write it all.
xmllog->root().write(f);
f.close();
writelog("Log file " + fname + " written.\n");
delete xmllog;
xmllog = 0;
current = 0;
}
}
#endif // WITH_HTML_LOGS
Application::Application() :
inputDirs(0),
stop_on_error(false),
options(),
tmp_dir("."),
xmlfiles(),
m_sleep("1"),
pMessenger() {
#if !defined( THREAD_SAFE_CANTERA )
pMessenger = std::auto_ptr<Messages>(new Messages());
#endif
// if TMP or TEMP is set, use it for the temporary
// directory
char* ctmpdir = getenv("CANTERA_TMPDIR");
if (ctmpdir != 0) {
tmp_dir = std::string(ctmpdir);
} else {
char* tmpdir = getenv("TMP");
if (tmpdir == 0) {
tmpdir = getenv("TEMP");
}
if (tmpdir != 0) {
tmp_dir = std::string(tmpdir);
}
}
// if SLEEP is set, use it as the sleep time
char* sleepstr = getenv("SLEEP");
if (sleepstr != 0) {
m_sleep = std::string(sleepstr);
}
// install a default logwriter that writes to standard
// output / standard error
// logwriter = new Logger();
//#ifdef WITH_HTML_LOGS
// // HTML log files
// xmllog = 0;
// current = 0;
// loglevel = 0;
//#endif
setDefaultDirectories();
#if defined(THREAD_SAFE_CANTERA)
Unit::units() ;
#endif
}
Application* Application::Instance() {
APP_LOCK();
if (Application::s_app == 0) {
Application::s_app = new Application();
}
return s_app;
}
Application::~Application()
{
std::map<std::string, XML_Node*>::iterator pos;
for (pos = xmlfiles.begin(); pos != xmlfiles.end(); ++pos) {
pos->second->unlock();
delete pos->second;
pos->second = 0;
}
}
void Application::ApplicationDestroy() {
APP_LOCK();
if (Application::s_app != 0) {
delete Application::s_app;
Application::s_app = 0;
}
}
void Application::thread_complete()
{
#if defined(THREAD_SAFE_CANTERA)
pMessenger.removeThreadMessages() ;
#endif
}
XML_Node* Application::get_XML_File(std::string file, int debug)
{
XML_LOCK();
std::string path = "";
/*
try {
path = findInputFile(file);
}
catch (CanteraError) {
string::size_type idot = file.rfind('.');
string ext = "";
if (idot != string::npos) {
ext = file.substr(idot, file.size());
string ctifile = file.substr(0,idot)+".cti";
try {
path = findInputFile(ctifile);
}
catch (CanteraError) {
path = findInputFile(file);
}
}
else
path = findInputFile(file);
}
*/
// The code above will try to process a cti file if the xml
// file is not found. But I (dgg) don't think it makes much sense,
// so it is replaced by:
path = findInputFile(file);
#ifdef _WIN32
// RFB: For Windows make the path POSIX compliant so code looking for directory
// separators is simpler. Just look for '/' not both '/' and '\\'
std::replace_if(path.begin(), path.end(),
std::bind2nd(std::equal_to<char>(), '\\'), '/') ;
#endif
string ff = path;
if (xmlfiles.find(path)
== xmlfiles.end()) {
/*
* Check whether or not the file is XML. If not, it will
* be first processed with the preprocessor. We determine
* whether it is an XML file by looking at the file extension.
*/
string::size_type idot = path.rfind('.');
string ext;
if (idot != string::npos) {
ext = path.substr(idot, path.size());
} else {
ext = "";
idot = path.size();
}
if (ext != ".xml" && ext != ".ctml") {
/*
* We will assume that we are trying to open a cti file.
* First, determine the name of the xml file, ff, derived from
* the cti file.
* In all cases, we will write the xml file to the current
* directory.
*/
string::size_type islash = path.rfind('/');
if (islash != string::npos) {
ff = string("./")+path.substr(islash+1,idot-islash - 1) + ".xml";
} else {
ff = string("./")+path.substr(0,idot) + ".xml";
}
#ifdef DEBUG_PATHS
cout << "get_XML_File(): Expected location of xml file = "
<< ff << endl;
#endif
/*
* Do a search of the existing XML trees to determine if we have
* already processed this file. If we have, return a pointer to
* the processed xml tree.
*/
if (xmlfiles.find(ff) != xmlfiles.end()) {
#ifdef DEBUG_PATHS
cout << "get_XML_File(): File, " << ff << ", was previously read."
<< " Retrieving the stored xml tree." << endl;
#endif
return xmlfiles[ff];
}
/*
* Ok, we didn't find the processed XML tree. Do the conversion
* to xml, possibly overwriting the file, ff, in the process.
*/
ctml::ct2ctml(path.c_str(),debug);
} else {
ff = path;
}
/*
* Take the XML file ff, open it, and process it, creating an
* XML tree, and then adding an entry in the map. We will store
* the absolute pathname as the key for this map.
*/
std::ifstream s(ff.c_str());
XML_Node* x = new XML_Node("doc");
if (s) {
x->build(s);
x->lock();
xmlfiles[ff] = x;
} else {
string estring = "cannot open "+ff+" for reading.";
estring += "Note, this error indicates a possible configuration problem.";
throw CanteraError("get_XML_File", estring);
}
}
/*
* Return the XML node pointer. At this point, we are sure that the
* lookup operation in the return statement will return a valid
* pointer.
*/
return xmlfiles[ff];
}
void Application::close_XML_File(std::string file)
{
XML_LOCK();
if (file == "all") {
std::map<string, XML_Node*>::iterator
b = xmlfiles.begin(),
e = xmlfiles.end();
for (; b != e; ++b) {
b->second->unlock();
delete b->second;
xmlfiles.erase(b->first);
}
} else if (xmlfiles.find(file) != xmlfiles.end()) {
xmlfiles[file]->unlock();
delete xmlfiles[file];
xmlfiles.erase(file);
}
}
#ifdef _WIN32
long int Application::readStringRegistryKey(const std::string& keyName, const std::string& valueName,
std::string& value, const std::string& defaultValue)
{
HKEY key;
long open_error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName.c_str(), 0, KEY_READ, &key);
if (open_error != ERROR_SUCCESS) {
return open_error;
}
value = defaultValue;
CHAR buffer[1024];
DWORD bufferSize = sizeof(buffer);
ULONG error;
error = RegQueryValueEx(key, valueName.c_str(), 0, NULL, (LPBYTE) buffer, &bufferSize);
if (ERROR_SUCCESS == error) {
value = buffer;
}
RegCloseKey(key);
return error;
}
#endif
void Application::setTmpDir(std::string tmp)
{
APP_LOCK();
tmp_dir = tmp ;
}
std::string Application::getTmpDir()
{
APP_LOCK();
return tmp_dir ;
}
std::string Application::sleep()
{
APP_LOCK();
return m_sleep ;
}
void Application::Messages::popError()
{
if (static_cast<int>(errorMessage.size()) > 0) {
errorRoutine.pop_back() ;
errorMessage.pop_back() ;
}
}
std::string Application::Messages::lastErrorMessage()
{
if (static_cast<int>(errorMessage.size()) > 0) {
string head =
"\n\n************************************************\n"
" Cantera Error! \n"
"************************************************\n\n";
return head+string("\nProcedure: ")+errorRoutine.back()
+string("\nError: ")+errorMessage.back();
} else {
return "<no Cantera error>";
}
}
void Application::Messages::getErrors(std::ostream& f)
{
int i = static_cast<int>(errorMessage.size());
if (i == 0) {
return;
}
f << endl << endl;
f << "************************************************" << endl;
f << " Cantera Error! " << endl;
f << "************************************************" << endl
<< endl;
int j;
for (j = 0; j < i; j++) {
f << endl;
f << "Procedure: " << errorRoutine[j] << endl;
f << "Error: " << errorMessage[j] << endl;
}
f << endl << endl;
errorMessage.clear();
errorRoutine.clear();
}
void Application::Messages::logErrors()
{
int i = static_cast<int>(errorMessage.size());
if (i == 0) {
return;
}
writelog("\n\n");
writelog("************************************************\n");
writelog(" Cantera Error! \n");
writelog("************************************************\n\n");
int j;
for (j = 0; j < i; j++) {
writelog("\n");
writelog(string("Procedure: ")+ errorRoutine[j]+" \n");
writelog(string("Error: ")+ errorMessage[j]+" \n");
}
writelog("\n\n");
errorMessage.clear();
errorRoutine.clear();
}
void Application::setDefaultDirectories()
{
std::vector<string>& dirs = inputDirs;
// always look in the local directory first
dirs.push_back(".");
#ifdef _WIN32
// Under Windows, the Cantera setup utility records the installation
// directory in the registry. Data files are stored in the 'data' and
// 'templates' subdirectories of the main installation directory.
std::string installDir;
readStringRegistryKey("SOFTWARE\\Cantera\\Cantera 2.0", "InstallDir", installDir, "");
if (installDir != "") {
dirs.push_back(installDir + "data");
dirs.push_back(installDir + "templates");
}
#endif
#ifdef DARWIN
//
// add a default data location for Mac OS X
//
dirs.push_back("/Applications/Cantera/data");
#endif
//
// if environment variable CANTERA_DATA is defined, then add
// it to the search path
//
if (getenv("CANTERA_DATA") != 0) {
string datadir = string(getenv("CANTERA_DATA"));
dirs.push_back(datadir);
}
// CANTERA_DATA is defined in file config.h. This file is written
// during the build process (unix), and points to the directory
// specified by the 'prefix' option to 'configure', or else to
// /usr/local/cantera.
#ifdef CANTERA_DATA
string datadir = string(CANTERA_DATA);
dirs.push_back(datadir);
#endif
}
void Application::addDataDirectory(std::string dir)
{
DIR_LOCK() ;
if (inputDirs.size() == 0) {
setDefaultDirectories();
}
string d = stripnonprint(dir);
size_t m, n = inputDirs.size();
// don't add if already present
for (m = 0; m < n; m++) {
if (d == inputDirs[m]) {
return;
}
}
inputDirs.push_back(d);
}
std::string Application::findInputFile(std::string name)
{
DIR_LOCK() ;
string::size_type islash = name.find('/');
string::size_type ibslash = name.find('\\');
string inname;
std::vector<string>& dirs = inputDirs;
int nd;
if (islash == string::npos && ibslash == string::npos) {
nd = static_cast<int>(dirs.size());
int i;
inname = "";
for (i = 0; i < nd; i++) {
inname = dirs[i] + "/" + name;
std::ifstream fin(inname.c_str());
if (fin) {
fin.close();
return inname;
}
}
string msg;
msg = "\nInput file " + name
+ " not found in director";
msg += (nd == 1 ? "y " : "ies ");
for (i = 0; i < nd; i++) {
msg += "\n'" + dirs[i] + "'";
if (i < nd-1) {
msg += ", ";
}
}
msg += "\n\n";
msg += "To fix this problem, either:\n";
msg += " a) move the missing files into the local directory;\n";
msg += " b) define environment variable CANTERA_DATA to\n";
msg += " point to the directory containing the file.";
throw CanteraError("findInputFile", msg);
}
return name;
}
Application* Application::s_app = 0;
} // namespace Cantera

787
src/base/application.h Normal file
View file

@ -0,0 +1,787 @@
#ifndef CT_BASE_APPLICATION_H
#define CT_BASE_APPLICATION_H
#include "cantera/base/config.h"
#include "cantera/base/logger.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace Cantera {
class XML_Node;
/*!
* @defgroup globalData Global Data
*
* Global data are available anywhere. There are two kinds.
* Cantera has an assortment of constant values for physical parameters.
* Also, Cantera maintains a collection of global data which is specific
* to each process that invokes Cantera functions. This process-specific
* data is stored in the class Application.
*/
//! Class to hold global data.
/*!
* Class Application is the top-level
* class that stores data that should persist for the duration of
* the process. The class should not be instantiated directly;
* instead, it is instantiated as needed by the functions declared
* here. At most one instance is created, and it is not destroyed
* until the process terminates.
*
* @ingroup HTML_logs
* @ingroup textlogs
* @ingroup globalData
*/
class Application
{
protected:
//! Class to carry out messages
/*!
* @ingroup HTML_logs
*/
class Messages
{
public:
//! Constructor for the Messages class
/*! Constructor for the Messages class which is a subclass
* of the Application class.
*/
Messages();
//! Copy Constructor for the Messages class
/*! Constructor for the Messages class which is a subclass
* of the Application class.
* @param r Message to be copied
*/
Messages(const Messages& r);
//! Assignment operator
/*!
* @param r Message to be copied
*/
Messages& operator=(const Messages& r);
//! Destructor for the Messages class
~Messages();
//! Set an error condition in the application class without
//! throwing an exception.
/*!
* This routine adds an error message to the end of the stack
* of errors that Cantera accumulates in the Application
* class.
* @param r location
* @param msg Description of the error
* @ingroup errorhandling
*/
void addError(std::string r, std::string msg);
//! Return the number of errors that have been encountered so far.
/*!
* @ingroup errorhandling
*/
int getErrorCount() ;
//! Discard the last error message
/*!
* %Cantera saves a stack of exceptions that it
* has caught in the Application class. This routine eliminates
* the last exception to be added to that stack.
*
* @ingroup errorhandling
*/
void popError() ;
//! Retrieve the last error message in a string
/*!
* This routine will retrieve the last error message and return
* it in the return string.
*
* @ingroup errorhandling
*/
std::string lastErrorMessage() ;
//! Prints all of the error messages to an ostream
/*!
* Print all of the error messages using function writelog.
* Write out all of the saved error messages to the ostream f
* Cantera saves a stack of exceptions that it
* has caught in the Application class. This routine writes
* out all of the error messages to the ostream
* and then clears them from internal storage.
*
* @param f ostream which will receive the error messages
*
* @ingroup errorhandling
*/
void getErrors(std::ostream& f) ;
//! Prints all of the error messages using writelog
/*!
* Print all of the error messages using function writelog.
* Cantera saves a stack of exceptions that it
* has caught in the Application class. This routine writes
* out all of the error messages
* and then clears them from internal storage.
*
* @ingroup errorhandling
*/
void logErrors();
//! Write a message to the screen.
/*!
* The string may be of any
* length, and may contain end-of-line characters. This method is
* used throughout %Cantera to write log messages.
*
* @param msg c++ string to be written to the screen
* @ingroup textlogs
*/
void writelog(const std::string& msg);
//! Write an end of line and flush output
void writelogendl();
//! Write a message to the screen.
/*!
* The string may be of any
* length, and may contain end-of-line characters. This method is
* used throughout %Cantera to write log messages.
*
* @param pszmsg c character string to be written to the screen
* @ingroup textlogs
*/
void writelog(const char* pszmsg) ;
//! Write an error message and quit.
/*!
* The default behavior is
* to write to the standard error stream, and then call
* exit(). Note that no end-of-line character is appended to
* the message, and so if one is desired it must be included
* in the string. Note that this default behavior will
* terminate the application Cantera is invoked from (MATLAB,
* Excel, etc.) If this is not desired, then derive a class
* and reimplement this method.
*
* @param msg Error message to be written to cerr.
*/
void logerror(const std::string& msg) ;
//! Returns an integer specifying the application environment
int getUserEnv() ;
//! Install a logger.
/*!
* Called by the language interfaces to install an appropriate logger.
* The logger is used for the writelog() function
*
* @param logwriter Pointer to a logger object
* @see Logger.
* @ingroup textlogs
*/
void setLogger(Logger* logwriter) ;
#ifdef WITH_HTML_LOGS
//!Create a new group for log messages.
/*!
* Usually this is called
* upon entering the function, with the title parameter equal to
* the name of the function or method. Subsequent messages
* written with addLogEntry will appear grouped under this
* heading, until endLogGroup() is called.
*
* @param title String name of the LogGroup
* @param loglevel loglevel of the group.
* @ingroup HTML_logs
*/
void beginLogGroup(std::string title, int loglevel) ;
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "tag:value".
*
* @param tag tag
* @param value double value
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string tag, std::string value) ;
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "tag:value".
*
* @param tag tag
* @param value double value
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string tag, doublereal value) ;
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "tag:value".
*
* @param tag tag
* @param value double value
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string tag, int value) ;
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "msg".
*
* @param msg Message to be added
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string msg) ;
//! Close the current group of log messages.
/*!
* This is typically
* called just before leaving a function or method, to close the
* group of messages that were output from this
* function. Subsequent messages written with addLogEntry() will
* appear at the next-higher level in the outline, unless
* beginLogGroup() is called first to create a new group.
*
* @param title Name of the log group. It defaults to the most recent
* log group created.
*/
void endLogGroup(std::string title) ;
//! Write the HTML log file.
/*!
* Log entries are stored in memory in
* an XML tree until this function is called, which writes the
* tree to a file and clears the entries stored in memory. The
* output file will have the name specified in the 'file'
* argument. If this argument has no extension, the extension
* '.html' will be appended. Also, if the file already exists, an
* integer will be appended to the name so that no existing log
* file will be overwritten.
* WITH_HTML_LOGS must be defined.
*
* @param file Name of the file to be written
*/
void write_logfile(std::string file);
#endif
protected:
//! Current list of error messages
std::vector<std::string> errorMessage;
//! Current error Routine
std::vector<std::string> errorRoutine;
//! Current pointer to the logwriter
Logger* logwriter;
#ifdef WITH_HTML_LOGS
//! Current pointer to the top of the XML_Node tree for the current HTML log
XML_Node* xmllog;
//! Pointer to the last current position in the XML_Node tree for the current HTML log
XML_Node* current;
//! Current value of the loglevel
int loglevel;
//! Vector of loglevels for loggroups that are open
std::vector<int> loglevels;
//! Current vector of loggroups that are open
std::vector<std::string> loggroups;
#endif
} ;
#ifdef THREAD_SAFE_CANTERA
//! Typedef for thread specific messages
typedef boost::shared_ptr< Messages > pMessages_t ;
//! Typedef for map between a thread and the message
typedef std::map< cthreadId_t, pMessages_t > threadMsgMap_t ;
//! Class that stores thread messages for each thread, and retrieves them
//! based on the thread id.
class ThreadMessages
{
public:
//! Constructor
ThreadMessages() {
}
//! Provide a pointer deferencing overloaded operator
/*!
* @return returns a pointer to Messages
*/
Messages* operator->() {
MSG_LOCK() ;
cthreadId_t curId = getThisThreadId() ;
threadMsgMap_t::iterator iter = m_threadMsgMap.find(curId) ;
if (iter != m_threadMsgMap.end()) {
return (iter->second.get()) ;
}
pMessages_t pMsgs(new Messages()) ;
m_threadMsgMap.insert(std::pair< cthreadId_t, pMessages_t >(curId, pMsgs)) ;
return pMsgs.get() ;
}
//! Remove a local thread message
void removeThreadMessages() {
MSG_LOCK() ;
cthreadId_t curId = getThisThreadId() ;
threadMsgMap_t::iterator iter = m_threadMsgMap.find(curId) ;
if (iter != m_threadMsgMap.end()) {
m_threadMsgMap.erase(iter) ;
}
}
private:
//! Thread Msg Map
threadMsgMap_t m_threadMsgMap ;
} ;
#endif
protected:
//! Constructor for class sets up the initial conditions
//! Protected ctor access thru static member function Instance
Application();
public:
//! Return a pointer to the one and only instance of class Application
/*!
* If the an Application object has not yet been created it is created
*/
static Application* Instance();
//! Destructor for class deletes global data
/*!
* Delete any open XML trees, the logwriter, and
* the XML log, if any.
*/
virtual ~Application();
//! Static function that destroys the application class's data
static void ApplicationDestroy();
//! Set the directory where temporary files may be written.
/*!
* @param tmp Name of the directory
*/
void setTmpDir(std::string tmp) ;
//! get the name of a directory where temporary files may be written.
std::string getTmpDir() ;
//! Pause the application for a certain amount
/*!
* This has been needed in the past for some network file systems.
*/
std::string sleep() ;
//! Set an error condition in the application class without
//! throwing an exception.
/*!
* This routine adds an error message to the end of the stack
* of errors that Cantera accumulates in the Application
* class.
* @param r location
* @param msg Description of the error
* @ingroup errorhandling
*/
void addError(std::string r, std::string msg) {
pMessenger->addError(r, msg) ;
}
//! Return the number of errors that have been encountered so far.
/*!
* @ingroup error handling
*/
int getErrorCount() {
return pMessenger->getErrorCount() ;
}
//! Discard the last error message
/*!
* %Cantera saves a stack of exceptions that it
* has caught in the Application class. This routine eliminates
* the last exception to be added to that stack.
*
* @ingroup errorhandling
*/
void popError() {
pMessenger->popError() ;
}
//! Retrieve the last error message in a string
/*!
* This routine will retrieve the last error message and return
* it in the return string.
*
* @ingroup errorhandling
*/
std::string lastErrorMessage() {
return pMessenger->lastErrorMessage() ;
}
//! Prints all of the error messages to an ostream
/*!
* Print all of the error messages using function writelog.
* Write out all of the saved error messages to the ostream f
* Cantera saves a stack of exceptions that it
* has caught in the Application class. This routine writes
* out all of the error messages to the ostream
* and then clears them from internal storage.
*
* @param f ostream which will receive the error messages
*
* @ingroup errorhandling
*/
void getErrors(std::ostream& f) {
pMessenger->getErrors(f) ;
}
//! Prints all of the error messages using writelog
/*!
* Print all of the error messages using function writelog.
* Cantera saves a stack of exceptions that it
* has caught in the Application class. This routine writes
* out all of the error messages
* and then clears them from internal storage.
*
* @ingroup errorhandling
*/
void logErrors() {
pMessenger->logErrors() ;
}
//! Add a directory to the data file search path.
/*!
* @ingroup inputfiles
*
* @param dir String name for the directory to be added to the search path
*/
void addDataDirectory(std::string dir) ;
//! Find an input file.
/*!
* This routine will search for a file in the default
* locations specified for the application.
* See the routine setDefaultDirectories() listed above.
*
* The default set of directories specified for the application
* will be searched if a '/' or an '\\' is found in the
* name. If either is found then a relative path name is
* presumed, and the default directories are not searched.
*
* The presence of the file is determined by whether the file
* can be opened for reading by the current user.
*
* @param name Name of the input file to be searched for
*
* @return
*
* The absolute path name of the first matching
* file is returned. If a relative path name
* is indicated, the relative path name is returned.
*
* If the file is not found, a message is written to
* stdout and a CanteraError exception is thrown.
*
* @ingroup inputfiles
*/
std::string findInputFile(std::string name) ;
//! Return a pointer to the XML tree for a Cantera input file.
/*!
* This routine will find the file and read the XML file into an
* XML tree structure. Then, a pointer will be returned. If the
* file has already been processed, then just the pointer will
* be returned.
*
* @param file String containing the relative or absolute file name
* @param debug Debug flag
*/
XML_Node* get_XML_File(std::string file, int debug=0) ;
//! Close an XML File
/*!
* Close a file that is opened by this application object
*
* @param file String containing the relative or absolute file name
*/
void close_XML_File(std::string file) ;
//! Write a message to the screen.
/*!
* The string may be of any
* length, and may contain end-of-line characters. This method is
* used throughout %Cantera to write log messages.
*
* @param msg c++ string to be written to the screen
* @ingroup textlogs
*/
#ifdef _WIN32
long int readStringRegistryKey(const std::string& keyName, const std::string& valueName,
std::string& value, const std::string& defaultValue);
#endif
void writelog(const std::string& msg) {
pMessenger->writelog(msg);
}
//! Write an endl to the screen and flush output
/*!
* @ingroup textlogs
*/
void writelogendl() {
pMessenger->writelogendl();
}
//! Write a message to the screen.
/*!
* The string may be of any
* length, and may contain end-of-line characters. This method is
* used throughout %Cantera to write log messages.
*
* @param pszmsg c null terminated string to be written to the screen
* @ingroup textlogs
*/
void writelog(const char* pszmsg) {
pMessenger->writelog(pszmsg);
}
//! Write an error message and quit.
/*!
* The default behavior is
* to write to the standard error stream, and then call
* exit(). Note that no end-of-line character is appended to
* the message, and so if one is desired it must be included
* in the string. Note that this default behavior will
* terminate the application Cantera is invoked from (MATLAB,
* Excel, etc.) If this is not desired, then derive a class
* and reimplement this method.
*
* @param msg Error message to be written to cerr.
*/
void logerror(const std::string& msg) {
pMessenger->logerror(msg);
}
//! Returns an integer specifying the application environment.
int getUserEnv() {
return pMessenger->getUserEnv() ;
}
//! Install a logger - Called by the language interfaces to install an
//! appropriate logger.
/*!
* @param logwriter Pointer to a logger object
* @see Logger.
* @ingroup textlogs
*/
void setLogger(Logger* logwriter) {
pMessenger->setLogger(logwriter);
}
//! Delete Messenger object allocated per thread.
void thread_complete() ;
#ifdef WITH_HTML_LOGS
//!Create a new group for log messages.
/*!
* Usually this is called
* upon entering the function, with the title parameter equal to
* the name of the function or method. Subsequent messages
* written with addLogEntry will appear grouped under this
* heading, until endLogGroup() is called.
*
* @param title String name of the LogGroup
* @param loglevel loglevel of the group.
* @ingroup HTML_logs
*/
void beginLogGroup(std::string title, int loglevel) {
pMessenger->beginLogGroup(title,loglevel);
}
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "tag:value".
*
* @param tag tag
* @param value double value
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string tag, std::string value) {
pMessenger->addLogEntry(tag, value);
}
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "tag:value".
*
* @param tag tag
* @param value double value
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string tag, doublereal value) {
pMessenger->addLogEntry(tag, value);
}
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "tag:value".
*
* @param tag tag
* @param value double value
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string tag, int value) {
pMessenger->addLogEntry(tag, value);
}
//! Add an entry to an HTML log file.
/*!
* Entries appear in the form "msg".
*
* @param msg Message to be added to file
*
* @ingroup HTML_logs
*/
void addLogEntry(std::string msg) {
pMessenger->addLogEntry(msg);
}
//! Close the current group of log messages.
/*!
* This is typically
* called just before leaving a function or method, to close the
* group of messages that were output from this
* function. Subsequent messages written with addLogEntry() will
* appear at the next-higher level in the outline, unless
* beginLogGroup() is called first to create a new group.
*
* @param title Name of the log group. It defaults to the most recent
* log group created.
* @ingroup HTML_logs
*/
void endLogGroup(std::string title) {
pMessenger->endLogGroup(title) ;
}
//! Write the HTML log file.
/*!
* Log entries are stored in memory in
* an XML tree until this function is called, which writes the
* tree to a file and clears the entries stored in memory. The
* output file will have the name specified in the 'file'
* argument. If this argument has no extension, the extension
* '.html' will be appended. Also, if the file already exists, an
* integer will be appended to the name so that no existing log
* file will be overwritten.
* WITH_HTML_LOGS must be defined.
*
* @param file Name of the file to be written
*/
void write_logfile(std::string file) {
pMessenger->write_logfile(file) ;
}
#endif
protected:
//! Set the default directories for input files.
/*!
* %Cantera searches
* for input files along a path that includes platform-specific
* default locations, and possibly user-specified locations. This
* function installs the platform-specific directories on the
* search path. It is invoked at startup by appinit(), and never
* should need to be called by user programs.
*
* The current directory (".") is always searched first. Then, on
* Windows platforms, if environment variable COMMONPROGRAMFILES
* is set (which it should be on Win XP or Win 2000), then
* directories under this one will be added to the search
* path. The %Cantera Windows installer installs data files to this
* location.
*
* On the Mac, directory '/Applications/Cantera/data' is added to the
* search path.
*
* On any platform, if environment variable CANTERA_DATA is set to a
* directory name, then this directory is added to the search path.
*
* Finally, the location where the data files were installed when
* %Cantera was built is added to the search path.
*
* Additional directories may be added by calling function addDirectory.
* @ingroup inputfiles
*/
void setDefaultDirectories();
//! Current vector of input directories to search for input files
std::vector<std::string> inputDirs;
//! Current list of error messages
//vector<string> errorMessage;
//! Current list of warning messages
//vector<string> warning;
//! Current error Routine
//vector<string> errorRoutine;
//! Last error message
//string msglog;
//! Current line length
// size_t linelen;
//! Current value of stop_on_error
bool stop_on_error;
//! Current map of options
std::map<std::string, std::string> options;
//! Current value of tmp_dir
std::string tmp_dir;
//! Current vector of xml file trees that have been previously parsed
std::map<std::string, XML_Node*> xmlfiles;
//! Current sleep command.
std::string m_sleep;
//! Current pointer to the logwriter
//Logger* logwriter;
#ifdef WITH_HTML_LOGS
//! Current pointer to the top of the XML_Node tree for the current HTML log
//XML_Node *xmllog;
//! Pointer to the last current position in the XML_Node tree for the current HTML log
//XML_Node *current;
//! Current value of loglevel
//int loglevel;
//! Vector of loglevels for loggroups that are open
//vector<int> loglevels;
//! Current vector of loggroups that are open
//vector<string> loggroups;
#endif
#if defined(THREAD_SAFE_CANTERA)
ThreadMessages pMessenger ;
#else
std::auto_ptr<Messages> pMessenger ;
#endif
private:
//! Pointer to the single Application instance
static Application* s_app ;
};
}
#endif

48
src/base/ctexceptions.cpp Normal file
View file

@ -0,0 +1,48 @@
#include "cantera/base/ctexceptions.h"
#include "application.h"
#include "cantera/base/global.h"
#include "cantera/base/stringUtils.h"
namespace Cantera {
// *** Exceptions ***
CanteraError::CanteraError(std::string procedure, std::string msg)
{
Application::Instance()->addError(procedure, msg);
}
ArraySizeError::ArraySizeError(std::string proc, size_t sz, size_t reqd) :
CanteraError(proc, "Array size ("+int2str(sz)+
") too small. Must be at least "+int2str(reqd))
{
}
ElementRangeError::ElementRangeError(std::string func, size_t m, size_t mmax) :
CanteraError(func, "Element index " + int2str(m) +
" outside valid range of 0 to " + int2str(mmax-1))
{
}
// *** Warnings ***
void deprecatedMethod(std::string classnm, std::string oldnm, std::string newnm)
{
writelog(">>>> WARNING: method "+oldnm+" of class "+classnm
+" is deprecated.\n");
writelog(" Use method "+newnm+" instead.\n");
writelog(" (If you want to rescue this method from deprecated\n");
writelog(" status, see http://www.cantera.org/deprecated.html)");
}
void removeAtVersion(std::string func, std::string version)
{
writelog("Removed procedure: "+func+"\n");
writelog("Removed in version: "+version+"\n");
throw CanteraError("removeAtVersion: "+ func,"procedure has been removed.");
}
} // namespace Cantera

303
src/base/global.cpp Normal file
View file

@ -0,0 +1,303 @@
#include "cantera/base/global.h"
#include "cantera/base/ctexceptions.h"
#include "cantera/base/FactoryBase.h"
#include "cantera/base/xml.h"
#include "application.h"
#include "units.h"
// RFB:TODO May need OS specifc include to use varargs.h instead
#include <stdarg.h>
using namespace std;
namespace Cantera {
//! Return a pointer to the application object
static Application* app()
{
return Application::Instance() ;
}
// **************** Text Logging ****************
void setLogger(Logger* logwriter)
{
try {
app()->setLogger(logwriter) ;
} catch (std::bad_alloc) {
logwriter->error("bad alloc thrown by app()");
}
}
void writelog(const std::string& msg)
{
app()->writelog(msg);
}
void writelog(const char* msg)
{
app()->writelog(msg);
}
void writelogf(const char* fmt,...)
{
enum { BUFSIZE = 2048 } ;
char sbuf[BUFSIZE] ;
va_list args ;
va_start(args, fmt) ;
#ifdef _MSC_VER
_vsnprintf(sbuf, BUFSIZE, fmt, args) ;
#else
vsprintf(sbuf, fmt, args) ;
#endif
writelog(sbuf) ;
va_end(args) ;
}
void writelogendl()
{
app()->writelogendl();
}
void error(const std::string& msg)
{
app()->logerror(msg);
}
int userInterface()
{
return app()->getUserEnv();
}
// **************** HTML Logging ****************
#ifdef WITH_HTML_LOGS
void beginLogGroup(std::string title, int loglevel)
{
app()->beginLogGroup(title, loglevel) ;
}
void addLogEntry(std::string tag, std::string value)
{
app()->addLogEntry(tag, value) ;
}
void addLogEntry(std::string tag, doublereal value)
{
app()->addLogEntry(tag, value) ;
}
void addLogEntry(std::string tag, int value)
{
app()->addLogEntry(tag, value) ;
}
void addLogEntry(std::string msg)
{
app()->addLogEntry(msg) ;
}
void endLogGroup(std::string title)
{
app()->endLogGroup(title) ;
}
void write_logfile(std::string file)
{
app()->write_logfile(file) ;
}
#endif // WITH_HTML_LOGS
// **************** Global Data ****************
Unit* Unit::s_u = 0;
#if defined(THREAD_SAFE_CANTERA)
boost::mutex Unit::units_mutex ;
#endif
void appdelete()
{
Application::ApplicationDestroy() ;
FactoryBase::deleteFactories();
Unit::deleteUnit();
}
void thread_complete()
{
app()->thread_complete() ;
}
XML_Node* get_XML_File(std::string file, int debug)
{
XML_Node* xtmp = app()->get_XML_File(file, debug) ;
//writelog("get_XML_File: returned from app:get_XML_FILE " + int2str(xtmp) + "\n");
return xtmp;
}
void close_XML_File(std::string file)
{
app()->close_XML_File(file) ;
}
void setTmpDir(std::string tmp)
{
app()->setTmpDir(tmp);
}
string tmpDir()
{
return app()->getTmpDir();
}
string sleep()
{
return app()->sleep();
}
int nErrors()
{
return app()->getErrorCount();
}
void popError()
{
app()->popError() ;
}
string lastErrorMessage()
{
return app()->lastErrorMessage() ;
}
void showErrors(std::ostream& f)
{
app()->getErrors(f) ;
}
void showErrors()
{
app()->logErrors() ;
}
void setError(std::string r, std::string msg)
{
app()->addError(r, msg) ;
}
void addDirectory(std::string dir)
{
app()->addDataDirectory(dir) ;
}
std::string findInputFile(std::string name)
{
return app()->findInputFile(name) ;
}
doublereal toSI(std::string unit)
{
doublereal f = Unit::units()->toSI(unit);
if (f) {
return f;
} else {
throw CanteraError("toSI","unknown unit string: "+unit);
}
return 1.0;
}
doublereal actEnergyToSI(std::string unit)
{
doublereal f = Unit::units()->actEnergyToSI(unit);
if (f) {
return f;
}
return 1.0;
}
string canteraRoot()
{
char* ctroot = 0;
ctroot = getenv("CANTERA_ROOT");
if (ctroot != 0) {
return string(ctroot);
}
#ifdef CANTERA_ROOT
return string(CANTERA_ROOT);
#else
return "";
#endif
}
//! split a string at a '#' sign. Used to separate a file name from an id string.
/*!
* @param src Original string to be split up. This is unchanged.
* @param file Output string representing the first part of the string, which is the filename.
* @param id Output string representing the last part of the string, which is the id.
*/
static void split_at_pound(const std::string& src, std::string& file, std::string& id)
{
string::size_type ipound = src.find('#');
if (ipound != string::npos) {
id = src.substr(ipound+1,src.size());
file = src.substr(0,ipound);
} else {
id = "";
file = src;
}
}
XML_Node* get_XML_Node(const std::string& file_ID, XML_Node* root)
{
std::string fname, idstr;
XML_Node* db, *doc;
split_at_pound(file_ID, fname, idstr);
if (fname == "") {
if (!root) throw CanteraError("get_XML_Node",
"no file name given. file_ID = "+file_ID);
db = root->findID(idstr, 3);
} else {
doc = get_XML_File(fname);
if (!doc) throw CanteraError("get_XML_Node",
"get_XML_File failed trying to open "+fname);
db = doc->findID(idstr, 3);
}
if (!db) {
throw CanteraError("get_XML_Node",
"id tag '"+idstr+"' not found.");
}
return db;
}
XML_Node* get_XML_NameID(const std::string& nameTarget,
const std::string& file_ID,
XML_Node* root)
{
string fname, idTarget;
XML_Node* db, *doc;
split_at_pound(file_ID, fname, idTarget);
if (fname == "") {
if (!root) {
return 0;
}
db = root->findNameID(nameTarget, idTarget);
} else {
doc = get_XML_File(fname);
if (!doc) {
return 0;
}
db = doc->findNameID(nameTarget, idTarget);
}
return db;
}
std::vector<FactoryBase*> FactoryBase::s_vFactoryRegistry;
}

File diff suppressed because it is too large Load diff