ParameterList.cc

00001 //Copyright 2013 Ben Loer
00002 //This file is part of the ConfigHandler library
00003 //It is released under the terms of the GNU General Public License v3
00004 
00005 #include "ParameterList.hh"
00006 #include "Parameter.hh"
00007 #include <sstream>
00008 #include "Message.hh"
00009 #include "ConfigHandler.hh"
00010 #include <stdexcept>
00011 #include <iomanip>
00012 
00013 ParameterList::~ParameterList()
00014 {
00015 
00016 }
00017 
00018 ParameterList::ParameterList(const ParameterList& right) :
00019   VParameterNode(right._default_key, right._helptext)
00020 {
00021   _node_type = PARAMETER_LIST;
00022   CopyPlistRelative(right);
00023 }
00024 
00025 ParameterList& ParameterList::operator=(const ParameterList& right)
00026 {
00027   _deleter.clear();
00028   _parameters.clear();
00029   return *this;
00030 }
00031 
00032 void ParameterList::CopyPlistRelative(const ParameterList& right)
00033 {
00034   ParMap::const_iterator it;
00035   for(it = right._parameters.begin(); it != right._parameters.end(); ++it){
00036     VParameterNode* newnode = it->second->Clone(&right, this);
00037     switch(newnode->GetNodeType()){
00038     case FUNCTION:
00039     case PARAMETER:{
00040       boost::shared_ptr<VParameterNode> ptr(newnode);
00041       _deleter.push_back(ptr);
00042       _parameters.insert(std::make_pair(it->first,newnode));
00043       break;
00044     }
00045     case PARAMETER_LIST:
00046       _parameters.insert(std::make_pair(it->first, newnode));
00047       break;
00048     default:
00049       break;
00050     }
00051   
00052   }//end loop over map iterator
00053 }
00054 
00055 
00056 VParameterNode* const ParameterList::GetParameter(const std::string& key){
00057   ParMap::iterator it = _parameters.find(key);
00058   if(it != _parameters.end()) 
00059     return it->second;
00060   else 
00061     return 0;
00062 }
00063 
00064 std::istream& ParameterList::ReadFrom(std::istream& in, bool single)
00065 {
00066   if(_parameters.empty())
00067     InitializeParameterList();
00068   char next = ' ';
00069   //peek at the next character
00070   while ( in.get(next) ){
00071     //if it's ')', or '}' exit
00072     if( next == ')' || next == '}' )
00073       break;
00074     //if it's space, \t, \n, or comma, or opening parneth. ignore it and move on
00075     if( next == ' ' || next == ',' || next == '\t' || next == '\n' 
00076         || next == '(' || next == '{' || next == '|' || next == ';')
00077       continue;
00078     //if it's #, it's a comment, so kill the line and move on
00079     if( next =='#' ){
00080       std::string dummy;
00081       std::getline(in,dummy);
00082       continue;
00083     }
00084     //if it's @, it marks the start of a function statement
00085     if( next == '@' ){
00086       std::string func;
00087       in>>func;
00088       if(func == "include"){
00089         std::string fname;
00090         in>>fname;
00091         std::string filepath = ConfigHandler::GetInstance()->FindConfigFile(fname);
00092         if(filepath == "")
00093           throw std::invalid_argument(fname);
00094         Message(DEBUG)<<"including file "<<filepath<<std::endl;
00095         ReadFromFile(filepath.c_str());
00096         continue;
00097       }
00098       else if (func == "copy"){
00099         std::string par1, par2;;
00100         in>>par1>>par2;
00101         Message(DEBUG)<<"Copying all settings of "<<par1<<" to "<<par2<<"\n";
00102         ParMap::iterator it1 = _parameters.find(par1);
00103         ParMap::iterator it2 = _parameters.find(par2);
00104         if(it1 == _parameters.end() || it2 == _parameters.end()){
00105           Message(EXCEPTION)<<"Unable to find one of the parameters "<<par1
00106                             <<" or "<<par2<<" to copy!\n";
00107           throw std::invalid_argument(par1+","+par2);
00108         }
00109         std::stringstream temp;
00110         (it1->second)->WriteTo(temp);
00111         (it2->second)->ReadFrom(temp);
00112         continue;
00113       }
00114       else{
00115         Message(WARNING)<<"Ignoring unknown command: @"<<func<<std::endl;
00116         continue;
00117       }
00118     }
00119     //anything else should be the start of a key 
00120     //so put it back and read in the key
00121     in.unget();
00122 
00123     std::string bigkey;
00124     if( !(in>>bigkey) ){
00125       //somethings messed up.  Throw an exception and die
00126       throw std::invalid_argument("Unabled to read parameter list");
00127       return in;
00128     }
00129     //bigkey may actually be a list of keys like key1,key2,key3
00130     std::vector<std::string> keylist;
00131     size_t searchstart=0;
00132     size_t pos;
00133     while( (pos = bigkey.find(',',searchstart)) != std::string::npos){
00134       keylist.push_back(bigkey.substr(searchstart,(pos-searchstart)));
00135       searchstart = pos+1;
00136       if(searchstart >= bigkey.size()) break;
00137     }
00138     //should be one last key
00139     keylist.push_back(bigkey.substr(searchstart));
00140     
00141     //read all the keys listed
00142     std::streampos start = in.tellg();
00143     for(size_t ikey = 0; ikey<keylist.size(); ++ikey){
00144       if(ikey>0)
00145         in.seekg(start);
00146 
00147       std::string key = keylist[ikey];
00148       //see if the key has '.' in it
00149       bool sendsingle = false;
00150       std::string::size_type pos = key.find('.',0);
00151       if( pos != std::string::npos){
00152         //only allow if we're the last key!
00153         if(ikey != keylist.size()-1){
00154           Message(EXCEPTION)<<"Configuration parameters with '.' are "
00155                             <<"only allowed last in a comma set!\n";
00156           throw std::invalid_argument(key);
00157         }
00158         //tell the next node to return after the first value is read
00159         sendsingle=true;
00160         //put back the rest of the "key" for the child to read
00161         in.seekg( in.tellg() - std::streampos(key.length()-pos - 1));
00162         //now we only care about the part before the '.'
00163         key = key.substr(0,pos);
00164       }
00165       
00166       //look for wildcards at the end ('*')
00167       if( key.at(key.length()-1) == '*'){
00168         key.resize( key.size() - 1 );
00169         int wildcardkeysfound = 0;
00170         for(int i=0; i<100; ++i){ //100 is totally arbitrary
00171           std::stringstream keystream;
00172           keystream<<key<<i;
00173           if(_parameters.find(keystream.str()) == _parameters.end())
00174             break;
00175           keylist.push_back(keystream.str());
00176           ++wildcardkeysfound;
00177         }
00178         //make sure there was at least one
00179         if(wildcardkeysfound==0){
00180           Message(EXCEPTION)<<"No keys matching wildcard '"<<key<<"*'!\n";
00181           throw std::invalid_argument(key+"*");
00182         }
00183         continue;
00184       }
00185       
00186       //now look for the actual parameter and read it
00187       ParMap::iterator mapit;
00188       mapit = _parameters.find(key);
00189       if( mapit == _parameters.end() ){
00190         //the key wasn't listed. throw an exception and abort
00191         Message e(EXCEPTION);
00192         e<<"Key "<<key<<" is not a valid parameter for ParameterList '"
00193          <<GetDefaultKey()<<"'"<<std::endl;
00194         throw std::invalid_argument(e.str());
00195         return in;
00196       }
00197       VParameterNode* child = (mapit->second);
00198       child->ReadFrom(in,sendsingle);
00199     }
00200     if(single) 
00201       return in;
00202   }
00203   return in;
00204 
00205 }
00206 
00207 std::ostream& ParameterList::WriteTo( std::ostream& out, bool showhelp,
00208                                       int indent) const
00209 {
00210   //if(_parameters.empty())
00211   //InitializeParameterList();
00212   std::stringstream dummy;
00213   dummy<<'\n';
00214   for(int i=0; i < indent; i++)
00215     dummy<<"  ";
00216   const std::string newline = dummy.str();
00217 
00218   //print an opening parenthesis to mark the beginning
00219   out<<"( "<<newline;
00220   ParMap::const_iterator mapit;
00221   mapit = _parameters.begin();
00222   //Loop over all the parameters in the map and pass the stream to them
00223   while( !out.fail() && mapit != _parameters.end() ){
00224     if(mapit->second->haswrite){
00225       int node_type = mapit->second->GetNodeType();
00226       if(showhelp) out<<newline<<"# "<<mapit->second->GetHelpText()<<newline;
00227       if(node_type == FUNCTION)
00228         out<<"#";
00229       out<<(mapit->first)<<" ";
00230       if(node_type == FUNCTION)
00231         out<<newline;
00232       mapit->second->WriteTo(out, showhelp, indent+1);
00233       out<<newline;
00234     }
00235     ++mapit;
00236   }
00237   out<<(showhelp ? newline : "")<<")" << (showhelp ? " #end list" : "");
00238   out.flush();
00239   return out;
00240 }
00241 
00242 int ParameterList::PrintHelp(const std::string& myname) const
00243 {
00244   // this function returns 1 to exit, 0 to print itself, and -n to go up n
00245   VParameterNode::PrintHelp(myname);
00246   std::cout<<"List of sub-parameters:\n";
00247   int parnumber=0;
00248   ParMap::const_iterator mapit; 
00249   for( mapit = _parameters.begin() ; mapit != _parameters.end(); ++mapit){
00250     std::cout<<" "<<std::left<<std::setw(5)<<std::setfill(' ')<<++parnumber
00251              <<(mapit->first)<<std::endl;
00252   }
00253   std::cout<<"\nEnter n) for more information about parameter n"
00254            <<"\n     -n) to go up n levels"
00255            <<"\n      0) to quit the help browser"<<std::endl;
00256            
00257   int response=0;
00258   std::cin >> response;
00259   if(response == 0)
00260     return 1;
00261   else if(response > (int)_parameters.size() ){
00262     std::cerr<<"The number you entered was too large!\n";
00263     return PrintHelp(myname);
00264   }
00265   else if(response > 0){
00266     mapit = _parameters.begin();
00267     for(int i=0; i < response-1; i++) ++mapit;
00268     response = (mapit->second)->PrintHelp(mapit->first);
00269   }
00270   //now response could be the user response or return from a sub-node
00271   if(response == 0)
00272     return PrintHelp(myname);
00273   if(response < 0)
00274     response++;
00275   
00276   return response;
00277 }
00278 
00279     
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on 20 Jun 2014 for daqman by  doxygen 1.6.1