4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief ProgramOptions non-inline non-template implementation */
31 #include "ProgramOptions.hh"
32 #include "ProgramOptions.ih"
35 #include <boost/algorithm/string/predicate.hpp>
36 #include <boost/format.hpp>
37 #include <senf/Utils/Range.hh>
38 #include "OverloadedCommand.hh"
40 //#include "ProgramOptions.mpp"
42 //-/////////////////////////////////////////////////////////////////////////////////////////////////
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
45 // senf::console::detail::ProgramOptionsSource::NonOptionContainer
47 prefix_ senf::console::detail::ProgramOptionsSource::NonOptionContainer::~NonOptionContainer()
50 //-/////////////////////////////////////////////////////////////////////////////////////////////////
51 // senf::console::detail::ProgramOptionsSource
53 prefix_ void senf::console::detail::ProgramOptionsSource::v_parse(RestrictedExecutor & executor)
59 char const ** argp (argv_+1);
61 for (; n; --n, ++argp) {
62 std::string arg (*argp);
64 for (; n; --n, ++argp)
65 parseNonOption(arg, executor);
68 else if (boost::algorithm::starts_with(arg, std::string("--")) && arg.size() > 2)
70 parseLongOption(arg.substr(2), executor);
72 catch (senf::ExceptionMixin & e) {
73 e << "\nwhile parsing command line option: " << arg;
76 else if (boost::algorithm::starts_with(arg, std::string("-")) && arg.size() > 1) {
77 for (std::string::size_type i (1); i<arg.size(); ++i) {
79 ShortOptions::iterator j (shortOptions_.find(opt));
80 if (j == shortOptions_.end())
81 throw SyntaxErrorException(
82 (boost::format("invalid short option '%c'") % opt).str());
84 if (j->second.withArg) {
85 if (i >= arg.size()-1) {
92 param = arg.substr(i+1);
95 std::string longOpt (j->second.longOpt);
96 if (! param.empty() ) {
100 if (boost::algorithm::starts_with(longOpt, std::string("--")))
101 longOpt = longOpt.substr(2);
103 parseLongOption(longOpt, executor);
105 catch (senf::ExceptionMixin & e) {
106 e << "\nwhile parsing command line option: -" << opt << ' ' << param;
112 parseNonOption(arg, executor);
117 senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const & arg,
118 RestrictedExecutor & executor)
120 std::string::size_type ix (arg.find('='));
121 std::string name (arg.substr(0,ix));
122 std::string value (ix==std::string::npos ? std::string() : arg.substr(ix+1));
124 typedef std::vector<Token> Path;
126 ParseCommandInfo cmd;
129 DirectoryNode::ptr cwd (executor.root().thisptr());
130 std::string::size_type b (0);
131 while (b < name.size()) {
132 std::string::size_type e (name.size());
133 for (;e != std::string::npos && e > b; e = name.rfind('-', e)) {
134 std::string key (name.substr(b,e-b));
135 if (! cwd->hasChild(key)) {
136 DirectoryNode::ChildrenRange completions (cwd->completions(key));
137 if (has_one_elt(completions))
138 key = completions.begin()->first;
144 path.push_back(WordToken(key));
146 cwd = cwd->getDirectory(key).thisptr();
151 if (e == std::string::npos || e <= b) {
152 // This will produce a correct error message later or will skip the node,
153 // if parsing is restricted to a subtree
154 path.push_back(WordToken(name.substr(b)));
160 // Here we check, whether the command
161 // - is an overloaded/parsed command
162 // - with a single overload
163 // - taking only a single argument
164 // - which consists of a single token
165 // If all these conditions are met, we pass the parameter value as a single WordToken
166 // otherwise we parse it using the config parser
168 GenericNode const & node (executor.getNode(cmd));
169 OverloadedCommandNode const * cmdnode (dynamic_cast<OverloadedCommandNode const *>(&node));
170 if (cmdnode && cmdnode->overloads().size() == 1) {
171 CommandOverload const & overload (**cmdnode->overloads().begin());
172 if (overload.numArguments() == 1) {
174 argdoc.singleToken = false;
175 overload.argumentDoc(0, argdoc);
176 if (argdoc.singleToken) {
177 cmd.addToken(WordToken(value));
182 parser_.parseArguments(value, cmd);
185 executor(executor.stream(), cmd);
187 catch (Executor::IgnoreCommandException &)
192 senf::console::detail::ProgramOptionsSource::parseNonOption(std::string const & arg,
193 RestrictedExecutor & executor)
196 throw SyntaxErrorException("invalid non-option argument");
197 nonOptions_->push_back(arg);
200 //-/////////////////////////////////////////////////////////////////////////////////////////////////
202 prefix_ void senf::console::parseOptions(int argc, char const ** argv, DirectoryNode & root)
204 ProgramOptions opts (argc, argv, root);
208 //-/////////////////////////////////////////////////////////////////////////////////////////////////
210 //#include "ProgramOptions.mpp"
216 // comment-column: 40
217 // c-file-style: "senf"
218 // indent-tabs-mode: nil
219 // ispell-local-dictionary: "american"
220 // compile-command: "scons -u test"