// ESAF : Euso Simulation and Analysis Framework
// $Id: Config.cc,v 1.14 2005/05/11 14:34:33 thea Exp $
// Author: Daniel De Marco Jan, 25 2002
// M.Pallavicini - added Standard configuration handling 1/10/02
/*****************************************************************************
* ESAF: Euso Simulation and Analysis Framework *
* *
* Id: EsafMsgDispatcher *
* Package: Base *
* Coordinator: Marco.Pallavicini *
* *
*****************************************************************************/
//______________________________________________________________________________
//
// Configuration Manager
// ====================
//
//
#include "Config.hh"
#include "StringsFileParser.hh"
#include <fstream>
ClassImp(Config)
Config *Config::fMe = 0;
//______________________________________________________________________________
Config::Config() {
//
// Ctor
//
fCurrentConfig = "None";
fStdConfigList = "./config/Standard/StandardConfigs.lst";
fDumpFileName = "./output/ConfigDump.cfg";
}
//______________________________________________________________________________
Config::~Config() {
//
// Dtor
//
}
//______________________________________________________________________________
Config* Config::Get() {
//
// Instance
//
if ( fMe == 0 )
fMe = new Config();
return fMe;
}
//______________________________________________________________________________
void Config::SetDumpFileName( const char* name ) {
//
//
//
if ( !name ) return;
string ext = ".cfg";
fDumpFileName = name;
if (fDumpFileName.rfind(ext) != (fDumpFileName.size()-ext.size()))
fDumpFileName += ext;
}
//______________________________________________________________________________
void Config::SaveConfig() {
//
// Save the current configuration in a single "standard config file"
//
ofstream of(fDumpFileName.c_str(),ios::out);
if ( IsStandardConfigDefined() ) {
of << "## Standard config " << fCurrentConfig << " is being used." << endl;
of << "## user defined variables dump" << endl;
map<string, vector<string>*>::iterator jt;
for(jt=fUserDef.begin(); jt != fUserDef.end(); jt++) {
of << "## Dump for class name " << jt->first << endl;
vector<string>::iterator jt2;
for(jt2 = jt->second->begin(); jt2 != jt->second->end(); jt2++)
of << (*jt2) << endl;
of << "## End of dump for class name " << jt->first << endl;
}
of.close();
return;
}
of << "## config file dump generated by ESAF n\n";
map<string, ConfigFileParser*>::const_iterator it;
for(it=fCfs.begin(); it!=fCfs.end(); it++) {
ConfigFileParser &cfp = *(it->second);
of << "## Dump for class name " << it->first << endl;
map<string,double>::const_iterator it2;
for(it2=cfp.fNumbers.begin(); it2!=cfp.fNumbers.end(); it2++) {
of << it2->first << " = " << it2->second << endl;
}
map<string,string>::const_iterator it3;
for(it3=cfp.fChars.begin(); it3!=cfp.fChars.end(); it3++) {
of << it3->first << " = " << it3->second << endl;
}
of << "## End of dump for class name " << it->first << endl;
}
of.close();
}
//______________________________________________________________________________
ConfigFileParser *Config::GetCF(const string &ClassType, const string &ClassName,
const string &path ) {
//
// if ClassName is name of a parent class whose real instance is a child, the
// file corresponding to the child is returned
//
// if a standard config is defined, use it
if ( IsStandardConfigDefined() ) {
return fStandards[fCurrentConfig];
}
// check if this class has a child
string child_name;
if ( fChildTable.count( ClassName ) == 0 )
child_name = ClassName;
else
child_name = *(fChildTable[ClassName]);
// create the ConfigFileParser if needed, and override parameters if required
if ( fCfs.count(child_name) == 0 ) {
fCfs[child_name] = new ConfigFileParser(ClassType,child_name,path);
if ( fUserDef.count( child_name ) != 0 ) {
vector<string>::iterator dummy;
for( dummy = fUserDef[child_name]->begin();
dummy != fUserDef[child_name]->end() ;dummy++)
fCfs[child_name]->Replace( *dummy );
}
}
// return ConfigFileParser
return fCfs[child_name];
}
// handling standard configuration
// The file config/Standard/StandardConfigs.lst contains the names of the "Standard"
// configurations, i.e. files with all ESAF parameters.
// Each file will be also kept in the same directory
//______________________________________________________________________________
void Config::DefineConfig(const string& name) {
//
// Define a new config with the current configuration files
// to be implemented
//
if ( fStandards.count(name) == 0 )
Msg(EsafMsg::Panic) << name << " is not defined as standard configuration in "
<< fStdConfigList<< MsgDispatch;
Msg(EsafMsg::Info) << "Using standard configuration " << name << MsgDispatch;
fCurrentConfig = name;
}
//______________________________________________________________________________
ConfigFileParser *Config::GetStandardConfig() {
//
// Get the current standard config if defined
// returns NULL if not (no exception thrown)
//
if ( IsStandardConfigDefined() ) {
if ( fStandards.find(fCurrentConfig) == fStandards.end() )
FatalError("Standard config "+fCurrentConfig+" does not exist!!!");
else
return fStandards[fCurrentConfig];
}
return (ConfigFileParser*)NULL;
}
//______________________________________________________________________________
void Config::LoadStandardConfigs() {
//
// Load the list of defined standard configs
//
// open file
ifstream in(fStdConfigList.c_str());
if(!in) FatalError("can't open file "+fStdConfigList);
// get list from file
// each line not beginning with # is considered a standard config name
string dummy;
while(getline(in, dummy)) {
size_t pos;
// erase comments
pos=dummy.find('#');
if(pos!=string::npos) dummy.erase(pos);
// swallow spaces
dummy=swallow_spaces(dummy);
// skip blank lines
if(dummy.empty()) continue;
// now ready with name
string cfgName = dummy;
//FIXME: conflict with EsafMsgDispatcher building
//Messages can't be used here
//Msg(EsafMsg::Info) << "Reading standard config " << cfgName << MsgDispatch;
Msg(EsafMsg::Info) << "Reading standard config " << cfgName << MsgDispatch;
// build the ConfigFileParser object and put it into the map
if ( fStandards.find(cfgName) == fStandards.end() ) {
fStandards[cfgName] = new ConfigFileParser("Standard",cfgName);
// override parameters if required
// iterate on map elements
map<string, vector<string>* >::iterator m_iter;
for(m_iter = fUserDef.begin(); m_iter != fUserDef.end(); m_iter++) {
// iterate on vector elements
vector<string>::iterator v_iter;
for(v_iter = m_iter->second->begin();
v_iter != m_iter->second->end(); v_iter++) {
fStandards[cfgName]->Replace(*v_iter);
}
}
}
else {
//FIXME: conflict with EsafMsgDispatcher building
//Messages can't be used here
Msg(EsafMsg::Panic) << "Duplicate name "+cfgName+" in ./config/Standard/Config.cfg" << MsgDispatch;
}
}
}
//______________________________________________________________________________
void Config::Reset() {
//
// Reset the config
//
// FIXME: check for memory leak here.
// Does map destroy the elements it points to ?
map<string,ConfigFileParser*>::iterator dummy;
if (fCfs.size() != 0)
for (dummy = fCfs.begin(); dummy != fCfs.end(); ++dummy)
delete dummy->second;
fCfs.clear();
}
//______________________________________________________________________________
void Config::ResetUserDef() {
//
// Reset User settings
//
map<string, vector<string>* >::iterator dummy;
if (fUserDef.size() != 0)
for (dummy = fUserDef.begin(); dummy != fUserDef.end(); ++dummy)
delete dummy->second;
fUserDef.clear();
}
//______________________________________________________________________________
void Config::AssociateParent(const string& c_name, const string& p_name) {
//
// associate class name and parent name
//
if ( fChildTable.count(p_name) == 0 )
fChildTable[p_name] = new string(c_name);
else {
if ( (*(fChildTable[p_name])) == c_name ) return;
Msg(EsafMsg::Warning) << c_name << " is being associated to "
<< p_name << endl;
Msg(EsafMsg::Warning) << *(fChildTable[p_name]) << MsgDispatch;
}
}
//______________________________________________________________________________
void Config::AddUserDefinition(const string &c_name, const string &expr) {
string s = expr;
s = swallow_spaces( s );
if ( s.empty() )
FatalError("invalid expr: "+expr);
if ( fUserDef.count(c_name) == 0)
fUserDef[c_name] = new vector<string>;
fUserDef[c_name]->push_back(expr);
if ( IsStandardConfigDefined() && fUserDef.count( c_name ) != 0 )
fStandards[fCurrentConfig]->Replace( expr, kTRUE );
MsgForm(EsafMsg::Debug,"UserDef added: class=%s, expr=%s",c_name.c_str(), expr.c_str());
}
//______________________________________________________________________________
Bool_t Config::LoadUserConfig( const char* fname ) {
//
// Load a set of user definitions from file
//
// The definitions MUST have the following format
// Classname.VarName=Value
//
StringsFileParser parser( fname );
if ( parser.IsZombie() )
MsgForm(EsafMsg::Panic,"File %s not found",fname);
list< list<string> >& lines = parser.GetLines();
size_t nlines = lines.size();
size_t n(0);
vector<string> keys(nlines);
vector<string> expr(nlines);
list<string>::const_iterator jt;
list< list<string> >::const_iterator it;
for( it = lines.begin(); it != lines.end(); it++ ) {
// rebuild the line with 1 space
string line;
for (jt=it->begin(); jt != it->end();jt++ ) {
if ( jt != it->begin() ) line += " ";
line += *(jt);
}
if ( it->size() != 3 ) {
MsgForm(EsafMsg::Warning,"Wrong number of elements in file %s at line:",fname);
Msg(EsafMsg::Warning) << line << " " << it->size() << MsgDispatch;
return kFALSE;
}
// keyword
jt = it->begin();
size_t pos = jt->find('.');
if ( pos == string::npos ) {
MsgForm(EsafMsg::Warning,"Corrupted file %s at line:",fname);
Msg(EsafMsg::Warning) << line << " " << it->size() << MsgDispatch;
return kFALSE;
}
keys[n] = jt->substr(0,pos);
// check on the '='
jt++;
if ( *(jt) != "=" ) {
MsgForm(EsafMsg::Warning,"Corrupted file %s at line:",fname);
Msg(EsafMsg::Warning) << line << " " << it->size() << MsgDispatch;
return kFALSE;
}
expr[n] = line;
n++;
}
for (size_t i(0); i<n; i++)
AddUserDefinition(keys[i],expr[i]);
return kTRUE;
}