GetoptParser.cpp
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of FZIs ic_workspace.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00012 //
00013 // -- END LICENSE BLOCK ------------------------------------------------
00014 
00015 //----------------------------------------------------------------------
00021 //----------------------------------------------------------------------
00022 #include <iostream>
00023 #include <stdlib.h>
00024 #include <boost/regex.hpp>
00025 #include <boost/foreach.hpp>
00026 
00027 #include "icl_core/List.h"
00028 #include "icl_core_config/GetoptParser.h"
00029 
00030 namespace icl_core {
00031 namespace config {
00032 
00033 Getopt& Getopt::instance()
00034 {
00035   static Getopt instance;
00036   return instance;
00037 }
00038 
00039 void Getopt::activateExtraCmdParams(const icl_core::String& delimiter)
00040 {
00041   m_extra_cmd_param_activated = true;
00042   m_extra_cmd_param_delimiter = delimiter;
00043 }
00044 
00045 void Getopt::addParameter(const GetoptParameter& parameter)
00046 {
00047   if (parameter.isPrefixOption())
00048   {
00049     m_prefix_parameters.insert(std::make_pair(parameter.option(), parameter));
00050     if (parameter.shortOption() != "")
00051     {
00052       m_short_prefix_parameters.insert(std::make_pair(parameter.shortOption(), parameter));
00053     }
00054   }
00055   else
00056   {
00057     m_parameters.insert(std::make_pair(parameter.option(), parameter));
00058     if (parameter.shortOption() != "")
00059     {
00060       m_short_parameters.insert(std::make_pair(parameter.shortOption(), parameter));
00061     }
00062   }
00063 }
00064 
00065 void Getopt::addParameter(const GetoptParameterList& parameters)
00066 {
00067   for (GetoptParameterList::const_iterator opt_it = parameters.begin();
00068        opt_it != parameters.end(); ++opt_it)
00069   {
00070     addParameter(*opt_it);
00071   }
00072 }
00073 
00074 void Getopt::addParameter(const GetoptPositionalParameter &parameter)
00075 {
00076   if (parameter.isOptional())
00077   {
00078     m_optional_positional_parameters.push_back(parameter);
00079   }
00080   else
00081   {
00082     m_required_positional_parameters.push_back(parameter);
00083   }
00084 }
00085 
00086 void Getopt::addParameter(const GetoptPositionalParameterList &parameters)
00087 {
00088   for (GetoptPositionalParameterList::const_iterator opt_it = parameters.begin();
00089        opt_it != parameters.end(); ++opt_it)
00090   {
00091     addParameter(*opt_it);
00092   }
00093 }
00094 
00095 bool Getopt::initialize(int& argc, char *argv[], bool remove_read_arguments)
00096 {
00097   return initialize(argc, argv, remove_read_arguments ? eCLC_Cleanup : eCLC_None, ePRC_Strict);
00098 }
00099 
00100 bool Getopt::initialize(int& argc, char *argv[], CommandLineCleaning cleanup,
00101                         ParameterRegistrationCheck registration_check)
00102 {
00103   if (argc == 0)
00104   {
00105     return false;
00106   }
00107 
00108   if (isInitialized())
00109   {
00110     std::cerr << "GETOPT WARNING: The commandline option framework is already initialized!" << std::endl;
00111     return true;
00112   }
00113 
00114   // Store the full argc and argv
00115   m_argc = argc;
00116   m_argv = argv;
00117 
00118 
00119   // Store the program name.
00120   m_program_name = argv[0];
00121 
00122   // Store all parameters in a temporary list.
00123   icl_core::List<icl_core::String> arguments;
00124   for (int index = 1; index < argc; ++index)
00125   {
00126     arguments.push_back(argv[index]);
00127   }
00128 
00129   // Scan the commandline parameters and check for
00130   // registered options.
00131   size_t positional_parameters_counter = 0;
00132   bool extra_cmd_params_reached = false;
00133   boost::regex long_opt_regex("--([^-][^=]*)(=(.*))?");
00134   boost::regex short_opt_regex("-([^-].*)");
00135   boost::smatch mres;
00136   for (icl_core::List<icl_core::String>::const_iterator arg_it = arguments.begin();
00137        arg_it != arguments.end(); ++arg_it)
00138   {
00139     if (extra_cmd_params_reached)
00140     {
00141       m_extra_cmd_param.push_back(*arg_it);
00142     }
00143     else if (boost::regex_match(*arg_it, mres, long_opt_regex))
00144     {
00145       // Found a long option parameter!
00146       icl_core::String name = mres[1];
00147       ParameterMap::const_iterator find_it = m_parameters.find(name);
00148       if (find_it != m_parameters.end())
00149       {
00150         if (find_it->second.hasValue())
00151         {
00152           // According to the regular expression the value has to be
00153           // the 3rd (and last) match result.
00154           if (mres.size() == 4)
00155           {
00156             m_param_opt[name] = mres[3];
00157           }
00158           else
00159           {
00160             std::cerr << "Found option " << *arg_it << " but the value is missing." << std::endl;
00161             printHelp();
00162             return false;
00163           }
00164         }
00165         else
00166         {
00167           m_param_opt[name] = "yes";
00168         }
00169       }
00170       else
00171       {
00172         // Parameter not found in the list of configured parameters.
00173         // Check if a matching prefix option has been registered.
00174         bool found = false;
00175         boost::smatch prefix_res;
00176         for (ParameterMap::const_iterator prefix_it = m_prefix_parameters.begin();
00177              !found && prefix_it != m_prefix_parameters.end(); ++prefix_it)
00178         {
00179           if (boost::regex_match(name, prefix_res, boost::regex(prefix_it->first + "(.*)")))
00180           {
00181             found = true;
00182 
00183             if (prefix_it->second.hasValue())
00184             {
00185               if (mres.size() == 4)
00186               {
00187                 m_prefix_param_opt[prefix_it->first].push_back(KeyValue(prefix_res[1], mres[3]));
00188               }
00189               else
00190               {
00191                 std::cerr << "Found prefix option " << name << " but the value is missing." << std::endl;
00192                 printHelp();
00193                 return false;
00194               }
00195             }
00196             else
00197             {
00198               m_prefix_param_opt[prefix_it->first].push_back(KeyValue(prefix_res[1], "yes"));
00199             }
00200           }
00201         }
00202 
00203         // Also not a prefix option!
00204         if (!found)
00205         {
00206           if (registration_check == ePRC_Strict)
00207           {
00208             std::cerr << "Found unknown option " << *arg_it << "." << std::endl;
00209             printHelp();
00210             return false;
00211           }
00212           else
00213           {
00214             m_param_non_opt.push_back(*arg_it);
00215           }
00216         }
00217       }
00218     }
00219     else if (boost::regex_match(*arg_it, mres, short_opt_regex))
00220     {
00221       // Found a short option parameter!
00222       icl_core::String name = mres[1];
00223       ParameterMap::const_iterator find_it = m_short_parameters.find(name);
00224       if (find_it != m_short_parameters.end())
00225       {
00226         if (find_it->second.hasValue())
00227         {
00228           // The value is the next commandline argument.
00229           ++arg_it;
00230           if (arg_it == arguments.end())
00231           {
00232             std::cerr << "Found option -" << name << " but the value is missing." << std::endl;
00233             printHelp();
00234             return false;
00235           }
00236           else
00237           {
00238             m_param_opt[find_it->second.option()] = *arg_it;
00239           }
00240         }
00241         else
00242         {
00243           m_param_opt[find_it->second.option()] = "yes";
00244         }
00245       }
00246       else
00247       {
00248         // Parameter not found in the list of configured parameters.
00249         // Check if a matching prefix option has been registered.
00250         bool found = false;
00251         boost::smatch prefix_res;
00252         for (ParameterMap::const_iterator prefix_it = m_short_prefix_parameters.begin();
00253              !found && prefix_it != m_short_prefix_parameters.end(); ++prefix_it)
00254         {
00255           if (boost::regex_match(name, prefix_res, boost::regex(prefix_it->first + "(.*)")))
00256           {
00257             found = true;
00258 
00259             if (prefix_it->second.hasValue())
00260             {
00261               // The value is the next commandline argument.
00262               ++arg_it;
00263               if (arg_it == arguments.end())
00264               {
00265                 std::cerr << "Found prefix option " << name << " but the value is missing." << std::endl;
00266                 printHelp();
00267                 return false;
00268               }
00269               else
00270               {
00271                 m_prefix_param_opt[prefix_it->second.option()].push_back(KeyValue(prefix_res[1], *arg_it));
00272               }
00273             }
00274             else
00275             {
00276               m_prefix_param_opt[prefix_it->second.option()].push_back(KeyValue(prefix_res[1], "yes"));
00277             }
00278           }
00279         }
00280 
00281         // Also not a prefix option!
00282         if (!found)
00283         {
00284           if (registration_check == ePRC_Strict)
00285           {
00286             std::cerr << "Found unknown option " << *arg_it << "." << std::endl;
00287             printHelp();
00288             return false;
00289           }
00290           else
00291           {
00292             m_param_non_opt.push_back(*arg_it);
00293           }
00294         }
00295       }
00296     }
00297     else if (m_extra_cmd_param_activated && *arg_it == m_extra_cmd_param_delimiter)
00298     {
00299       extra_cmd_params_reached = true;
00300     }
00301     else if (positional_parameters_counter < m_required_positional_parameters.size())
00302     {
00303       // Found a required positional parameter
00304       const GetoptPositionalParameter& param = m_required_positional_parameters[positional_parameters_counter];
00305       m_param_opt[param.name()] = *arg_it;
00306       positional_parameters_counter++;
00307     }
00308     else if (positional_parameters_counter < m_required_positional_parameters.size() + m_optional_positional_parameters.size())
00309     {
00310       // Found an optional positional parameter
00311       const GetoptPositionalParameter& param = m_optional_positional_parameters[positional_parameters_counter - m_required_positional_parameters.size()];
00312       m_param_opt[param.name()] = *arg_it;
00313       positional_parameters_counter++;
00314     }
00315     else if (positional_parameters_counter >= m_required_positional_parameters.size() + m_optional_positional_parameters.size())
00316     {
00321 //      if (registration_check == ePRC_Strict)
00322 //      {
00323 //        std::cerr << "Found unknown positional parameter \"" << *arg_it << "\" and registration_check is ePRC_Strict. Aborting." << std::endl;
00324 //        printHelp();
00325 //        return false;
00326 //      }
00327 //      else
00328       {
00329         m_param_non_opt.push_back(*arg_it);
00330       }
00331     }
00332   }
00333 
00334   // Check if all required positional parameters are given
00335   if (positional_parameters_counter < m_required_positional_parameters.size())
00336   {
00337     std::cerr << "Not all required parameters are given. Aborting." << std::endl;
00338     printHelp();
00339     exit(0);
00340   }
00341 
00342   // Check if the help text has to be printed.
00343   if (m_param_opt.find("help") != m_param_opt.end())
00344   {
00345     printHelp();
00346     exit(0);
00347   }
00348 
00349   // Remove all option parameters from the "real" commandline.
00350   if (cleanup == eCLC_Cleanup)
00351   {
00352     int check = 1;
00353     while (check < argc)
00354     {
00355       icl_core::Vector<icl_core::String>::const_iterator find_it =
00356         std::find(m_param_non_opt.begin(), m_param_non_opt.end(), icl_core::String(argv[check]));
00357       if (find_it == m_param_non_opt.end())
00358       {
00359         for (int move = check + 1; move < argc; ++move)
00360         {
00361           argv[move - 1] = argv[move];
00362         }
00363         --argc;
00364       }
00365       else
00366       {
00367         ++check;
00368       }
00369     }
00370   }
00371 
00372   return true;
00373 }
00374 
00375 int& Getopt::argc()
00376 {
00377   return m_argc;
00378 }
00379 
00380 char **Getopt::argv() const
00381 {
00382   return m_argv;
00383 }
00384 
00385 icl_core::String Getopt::extraCmdParam(size_t index) const
00386 {
00387   return m_extra_cmd_param[index];
00388 }
00389 
00390 size_t Getopt::extraCmdParamCount() const
00391 {
00392   return m_extra_cmd_param.size();
00393 }
00394 
00395 icl_core::String Getopt::paramOpt(const icl_core::String& name) const
00396 {
00397   icl_core::Map<icl_core::String, icl_core::String>::const_iterator find_it = m_param_opt.find(name);
00398   if (find_it == m_param_opt.end())
00399   {
00400     return "";
00401   }
00402   else
00403   {
00404     return find_it->second;
00405   }
00406 }
00407 
00408 bool Getopt::paramOptPresent(const icl_core::String& name) const
00409 {
00410   return m_param_opt.find(name) != m_param_opt.end();
00411 }
00412 
00413 Getopt::KeyValueList Getopt::paramPrefixOpt(const icl_core::String& prefix) const
00414 {
00415   icl_core::Map<icl_core::String, KeyValueList>::const_iterator find_it = m_prefix_param_opt.find(prefix);
00416   if (find_it == m_prefix_param_opt.end())
00417   {
00418     return KeyValueList();
00419   }
00420   else
00421   {
00422     return find_it->second;
00423   }
00424 }
00425 
00426 bool Getopt::paramPrefixOptPresent(const icl_core::String& prefix) const
00427 {
00428   return m_prefix_param_opt.find(prefix) != m_prefix_param_opt.end();
00429 }
00430 
00431 icl_core::String Getopt::paramNonOpt(size_t index) const
00432 {
00433   if (index < m_param_non_opt.size())
00434   {
00435     return m_param_non_opt.at(index);
00436   }
00437   else
00438   {
00439     return "";
00440   }
00441 }
00442 
00443 size_t Getopt::paramNonOptCount() const
00444 {
00445   return m_param_non_opt.size();
00446 }
00447 
00448 icl_core::String Getopt::programName() const
00449 {
00450   return m_program_name;
00451 }
00452 
00453 icl_core::String Getopt::programVersion() const
00454 {
00455   return m_program_version;
00456 }
00457 
00458 void Getopt::setProgramVersion(icl_core::String const & version)
00459 {
00460   m_program_version = version;
00461 }
00462 
00463 icl_core::String Getopt::programDescription() const
00464 {
00465   return m_program_description;
00466 }
00467 
00468 void Getopt::setProgramDescription(icl_core::String const & description)
00469 {
00470   m_program_description = description;
00471 }
00472 
00473 void Getopt::printHelp() const
00474 {
00475   // prepare list of all positional parameters
00476   GetoptPositionalParameterList positional_parameters = m_required_positional_parameters;
00477   std::copy(m_optional_positional_parameters.begin(), m_optional_positional_parameters.end(), std::back_inserter(positional_parameters));
00478 
00479   std::cerr << programName();
00480   if (programVersion() != "")
00481   {
00482     std::cerr << " (version " << programVersion() << ")";
00483   }
00484   std::cerr << std::endl << std::endl;
00485 
00486   std::cerr << "Usage: ";
00487   std::cerr << programName();
00488 
00489   std::cerr << " [OPTIONS...]";
00490 
00491   BOOST_FOREACH(const GetoptPositionalParameter param, positional_parameters)
00492   {
00493     if (param.isOptional())
00494     {
00495       std::cerr  << " [<" << param.name() << ">]";
00496     }
00497     else
00498     {
00499       std::cerr  << " <" << param.name() << ">";
00500     }
00501   }
00502 
00503   std::cerr << std::endl << std::endl << programDescription() << std::endl << std::endl;
00504 
00505   if (positional_parameters.size() > 0 )
00506   {
00507     std::cerr << "Positional Parameters:" << std::endl;
00508 
00509     BOOST_FOREACH(const GetoptPositionalParameter param, positional_parameters)
00510     {
00511       std::cerr << "  <" << param.name() << ">" << ":" << std::endl << "\t"
00512                 << boost::regex_replace(param.help(), boost::regex("\\n"), "\n\t")
00513                 << std::endl;
00514     }
00515     std::cerr << std::endl;
00516   }
00517 
00518   for (int i=0; i<2; ++i)
00519   {
00520     std::cerr << (i == 0 ? "Generic options:" : "Options:") << std::endl;
00521     for (ParameterMap::const_iterator it = m_parameters.begin(); it != m_parameters.end(); ++it)
00522     {
00523       bool const is_generic =
00524           it->second.option() == "configfile"  ||
00525           it->second.option() == "dump-config" ||
00526           it->second.option() == "help"        ||
00527           it->second.option() == "log-level"   ||
00528           it->second.option() == "quick-debug";
00529       if (!i==is_generic)
00530       {
00531         std::cerr << "  ";
00532         // Short option.
00533         if (it->second.shortOption() != "")
00534         {
00535           std::cerr << "-" << it->second.shortOption();
00536           if (it->second.hasValue())
00537           {
00538             std::cerr << " <value>";
00539           }
00540           std::cerr << ", ";
00541         }
00542 
00543         // Long option.
00544         std::cerr << "--" << it->second.option();
00545         if (it->second.hasValue())
00546         {
00547           std::cerr << "=<value>";
00548         }
00549 
00550         // Help text
00551         std::cerr << ":" << std::endl << "\t"
00552                   << boost::regex_replace(it->second.help(), boost::regex("\\n"), "\n\t")
00553                   << std::endl;
00554       }
00555     }
00556     std::cerr << std::endl;
00557   }
00558 }
00559 
00561 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00562 
00566 Getopt& Getopt::Instance()
00567 {
00568   return instance();
00569 }
00570 
00574 void Getopt::ActivateExtraCmdParams(const icl_core::String& delimiter)
00575 {
00576   activateExtraCmdParams(delimiter);
00577 }
00578 
00582 void Getopt::AddParameter(const GetoptParameter& parameter)
00583 {
00584   addParameter(parameter);
00585 }
00586 
00590 void Getopt::AddParameter(const GetoptParameterList& parameters)
00591 {
00592   addParameter(parameters);
00593 }
00594 
00598 bool Getopt::Initialize(int& argc, char *argv[], bool remove_read_arguments)
00599 {
00600   return initialize(argc, argv, remove_read_arguments);
00601 }
00602 
00606 bool Getopt::Initialize(int& argc, char *argv[],
00607                         CommandLineCleaning cleanup,
00608                         ParameterRegistrationCheck registration_check)
00609 {
00610   return initialize(argc, argv, cleanup, registration_check);
00611 }
00612 
00616 bool Getopt::IsInitialized() const
00617 {
00618   return isInitialized();
00619 }
00620 
00624 icl_core::String Getopt::ExtraCmdParam(size_t index) const
00625 {
00626   return extraCmdParam(index);
00627 }
00628 
00632 size_t Getopt::ExtraCmdParamCount() const
00633 {
00634   return extraCmdParamCount();
00635 }
00636 
00640 icl_core::String Getopt::ParamOpt(const icl_core::String& name) const
00641 {
00642   return paramOpt(name);
00643 }
00644 
00648 bool Getopt::ParamOptPresent(const icl_core::String& name) const
00649 {
00650   return paramOptPresent(name);
00651 }
00652 
00656 Getopt::KeyValueList Getopt::ParamPrefixOpt(const icl_core::String& prefix) const
00657 {
00658   return paramPrefixOpt(prefix);
00659 }
00660 
00664 bool Getopt::ParamPrefixOptPresent(const icl_core::String& prefix) const
00665 {
00666   return paramPrefixOptPresent(prefix);
00667 }
00668 
00672 icl_core::String Getopt::ParamNonOpt(size_t index) const
00673 {
00674   return paramNonOpt(index);
00675 }
00676 
00680 size_t Getopt::ParamNonOptCount() const
00681 {
00682   return paramNonOptCount();
00683 }
00684 
00688 icl_core::String Getopt::ProgramName() const
00689 {
00690   return programName();
00691 }
00692 
00696 void Getopt::PrintHelp() const
00697 {
00698   printHelp();
00699 }
00700 
00701 #endif
00702 
00703 
00704 Getopt::Getopt()
00705   : m_extra_cmd_param_activated(false),
00706     m_initialized(false)
00707 {
00708   addParameter(GetoptParameter("help", "h", "Print commandline help."));
00709 }
00710 
00711 }
00712 }


fzi_icl_core
Author(s):
autogenerated on Thu Jun 6 2019 20:22:23