Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ProgramOptions.cc

Go to the documentation of this file.
00001 // $Id: ProgramOptions.cc 1742 2010-11-04 14:51:56Z g0dil $
00002 //
00003 // Copyright (C) 2008
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "ProgramOptions.hh"
00027 #include "ProgramOptions.ih"
00028 
00029 // Custom includes
00030 #include <boost/algorithm/string/predicate.hpp>
00031 #include <boost/format.hpp>
00032 #include <senf/Utils/Range.hh>
00033 #include "OverloadedCommand.hh"
00034 
00035 //#include "ProgramOptions.mpp"
00036 #define prefix_
00037 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00038 
00039 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00040 // senf::console::detail::ProgramOptionsSource::NonOptionContainer
00041 
00042 prefix_ senf::console::detail::ProgramOptionsSource::NonOptionContainer::~NonOptionContainer()
00043 {}
00044 
00045 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00046 // senf::console::detail::ProgramOptionsSource
00047 
00048 prefix_ void senf::console::detail::ProgramOptionsSource::v_parse(RestrictedExecutor & executor)
00049 {
00050     if (nonOptions_)
00051         nonOptions_->clear();
00052     if (argc_ <= 1)
00053         return;
00054     char const ** argp (argv_+1);
00055     int n (argc_-1);
00056     for (; n; --n, ++argp) {
00057         std::string arg (*argp);
00058         if (arg == "--") {
00059             for (; n; --n, ++argp)
00060                 parseNonOption(arg, executor);
00061             break;
00062         }
00063         else if (boost::algorithm::starts_with(arg, std::string("--")) && arg.size() > 2)
00064             try {
00065                 parseLongOption(arg.substr(2), executor);
00066             }
00067             catch (senf::ExceptionMixin & e) {
00068                 e << "\nwhile parsing command line option: " << arg;
00069                 throw;
00070             }
00071         else if (boost::algorithm::starts_with(arg, std::string("-")) && arg.size() > 1) {
00072             for (std::string::size_type i (1); i<arg.size(); ++i) {
00073                 char opt (arg[i]);
00074                 ShortOptions::iterator j (shortOptions_.find(opt));
00075                 if (j == shortOptions_.end())
00076                     throw SyntaxErrorException(
00077                         (boost::format("invalid short option '%c'") % opt).str());
00078                 std::string param;
00079                 if (j->second.withArg) {
00080                     if (i >= arg.size()-1) {
00081                         if (n > 0) {
00082                             param = *(++argp);
00083                             --n;
00084                         }
00085                     }
00086                     else
00087                         param = arg.substr(i+1);
00088                     i = arg.size();
00089                 }
00090                 std::string longOpt (j->second.longOpt);
00091                 if (! param.empty() ) {
00092                     longOpt += "=";
00093                     longOpt += param;
00094                 }
00095                 if (boost::algorithm::starts_with(longOpt, std::string("--")))
00096                     longOpt = longOpt.substr(2);
00097                 try {
00098                     parseLongOption(longOpt, executor);
00099                 }
00100                 catch (senf::ExceptionMixin & e) {
00101                     e << "\nwhile parsing command line option: -" << opt << ' ' << param;
00102                     throw;
00103                 }
00104             }
00105         }
00106         else
00107             parseNonOption(arg, executor);
00108     }
00109 }
00110 
00111 prefix_ void
00112 senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const & arg,
00113                                                              RestrictedExecutor & executor)
00114 {
00115     std::string::size_type ix (arg.find('='));
00116     std::string name (arg.substr(0,ix));
00117     std::string value (ix==std::string::npos ? std::string() : arg.substr(ix+1));
00118 
00119     typedef std::vector<Token> Path;
00120 
00121     ParseCommandInfo cmd;
00122     Path path;
00123 
00124     DirectoryNode::ptr cwd (executor.root().thisptr());
00125     std::string::size_type b (0);
00126     while (b < name.size()) {
00127         std::string::size_type e (name.size());
00128         for (;e != std::string::npos && e > b; e = name.rfind('-', e)) {
00129             std::string key (name.substr(b,e-b));
00130             if (! cwd->hasChild(key)) {
00131                 DirectoryNode::ChildrenRange completions (cwd->completions(key));
00132                 if (has_one_elt(completions))
00133                     key = completions.begin()->first;
00134                 else {
00135                     e -= 1;
00136                     continue;
00137                 }
00138             }
00139             path.push_back(WordToken(key));
00140             if (e < name.size())
00141                 cwd = cwd->getDirectory(key).thisptr();
00142             b = e+1;
00143             e = b+1;
00144             break;
00145         }
00146         if (e == std::string::npos || e <= b) {
00147             // This will produce a correct error message later or will skip the node,
00148             // if parsing is restricted to a subtree
00149             path.push_back(WordToken(name.substr(b)));
00150             b = name.size();
00151         }
00152     }
00153 
00154     cmd.command(path);
00155     // Here we check, whether the command
00156     // - is an overloaded/parsed command
00157     // - with a single overload
00158     // - taking only a single argument
00159     // - which consists of a single token
00160     // If all these conditions are met, we pass the parameter value as a single WordToken
00161     // otherwise we parse it using the config parser
00162     try {
00163         GenericNode const & node (executor.getNode(cmd));
00164         OverloadedCommandNode const * cmdnode (dynamic_cast<OverloadedCommandNode const *>(&node));
00165         if (cmdnode && cmdnode->overloads().size() == 1) {
00166             CommandOverload const & overload (**cmdnode->overloads().begin());
00167             if (overload.numArguments() == 1) {
00168                 ArgumentDoc argdoc;
00169                 argdoc.singleToken = false;
00170                 overload.argumentDoc(0, argdoc);
00171                 if (argdoc.singleToken) {
00172                     cmd.addToken(WordToken(value));
00173                     goto execute;
00174                 }
00175             }
00176         } /* else */ {
00177             parser_.parseArguments(value, cmd);
00178         }
00179     execute:
00180         executor(executor.stream(), cmd);
00181     }
00182     catch (Executor::IgnoreCommandException &)
00183     {}
00184 }
00185 
00186 prefix_ void
00187 senf::console::detail::ProgramOptionsSource::parseNonOption(std::string const & arg,
00188                                                             RestrictedExecutor & executor)
00189 {
00190     if (! nonOptions_)
00191         throw SyntaxErrorException("invalid non-option argument");
00192     nonOptions_->push_back(arg);
00193 }
00194 
00195 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00196 
00197 prefix_ void senf::console::parseOptions(int argc, char const ** argv, DirectoryNode & root)
00198 {
00199     ProgramOptions opts (argc, argv, root);
00200     opts.parse();
00201 }
00202 
00203 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00204 #undef prefix_
00205 //#include "ProgramOptions.mpp"
00206 
00207 
00208 // Local Variables:
00209 // mode: c++
00210 // fill-column: 100
00211 // comment-column: 40
00212 // c-file-style: "senf"
00213 // indent-tabs-mode: nil
00214 // ispell-local-dictionary: "american"
00215 // compile-command: "scons -u test"
00216 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research