Config.cpp
Go to the documentation of this file.
00001 /*******************************************************************************
00002  *  Config.cpp
00003  *
00004  *  (C) 2006 AG Aktives Sehen <agas@uni-koblenz.de>
00005  *           Universitaet Koblenz-Landau
00006  *
00007  * Author: Frank Neuhaus
00008  *******************************************************************************/
00009 
00010 #include "Config.h"
00011 #include <iostream>
00012 #include "../../Architecture/TinyXML/tinyxml.h"
00013 #include "ros/ros.h"
00014 
00015 #include <fstream>
00016 
00017 #define ROOTNODE_NAME "MergedConfig"
00018 
00019 Config* Config::m_inst=0;
00020 
00021 Mutex Config::m_AccessMutex = Mutex ();
00022 
00023 using namespace std;
00024 
00025 //---------------------------------------------------------------------------------
00026 Config::Config()
00027 {
00028   m_doc=0;
00029 }
00030 //---------------------------------------------------------------------------------
00031 Config::~Config()
00032 {
00033     delete m_doc;
00034 }
00035 //---------------------------------------------------------------------------------
00036 Config::Config(const Config& c2)
00037   :
00038   m_fileName(c2.m_fileName),
00039   m_activeProfile(c2.m_activeProfile),
00040   m_moduleList(c2.m_moduleList),
00041   m_values(c2.m_values)
00042 {
00043   if (c2.m_doc)
00044     m_doc=new TiXmlDocument(*c2.m_doc);
00045   else
00046     m_doc=0;
00047 }
00048 //---------------------------------------------------------------------------------
00049 Config& Config::operator=(const Config& c2)
00050 {
00051   m_fileName=c2.m_fileName;
00052   m_moduleList=c2.m_moduleList;
00053   m_activeProfile=c2.m_activeProfile;
00054   m_values=c2.m_values;
00055   if (c2.m_doc)
00056     m_doc=new TiXmlDocument(*c2.m_doc);
00057   else
00058     m_doc=0;
00059   return *this;
00060 }
00061 //---------------------------------------------------------------------------------
00062 Config* Config::getInstance()
00063 {
00064   m_AccessMutex.lock ();
00065   if ( !m_inst )
00066   {
00067     ROS_WARN_STREAM( "No instance was set! Trying to load 'default' profile from file 'Config.xml'.." );
00068     Config* newConf=new Config();
00069     vector<string> profiles;
00070     profiles.push_back("default");
00071     newConf->loadFromFile("Config.xml",profiles);
00072     setInstance( newConf );
00073   }
00074   m_AccessMutex.unlock ();
00075   return m_inst;
00076 }
00077 
00078 
00079 void Config::loadConfig(const std::vector<std::string> files, const std::vector<std::string> profiles, const std::string& prepend_path)
00080 {
00081     ofstream outStream;
00082     std::string mergedFile = prepend_path + "/config/merged.xml";
00083     outStream.open(mergedFile.c_str());
00084     outStream << "<?xml version=\"1.0\" standalone=\"no\" ?>\n\n";
00085     outStream << "<MergedConfig>\n\n";
00086 
00087     vector< string > fileNames;
00088     fileNames.push_back(prepend_path + "/config/default.xml");
00089 
00090     // insert additional files
00091     std::vector<std::string>::iterator it;
00092     it = fileNames.end();
00093     fileNames.insert (it, files.begin(), files.end());
00094 
00095     for ( unsigned i=0; i<fileNames.size(); i++ )
00096     {
00097       ROS_INFO_STREAM( "Loading " + fileNames[i] );
00098       string line;
00099       ifstream configFile (fileNames[i].c_str());
00100       if (configFile.is_open()) {
00101         while ( configFile.good() )
00102         {
00103           getline (configFile,line);
00104           outStream << line << endl;
00105         }
00106         configFile.close();
00107       }
00108     }
00109 
00110     outStream << "\n\n</MergedConfig>";
00111     outStream.close();
00112 
00113     vector<std::string> profilesToLoad;
00114     profilesToLoad.push_back("default");
00115 
00116     // insert additional profiles
00117     it = profilesToLoad.end();
00118     profilesToLoad.insert (it, profiles.begin(), profiles.end());
00119 
00120     Config* newConf=new Config();
00121     if (!newConf->loadFromFile( prepend_path + "/config/merged.xml", profilesToLoad ))
00122     {
00123         ROS_ERROR_STREAM("Could not load config file!");
00124         exit ( -126 );
00125     }
00126     Config::setInstance(newConf);
00127 }
00128 
00129 
00130 int Config::getInt ( const std::string& id )
00131 {
00132   return getInstance()->get<int>( id );
00133 }
00134 
00135 bool Config::getBool ( const std::string& id )
00136 {
00137   return getInstance()->get<int>( id );
00138 }
00139 
00140 std::string Config::getString ( const std::string& id )
00141 {
00142   return getInstance()->get<const char*>( id );
00143 }
00144 
00145 float Config::getFloat ( const std::string& id )
00146 {
00147   return getInstance()->get<float>( id );
00148 }
00149 
00150 bool Config::getFloatMinMax ( const std::string& id, std::pair<float,float>& minmax )
00151 {
00152   return getInstance()->getMinMax<float>( id, minmax );
00153 }
00154 
00155 bool Config::getIntMinMax ( const std::string& id, std::pair<int,int>& minmax )
00156 {
00157   return getInstance()->getMinMax<int>( id, minmax );
00158 }
00159 
00160 //---------------------------------------------------------------------------------
00161 void Config::clear()
00162 {
00163   m_AccessMutex.lock ();
00164   m_values.clear();
00165   m_AccessMutex.unlock ();
00166 }
00167 //---------------------------------------------------------------------------------
00168 bool Config::parseValue ( TiXmlElement* el,Config::ConfigEntry& newEntry, std::string& name ) const
00169 {
00170   if ( !el )
00171     return false;
00172 
00173   bool error=false;
00174 
00175   const char* pName=el->Attribute ( "name" );
00176   if ( !pName )
00177     return false;
00178 
00179   /*std::string */name=pName;
00180 
00181   if ( name.size() <1 )
00182     return false;
00183 
00184   //ConfigEntry newEntry;
00185   if ( name.c_str() [0]=='i' || name.c_str() [0]=='b' )
00186   {
00187     int tmp=0;
00188     error&= ( el->QueryIntAttribute ( "value",&tmp ) !=TIXML_SUCCESS );
00189     newEntry.setInt ( tmp );
00190 
00191     tmp=0;
00192     error&= ( el->QueryIntAttribute ( "min", &tmp ) !=TIXML_SUCCESS );
00193     newEntry.setIntMin ( tmp );
00194 
00195     tmp=0;
00196     error&= ( el->QueryIntAttribute ( "max", &tmp ) !=TIXML_SUCCESS );
00197     newEntry.setIntMax ( tmp );
00198   }
00199   else if ( name.c_str() [0]=='f' )
00200   {
00201     float tmp=0;
00202     error&= ( el->QueryFloatAttribute ( "value", &tmp ) !=TIXML_SUCCESS );
00203     newEntry.setFloat ( tmp );
00204 
00205     tmp=0;
00206     error&= ( el->QueryFloatAttribute ( "min", &tmp ) !=TIXML_SUCCESS );
00207     newEntry.setFloatMin ( tmp );
00208 
00209     tmp=0;
00210     error&= ( el->QueryFloatAttribute ( "max", &tmp ) !=TIXML_SUCCESS );
00211     newEntry.setFloatMax ( tmp );
00212   }
00213   else if ( name.c_str() [0]=='s' )
00214   {
00215     const char* val=el->Attribute ( "value" );
00216     if ( val )
00217     {
00218       newEntry.setString ( val );
00219     }
00220     else
00221       error=true;
00222   }
00223   else
00224     error=true;
00225 
00226   if ( error )
00227     return false;
00228 
00229   //m_values[level+"."+name]=newEntry;
00230 
00231   return true;
00232 }
00233 //---------------------------------------------------------------------------------
00234 bool Config::parseValues ( const std::string& level, TiXmlNode* root )
00235 {
00236   if ( !root )
00237     return false;
00238 
00239   for ( TiXmlNode* value=root->FirstChildElement();value!=NULL;value=value->NextSibling() )
00240   {
00241     TiXmlElement* el=value->ToElement();
00242     if (!el) continue;
00243     if ( !strcasecmp ( el->Value(),"Modules" ) ) continue;
00244     if ( !strcasecmp ( el->Value(),"value" ) )
00245     {
00246       ConfigEntry dest;
00247       std::string name;
00248       if (parseValue ( el,dest ,name))
00249       {
00250         m_values[level+"."+name]=dest;
00251       }
00252     }
00253     else
00254     {
00255       if ( !level.empty() )
00256         parseValues ( level+"."+el->Value(),value );
00257       else
00258         parseValues ( el->Value(),value );
00259     }
00260 
00261   }
00262 
00263   return true;
00264 }
00265 //---------------------------------------------------------------------------------
00266 void Config::addModule( std::string name )
00267 {
00268   bool found=false;
00269   for (unsigned i=0; i<m_moduleList.size(); i++ )
00270   {
00271     if (m_moduleList[i] == name)
00272     {
00273       found=true;
00274       break;
00275     }
00276   }
00277   if ( !found )
00278   {
00279     ROS_DEBUG_STREAM( "Adding module "+name );
00280     m_moduleList.push_back( name );
00281   } else {
00282     ROS_WARN_STREAM( "Duplicate module entry '"+name+"' was ignored." );
00283   }
00284 }
00285 //---------------------------------------------------------------------------------
00286 void Config::parseModules(TiXmlNode* root)
00287 {
00288   if (!root)
00289     return;
00290 
00291   for ( TiXmlNode* value=root->FirstChildElement();value!=NULL;value=value->NextSibling() )
00292   {
00293     if (!value->ToElement()) continue;
00294     if (!strcasecmp(value->ToElement()->Value(),"module"))
00295     {
00296       if (value->ToElement()->Attribute("name"))
00297       {
00298         std::string name=value->ToElement()->Attribute("name");
00299         addModule( name );
00300       }
00301     }
00302   }
00303 
00304 }
00305 
00306 bool Config::parseProfile ( TiXmlNode* root )
00307 {
00308   //Parse parent profile
00309   if ( root->ToElement()->Attribute("parents") )
00310   {
00311     string parents = root->ToElement()->Attribute("parents");
00312 //     ROS_INFO( parents );
00313     std::vector<std::string> parentList = explode( parents, "," );
00314     
00315     for ( unsigned i=0; i < parentList.size(); i++ )
00316     {
00317       string parentProfileName = parentList[i];
00318       TiXmlNode* docRoot=m_doc->FirstChild ( ROOTNODE_NAME );
00319       TiXmlNode* parentProfileNode=docRoot->FirstChild ( parentProfileName );
00320       
00321       if ( m_loadedProfileNames.find( parentProfileName) != m_loadedProfileNames.end() )
00322       {
00323         ROS_ERROR_STREAM( "Cyclic profile dependecy detected! Main profile: "+m_activeProfile );
00324         ROS_INFO_STREAM( "Profile " << parentProfileName << " already loaded" );
00325         return true;
00326       }
00327       
00328       if (!parentProfileNode) {
00329         ROS_ERROR_STREAM( "Parent profile node '" + parentProfileName + "' not found");
00330         return false;
00331       }
00332       
00333       m_loadedProfileNames.insert( parentProfileName );
00334       parseProfile( parentProfileNode );
00335     }
00336     
00337   }
00338 
00339   ROS_INFO_STREAM( "Parsing profile "+string(root->ToElement()->Value()) );
00340 
00341   TiXmlNode* modules=root->FirstChild ( "Modules" );
00342   if (modules) {
00343     parseModules(modules);
00344   }
00345 
00346   if ( !parseValues( "", root) ) {
00347      ROS_ERROR_STREAM( "Could not parse values from " + root->ValueStr()); 
00348     return false;
00349   }
00350   return true;
00351 }
00352 
00353 //---------------------------------------------------------------------------------
00354 bool Config::parseDocument(const std::string& fileName, const std::vector<std::string>& profiles )
00355 {
00356   m_fileName=fileName;
00357 
00358   TiXmlNode* root=m_doc->FirstChild ( ROOTNODE_NAME );
00359   if ( !root ) {
00360     ROS_ERROR_STREAM( "Failed to load " + fileName + ": Root node not found: " << ROOTNODE_NAME);
00361     return false;
00362   }
00363 
00364   //Read list of all profiles
00365   TiXmlNode* child = 0;
00366   ostringstream stream;
00367   stream.setf ( ios::left, ios::adjustfield );
00368   stream.width(35);
00369   stream << "Profile";
00370   stream << "Parents";
00371   stream << endl << "---------------------------------------------------------";
00372   while( (child = root->IterateChildren( child )) )
00373   {
00374     if ( child->Type() == TiXmlNode::ELEMENT )
00375     {
00376       string parentName=" ";
00377       if ( child->ToElement()->Attribute("parents") )
00378       {
00379         parentName=child->ToElement()->Attribute("parents");
00380       }
00381       stream << endl;
00382       stream.width(35);
00383       stream << child->ValueStr();
00384       stream << parentName;
00385     }
00386   }
00387   m_allProfileNames=stream.str();
00388 
00389   stream.str("");
00390   //load all profiles
00391   for ( unsigned p=0; p<profiles.size(); p++ )
00392   {
00393     string profileName = profiles[p];
00394     
00395     if ( p != 0 )
00396     {
00397       stream << "_";
00398     }
00399     stream << profileName;
00400     
00401     TiXmlNode* profileNode=root->FirstChild ( profileName );
00402     if (!profileNode) {
00403       ROS_ERROR_STREAM( "Failed to load " + fileName + ": Profile node '" + profileName + "' not found\n\n"+m_allProfileNames);
00404       return false;
00405     }
00406 
00407     m_loadedProfileNames.insert( profileName );
00408     if (!parseProfile( profileNode )) {
00409       ROS_ERROR_STREAM( "Failed to load " + fileName + ": Could not parse profile '"+profileName+"'\n\n"+m_allProfileNames);
00410       return false;
00411     }
00412   }
00413   
00414   m_activeProfile = stream.str();
00415 
00416   return true;
00417 }
00418 
00419 //---------------------------------------------------------------------------------
00420 bool Config::loadFromFile ( const std::string& fileName, const std::vector<std::string>& profiles )
00421 {
00422   delete m_doc;
00423   m_doc=new TiXmlDocument ( fileName.c_str() );
00424   bool loadOkay = m_doc->LoadFile();
00425   if ( !loadOkay )
00426   {
00427     ROS_ERROR_STREAM( "Failed to load " + fileName + ": "+ m_doc->ErrorDesc());
00428     return false;
00429   }
00430   return parseDocument(fileName,profiles);
00431 
00432 }
00433 //---------------------------------------------------------------------------------
00434 void Config::saveValue ( const std::string& name, const ConfigEntry& entry, TiXmlElement* allProfValues,TiXmlElement* values ) const
00435 {
00436   assert(values);
00437   std::string valuename;
00438 
00439   std::string::size_type start=0;
00440   std::string::size_type pos;
00441   TiXmlElement* curAllProf=allProfValues;
00442   bool doInsert=false;
00443   while ( 1 )
00444   {
00445     pos = name.find ( '.' ,start);
00446     if ( pos == std::string::npos )
00447     {
00448       valuename=name.substr ( start );
00449       curAllProf=curAllProf->FirstChildElement();
00450       while (curAllProf)
00451       {
00452         const char* nameattr=curAllProf->Attribute("name");
00453         if (!nameattr) continue;
00454         if (!strcmp(curAllProf->Attribute("name"),valuename.c_str()))
00455           break;
00456         curAllProf=curAllProf->NextSiblingElement();
00457       }
00458       if (!curAllProf)
00459       {
00460         doInsert=true;
00461       }
00462       break;
00463     }
00464     else
00465     {
00466       TiXmlElement* childAll=curAllProf->FirstChildElement ( name.substr ( start,pos-start ).c_str() );
00467       if ( !childAll )
00468       {
00469         doInsert=true;
00470         break;
00471       }
00472       curAllProf=childAll;
00473       start=pos+1;
00474     }
00475   }
00476   TiXmlElement * cxn = new TiXmlElement ( "value" );
00477 
00478 
00479   cxn->SetAttribute ( "name", valuename.c_str() );
00480   if ( entry.getType() ==ConfigEntry::TYPE_INT )
00481   {
00482     char tmp[256];
00483     sprintf ( tmp,"%d",entry.getInt() );
00484     cxn->SetAttribute ( "value",tmp );
00485 
00486     if ( entry.getIntMax() !=entry.getIntMin() )
00487     {
00488       sprintf ( tmp,"%d",entry.getIntMin() );
00489       cxn->SetAttribute ( "min",tmp );
00490       sprintf ( tmp,"%d",entry.getIntMax() );
00491       cxn->SetAttribute ( "max",tmp );
00492     }
00493   }
00494   else if ( entry.getType() ==ConfigEntry::TYPE_FLOAT )
00495   {
00496     char tmp[256];
00497     sprintf ( tmp,"%1.2f",entry.getFloat() );
00498     cxn->SetAttribute ( "value",tmp );
00499 
00500     if ( entry.getFloatMax() !=entry.getFloatMin() )
00501     {
00502       sprintf ( tmp,"%1.2f",entry.getFloatMin() );
00503       cxn->SetAttribute ( "min",tmp );
00504       sprintf ( tmp,"%1.2f",entry.getFloatMax() );
00505       cxn->SetAttribute ( "max",tmp );
00506     }
00507   }
00508   else if ( entry.getType() ==ConfigEntry::TYPE_STRING )
00509   {
00510     cxn->SetAttribute ( "value",entry.getString() );
00511   }
00512   else
00513     assert ( 0 );
00514 
00515 
00516   if (!doInsert)
00517   {
00518     TiXmlElement* val=curAllProf;
00519     if (val)
00520     {
00521       ConfigEntry ent;
00522       std::string dummy;
00523       if (parseValue(val,ent,dummy))
00524       {
00525         if (ent==entry)
00526         {
00527           delete cxn;
00528           return;
00529         }
00530       }
00531 
00532     }
00533   }
00534 
00535   start=0;
00536   TiXmlElement* cur=values;
00537   while ( 1 )
00538   {
00539     pos = name.find ( '.' ,start);
00540     if ( pos == std::string::npos )
00541     {
00542       valuename=name.substr ( start );
00543       break;
00544     }
00545     else
00546     {
00547       TiXmlElement* child=cur->FirstChildElement ( name.substr ( start,pos-start ).c_str() );
00548       if ( !child )
00549       {
00550         child=new TiXmlElement ( name.substr ( start,pos-start ).c_str() );
00551         cur->LinkEndChild ( child );
00552       }
00553       cur=child;
00554 
00555       start=pos+1;
00556 
00557     }
00558   }
00559 
00560 
00561   cur->LinkEndChild ( cxn );
00562 
00563 }
00564 //---------------------------------------------------------------------------------
00565 std::vector<std::string> Config::getAllVars() const
00566 {
00567   std::vector<std::string> ret;
00568   for ( std::map<std::string,ConfigEntry>::const_iterator it=m_values.begin();it!=m_values.end();++it )
00569   {
00570     ret.push_back(it->first);
00571   }
00572   return ret;
00573 }
00574 //---------------------------------------------------------------------------------
00575 const std::vector<std::string>& Config::getModuleList() const
00576 {
00577   return m_moduleList;
00578 }
00579 //---------------------------------------------------------------------------------
00580 
00581 
00582 std::vector<std::string> Config::explode (const std::string& text, const std::string& separators, bool keepSeparators)
00583 {
00584   size_t n     = text.length ();
00585   size_t start = text.find_first_not_of (separators);
00586   std::vector<std::string> words;
00587   
00588   while (start < n)
00589   {
00590     size_t stop = text.find_first_of (separators, start);
00591     if (stop > n) stop = n;
00592     if ( keepSeparators )
00593     {
00594       words.push_back (text.substr (start, stop-start+1));
00595     }
00596     else
00597     {
00598       words.push_back (text.substr (start, stop-start));
00599     }
00600     start = text.find_first_not_of (separators, stop+1);
00601   };
00602   return words;
00603 }
00604 //---------------------------------------------------------------------------------


robbie_architecture
Author(s): Viktor Seib
autogenerated on Mon Oct 6 2014 02:53:09