00001
00002
00003
00004
00005 #include "ConfigHandler.hh"
00006 #include "CommandSwitchFunctions.hh"
00007 #include "MessageHandler.hh"
00008 #include <iostream>
00009 #include <exception>
00010 #include <stdexcept>
00011
00012 #include <sys/ioctl.h>
00013 #include <stdio.h>
00014 #include <limits.h>
00015 #include <unistd.h>
00016 #include <fstream>
00017
00018 class ParamHelpPrinter{
00019 const VParameterNode* p;
00020 public:
00021 ParamHelpPrinter(const VParameterNode* node) : p(node){}
00022 int operator()(const char*){ p->PrintHelp(); exit(0); }
00023 };
00024
00025 int PrintProgramUsage(const char* dummy = "")
00026 {
00027 ConfigHandler::GetInstance()->PrintSwitches(true);
00028 return 0;
00029 }
00030
00031 int PrintAnnotatedConfig(const char* dummy = "")
00032 {
00033 MessageHandler::GetInstance()->End();
00034 ConfigHandler::GetInstance()->PrintSwitches(false,std::cout, true);
00035 std::cout<<"\n#Full sample configuration file:\n"<<std::endl;
00036 ConfigHandler::GetInstance()->WriteTo(std::cout,true,0);
00037 std::cout<<"\n\n#End sample config file"<<std::endl;
00038 exit(0);
00039 return 0;
00040 }
00041
00042 int NoOp(const char* dummy="") { return 0; }
00043
00044 ConfigHandler::ConfigHandler() :
00045 ParameterList("ConfigHandler","Global container for all parameters"),
00046 _program_usage(""), _program_description(""),
00047 _notes(), _default_cfg_file(), _saved_cfg()
00048 {
00049 AddCommandSwitch(' ',"cfg","Load global configuration data from <file>",
00050 CommandSwitch::LoadConfigFile(this),
00051 "file");
00052 AddCommandSwitch(' ',"no-cfg","Prevent loading of any default config file",
00053 NoOp);
00054 AddCommandSwitch(' ',"saved-config",
00055 "Load saved configuration from previous run from <file>",
00056 CommandSwitch::DefaultRead<std::string>(_saved_cfg),
00057 "file");
00058 AddCommandSwitch(' ',"show-parameters",
00059 "Interactively browse available configuration parameters",
00060 ParamHelpPrinter(this) );
00061 AddCommandSwitch('h',"help","Display this help page",
00062 PrintProgramUsage) ;
00063 AddCommandSwitch(' ',"print-options",
00064 "Print all config options with annotated description",
00065 PrintAnnotatedConfig );
00066
00067 RegisterParameter("notes",_notes, "Generic notes about this run, etc");
00068
00069
00070
00071
00072 _cfg_paths.clear();
00073
00074 _cfg_paths.push_back(".");
00075
00076 if( getenv("DAQMAN_CFGDIR") )
00077 _cfg_paths.push_back( getenv("DAQMAN_CFGDIR") );
00078
00079 char result[ PATH_MAX ];
00080 ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
00081 if(count > 0){
00082 std::string dirpart = std::string(result,count);
00083 if(dirpart.find_last_of('/') != std::string::npos)
00084 dirpart.erase(dirpart.find_last_of('/'));
00085 _cfg_paths.push_back( dirpart+"/../cfg");
00086 }
00087
00088 #ifdef DAQMANBUILDDIR
00089 _cfg_paths.push_back(std::string(DAQMANBUILDDIR)+"/cfg");
00090 #endif
00091
00092 }
00093
00094 ConfigHandler::~ConfigHandler()
00095 {
00096
00097 for(SwitchSet::iterator it = _switches.begin(); it != _switches.end(); it++){
00098 delete (*it);
00099 }
00100 }
00101
00102 std::string ConfigHandler::FindConfigFile(const std::string& fname)
00103 {
00104
00105 for(size_t i=0; i<_cfg_paths.size(); ++i){
00106 std::string filepath = _cfg_paths[i]+"/"+fname;
00107 Message(DEBUG)<<"Searching for file "<<fname<<" under path "
00108 <<filepath<<"...\n";
00109 std::ifstream test(filepath.c_str());
00110 if(test.is_open()){
00111 Message(INFO)<<"Found config file "<<fname<<" at "<<filepath<<"\n";
00112 return filepath;
00113 }
00114 }
00115
00116
00117 Message(ERROR)<<"Unable to find config file "<<fname<<" under search paths\n";
00118 return "";
00119 }
00120
00121 int ConfigHandler::RemoveCommandSwitch(char shortname,
00122 const std::string& longname){
00123
00124 for(SwitchSet::iterator it = _switches.begin(); it != _switches.end(); it++){
00125 if( (*it)->shortname == shortname && (*it)->longname == longname){
00126 delete (*it);
00127 _switches.erase(it);
00128 return 0;
00129 }
00130 }
00131 std::cerr<<"Unable to find switch "<<shortname<<","<<longname<<std::endl;
00132 return 1;
00133 }
00134
00135 void ConfigHandler::PrintSwitches(bool quit, std::ostream& out, bool escape)
00136 {
00137 std::string endline = "\n";
00138 if(escape) endline+="#";
00139
00140 out<<endline;
00141
00142 if(quit)
00143 MessageHandler::GetInstance()->End();
00144 if(_program_usage != "")
00145 out<<"Usage: "<<_program_usage<<endline;
00146 if(_program_description != "")
00147 out<<"Description: "<<_program_description<<endline;
00148
00149 size_t maxlong = 0;
00150 size_t maxpar = 0;
00151
00152
00153
00154 size_t termsize = 80;
00155
00156
00157
00158 for(SwitchSet::iterator it = _switches.begin(); it != _switches.end(); it++){
00159 maxlong = (maxlong > (*it)->longname.size() ?
00160 maxlong : (*it)->longname.size() );
00161 maxpar = (maxpar > (*it)->parameter.size() ?
00162 maxpar : (*it)->parameter.size() );
00163 }
00164 out<<"Available Command Line Options:"<<endline;
00165 for(SwitchSet::iterator it = _switches.begin(); it != _switches.end(); it++){
00166 VCommandSwitch* cmd = *it;
00167 out<<" ";
00168 if( cmd->shortname != ' ')
00169 out<<'-'<<cmd->shortname;
00170 else
00171 out<<" ";
00172
00173 if( cmd->shortname != ' ' && cmd->longname != "")
00174 out<<',';
00175 else
00176 out<<' ';
00177 if( cmd->longname != "" )
00178 out<<"--"<<cmd->longname;
00179 else
00180 out<<" ";
00181 for(size_t i=0; i < maxlong - cmd->longname.size(); i++)
00182 out<<' ';
00183 if( cmd->parameter != "" )
00184 out<<" <"<<cmd->parameter<<'>';
00185 else
00186 out<<" ";
00187 for(size_t i=0; i < maxpar - cmd->parameter.size(); i++)
00188 out<<' ';
00189 out<<" ";
00190
00191 int offset=1+2+1+2+maxlong+3+maxpar+2+2;
00192 std::string spaces;
00193 spaces.assign(offset,' ');
00194 size_t length=termsize-offset;
00195 size_t mypos = 0;
00196 while(cmd->helptext.size()-mypos > length ){
00197
00198 std::string chunk = cmd->helptext.substr(mypos, length);
00199 size_t spacepos = chunk.rfind(' ');
00200 if(spacepos == std::string::npos)
00201 break;
00202 out<<chunk.substr(0,spacepos)<<(escape ? "\n#":"\n")<<spaces;
00203 mypos += spacepos+1;
00204 }
00205 out<<cmd->helptext.substr(mypos)<<endline;
00206 }
00207 out<<std::endl;
00208 if(quit)
00209 exit(0);
00210 }
00211
00212 int ConfigHandler::ProcessCommandLine(int& argc, char** argv)
00213 {
00214 int status = 0;
00215 try{
00216
00217
00218 bool cfgswitchfound = false;
00219 bool skipcfgswitchfound = false;
00220 std::set<std::string> skipcfgargs;
00221 skipcfgargs.insert("--no-cfg");
00222 skipcfgargs.insert("-h");
00223 skipcfgargs.insert("--help");
00224
00225 for(int arg = 1; arg<argc; arg++){
00226 if(std::string(argv[arg]) == "--cfg"){
00227 cfgswitchfound = true;
00228 break;
00229 }
00230 if(skipcfgargs.find(argv[arg]) != skipcfgargs.end())
00231 skipcfgswitchfound = true;
00232 }
00233 if(!cfgswitchfound){
00234 if(_default_cfg_file != "" && !skipcfgswitchfound){
00235 Message(INFO)<<"No --cfg switch found; reading default cfg file "
00236 <<_default_cfg_file<<"...\n";
00237 status = CommandSwitch::LoadConfigFile(this)(_default_cfg_file.c_str());
00238 }
00239 else{
00240 Message(DEBUG)<<"No --cfg switch found and no default file specified; "
00241 <<"using compiled defaults.\n";
00242 }
00243 }
00244
00245 for(int arg = 1; arg<argc; arg++){
00246 if(status != 0){
00247 break;
00248
00249 }
00250 if( argv[arg][0] != '-' ){
00251
00252 for( int i=arg; i<argc; i++){
00253 _cmd_args.push_back(argv[i]);
00254 argv[1 + i - arg] = argv[i];
00255 }
00256
00257 argc = 1 + argc - arg;
00258 break;
00259
00260 }
00261
00262 if( argv[arg][1] == '-' ){
00263
00264 bool switchfound = false;
00265 std::string key(argv[arg]+2);
00266 for(SwitchSet::iterator it = _switches.begin(); it != _switches.end();
00267 it++){
00268 if( (*it)->longname != key)
00269 continue;
00270
00271 switchfound = true;
00272
00273 bool need_parameter = ((*it)->parameter != "");
00274 bool next_is_parameter = ( arg != argc-1 && argv[arg+1][0] != '-');
00275 if( !need_parameter ){
00276 status = (*it)->Process("");
00277 break;
00278 }
00279 else if( next_is_parameter){
00280 status = (*it)->Process(argv[++arg]);
00281 break;
00282 }
00283 else{
00284
00285 Message e(EXCEPTION);
00286 e <<"Switch --" << key
00287 <<" is missing required parameter "
00288 << (*it)->parameter<<std::endl;
00289 throw std::invalid_argument(e.str());
00290 }
00291 }
00292 if(!switchfound){
00293 Message e(EXCEPTION);
00294 e<<argv[arg]<<" is not a valid switch!\n";
00295 throw std::invalid_argument(e.str());
00296 }
00297 }
00298 else{
00299
00300 std::string shortkeys(argv[arg]+1);
00301 for(size_t i=0; i<shortkeys.size(); i++){
00302 bool switchfound = false;
00303 char key = shortkeys.at(i);
00304 for(SwitchSet::iterator it = _switches.begin();
00305 it != _switches.end(); it++){
00306 if( (*it)->shortname != key)
00307 continue;
00308 switchfound = true;
00309
00310 bool need_parameter = ((*it)->parameter != "");
00311 bool next_is_parameter = ( i == shortkeys.size() - 1 &&
00312 arg != argc-1 &&
00313 argv[arg+1][0] != '-' );
00314 if( !need_parameter ){
00315 status = (*it)->Process("");
00316 break;
00317 }
00318 else if( next_is_parameter){
00319 status = (*it)->Process(argv[++arg]);
00320 break;
00321 }
00322 else{
00323
00324 Message e(EXCEPTION);
00325 e <<"Switch -" << key
00326 <<" is missing required parameter "
00327 << (*it)->parameter<<std::endl;
00328 throw std::invalid_argument(e.str());
00329 }
00330 }
00331 if(!switchfound){
00332 Message e(EXCEPTION);
00333 e <<"-"<<key<<" is not a valid switch!\n";
00334 throw std::invalid_argument(e.str());
00335 }
00336 }
00337 }
00338 }
00339 }
00340 catch(std::exception& e){
00341 Message(EXCEPTION)<<"An error occurred processing command line arguments:\n"
00342 <<e.what()<<std::endl;
00343 PrintSwitches(true);
00344 }
00345
00346 if(status){
00347 Message(ERROR)<<"Problem encountered while processing command line\n";
00348 return status;
00349 }
00350
00351 argc = _cmd_args.size() + 1;
00352 MessageHandler::GetInstance()->UpdateThreshold();
00353 return 0;
00354 }
00355
00356 bool ConfigHandler::OrderCommandSwitchPointers::operator()
00357 (VCommandSwitch* a, VCommandSwitch* b )
00358 {
00359
00360
00361 char shorta = (a->shortname == ' ' ? a->longname.at(0) : a->shortname);
00362 char shortb = (b->shortname == ' ' ? b->longname.at(0) : b->shortname);
00363
00364
00365 if( shorta < shortb )
00366 return true;
00367 else if( shorta > shortb )
00368 return false;
00369 else {
00370
00371 if( a->longname < b->longname)
00372 return true;
00373 else
00374 return false;
00375 }
00376
00377 return false;
00378 }
00379