Move Console from Scheduler into Utils
[senf.git] / Utils / Console / ProgramOptions.cc
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief ProgramOptions non-inline non-template implementation */
25
26 #include "ProgramOptions.hh"
27 #include "ProgramOptions.ih"
28
29 // Custom includes
30 #include <boost/algorithm/string/predicate.hpp>
31 #include <boost/format.hpp>
32 #include "../../Utils/range.hh"
33
34 //#include "ProgramOptions.mpp"
35 #define prefix_
36 ///////////////////////////////cc.p////////////////////////////////////////
37
38 ///////////////////////////////////////////////////////////////////////////
39 // senf::console::detail::ProgramOptionsSource::NonOptionContainer
40
41 prefix_ senf::console::detail::ProgramOptionsSource::NonOptionContainer::~NonOptionContainer()
42 {}
43
44 ///////////////////////////////////////////////////////////////////////////
45 // senf::console::detail::ProgramOptionsSource
46
47 prefix_ void senf::console::detail::ProgramOptionsSource::v_parse(RestrictedExecutor & executor)
48 {
49     if (nonOptions_)
50         nonOptions_->clear();
51     if (argc_ <= 1)
52         return;
53     char const ** argp (argv_+1);
54     int n (argc_-1);
55     for (; n; --n, ++argp) {
56         std::string arg (*argp);
57         if (arg == "--") {
58             for (; n; --n, ++argp)
59                 parseNonOption(arg, executor);
60             break;
61         }
62         else if (boost::algorithm::starts_with(arg, std::string("--")) && arg.size() > 2)
63             try {
64                 parseLongOption(arg.substr(2), executor);
65             }
66             catch (senf::ExceptionMixin & e) {
67                 e << "\nwhile parsing command line option: " << arg;
68                 throw;
69             }
70         else if (boost::algorithm::starts_with(arg, std::string("-")) && arg.size() > 1) {
71             for (std::string::size_type i (1); i<arg.size(); ++i) {
72                 char opt (arg[i]);
73                 ShortOptions::iterator j (shortOptions_.find(opt));
74                 if (j == shortOptions_.end())
75                     throw SyntaxErrorException(
76                         (boost::format("invalid short option '%c'") % opt).str());
77                 std::string param;
78                 if (j->second.withArg) {
79                     if (i >= arg.size()-1) {
80                         if (n > 0) {
81                             param = *(++argp);
82                             --n;
83                         }
84                     }
85                     else 
86                         param = arg.substr(i+1);
87                     i = arg.size();
88                 }
89                 std::string longOpt (j->second.longOpt);
90                 if (! param.empty() ) {
91                     longOpt += "=";
92                     longOpt += param;
93                 }
94                 if (boost::algorithm::starts_with(longOpt, std::string("--")))
95                     longOpt = longOpt.substr(2);
96                 try {
97                     parseLongOption(longOpt, executor);
98                 }
99                 catch (senf::ExceptionMixin & e) {
100                     e << "\nwhile parsing command line option: -" << opt << ' ' << param;
101                     throw;
102                 }
103             }
104         }
105         else
106             parseNonOption(arg, executor);
107     }
108 }
109
110 prefix_ void
111 senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const & arg,
112                                                              RestrictedExecutor & executor)
113 {
114     std::string::size_type ix (arg.find('='));
115     std::string name (arg.substr(0,ix));
116     std::string value (ix==std::string::npos ? std::string() : arg.substr(ix+1));
117
118     typedef std::vector<Token> Path;
119
120     ParseCommandInfo cmd;
121     Path path;
122  
123     DirectoryNode::ptr cwd (executor.root().thisptr());
124     std::string::size_type b (0);
125     while (b < name.size()) {
126         std::string::size_type e (name.size());
127         for (;e != std::string::npos && e > b; e = name.rfind('-', e)) {
128             std::string key (name.substr(b,e-b));
129             if (! cwd->hasChild(key)) {
130                 DirectoryNode::ChildrenRange completions (cwd->completions(key));
131                 if (has_one_elt(completions))
132                     key = completions.begin()->first;
133                 else {
134                     e -= 1;
135                     continue;
136                 }
137             }
138             path.push_back(WordToken(key));
139             if (e < name.size())
140                 cwd = cwd->getDirectory(key).thisptr();
141             b = e+1;
142             e = b+1;
143             break;
144         }
145         if (e == std::string::npos || e <= b) {
146             // This will produce a correct error message later or will skip the node,
147             // if parsing is restricted to a subtree
148             path.push_back(WordToken(name.substr(b)));
149             b = name.size();
150         }
151     }
152
153     cmd.command(path);
154     parser_.parseArguments(value, cmd);
155     executor(std::cerr, cmd);
156 }
157
158 prefix_ void
159 senf::console::detail::ProgramOptionsSource::parseNonOption(std::string const & arg,
160                                                             RestrictedExecutor & executor)
161 {
162     if (! nonOptions_)
163         throw SyntaxErrorException("invalid non-option argument");
164     nonOptions_->push_back(arg);
165 }
166
167 ///////////////////////////////////////////////////////////////////////////
168
169 prefix_ void senf::console::parseOptions(int argc, char const ** argv, DirectoryNode & root)
170 {
171     ProgramOptions opts (argc, argv, root);
172     opts.parse();
173 }
174
175 ///////////////////////////////cc.e////////////////////////////////////////
176 #undef prefix_
177 //#include "ProgramOptions.mpp"
178
179 \f
180 // Local Variables:
181 // mode: c++
182 // fill-column: 100
183 // comment-column: 40
184 // c-file-style: "senf"
185 // indent-tabs-mode: nil
186 // ispell-local-dictionary: "american"
187 // compile-command: "scons -u test"
188 // End: