Port SENF to compile against boost-1.35
[senf.git] / Scheduler / Console / Executor.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 Executor non-inline non-template implementation */
25
26 #include "Executor.hh"
27 //#include "Executor.ih"
28
29 // Custom includes
30 #include <boost/utility.hpp>
31 #include <boost/range/iterator_range.hpp>
32 #include <boost/bind.hpp>
33 #include "../../Utils/senfassert.hh"
34 #include "../../Utils/Range.hh"
35 #include "../../Utils/String.hh"
36 #include "../../Utils/range.hh"
37
38 //#include "Executor.mpp"
39 #define prefix_
40 ///////////////////////////////cc.p////////////////////////////////////////
41
42 namespace {
43
44     struct TraverseTokens {
45         typedef std::string const & result_type;
46         result_type operator()(senf::console::Token const & token) const {
47             return token.value();
48         }
49     };
50     
51 }
52
53 ///////////////////////////////////////////////////////////////////////////
54 // senf::console::Executor
55
56 prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
57     const
58 {
59     SENF_ASSERT( ! cwd_.empty() );
60     while (cwd_.size()>1 && (cwd_.back().expired() || ! cwd_.back().lock()->active()))
61         cwd_.pop_back();
62     return * cwd_.back().lock();
63 }
64
65 prefix_ std::string senf::console::Executor::cwdPath()
66     const
67 {
68     if (skipping())
69         return "";
70     return "/" + senf::stringJoin(
71         senf::make_transform_range(
72             boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
73             boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))),
74         "/" );
75 }
76
77 prefix_ void senf::console::Executor::execute(std::ostream & output,
78                                               ParseCommandInfo const & command)
79 {
80     SENF_LOG(( "Executing: " << command ));
81
82     if (! skipping())
83         (void) cwd(); // Prune the cwd path of expired entries
84
85     try {
86         switch(command.builtin()) {
87         case ParseCommandInfo::NoBuiltin : 
88             if (skipping())
89                 return;
90             exec(output, command);
91             break;
92
93         case ParseCommandInfo::BuiltinCD :
94             if (skipping())
95                 break;
96             try {
97                 // The parser ensures, we have exactly one argument
98                 cd(*command.arguments().begin());
99             }
100             catch (IgnoreCommandException &) {
101                 throw SyntaxErrorException(
102                     "'cd' cannot be skipped (don't use 'cd' in conf-files)");
103             }
104             break;
105             
106         case ParseCommandInfo::BuiltinLS :
107             if (skipping())
108                 break;
109             // The parser ensures, we have either one or no argument
110             ls( output,
111                 command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
112             break;
113
114         case ParseCommandInfo::BuiltinPUSHD :
115             // The parser ensures, we have exactly one argument
116             pushd( *command.arguments().begin() );
117             break;
118             
119         case ParseCommandInfo::BuiltinPOPD :
120             // The parser ensures, we have no arguments
121             popd();
122             break;
123             
124         case ParseCommandInfo::BuiltinEXIT :
125             if (skipping())
126                 break;
127             // The parser ensures, we have no arguments
128             exit();
129             break;
130
131         case ParseCommandInfo::BuiltinHELP :
132             if (skipping())
133                 break;
134             // The parser ensures, we have either one or no arguments
135             help( output,
136                   command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
137             break;
138
139         }
140     }
141     catch (InvalidPathException &) {
142         throw SyntaxErrorException("invalid path");
143     }
144     catch (InvalidDirectoryException &) {
145         throw SyntaxErrorException("invalid directory");
146     }
147     catch (InvalidCommandException &) {
148         throw SyntaxErrorException("invalid command");
149     }
150     catch (IgnoreCommandException &) {}
151 }
152
153 prefix_ void senf::console::Executor::exec(std::ostream & output,
154                                            ParseCommandInfo const & command)
155 {
156     GenericNode & node ( traverseNode(command.commandPath()) );
157     DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
158     if ( dir ) {
159         if (autocd_ && command.tokens().empty()) {
160             cd( boost::make_iterator_range(
161                     command.commandPath().begin(),
162                     command.commandPath().end()) );
163         } else
164             throw InvalidCommandException();
165     } else {
166         dynamic_cast<CommandNode &>(node)(output, command);
167     }
168 }
169
170
171 prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir)
172 {
173     if (dir.size() == 1 && *dir.begin() == WordToken("-")) {
174         cwd_.swap(oldCwd_);
175         (void) cwd(); // Prune any expired items
176     }
177     else {
178         // We need to use a temporary so an error somewhere while traversing the dir does not cause
179         // the current directory to change.
180         Path newDir (cwd_);
181         traverseDirectory(dir, newDir);
182         oldCwd_.swap(cwd_);
183         cwd_.swap(newDir);
184     }
185 }
186
187 prefix_ void senf::console::Executor::ls(std::ostream & output,
188                                          ParseCommandInfo::TokensRange path)
189 {
190     Path dir (cwd_);
191     traverseDirectory(path, dir);
192     DirectoryNode & node (*dir.back().lock());
193     DirectoryNode::child_iterator i (node.children().begin());
194     DirectoryNode::child_iterator const i_end (node.children().end());
195     for (; i != i_end; ++i) {
196         output << i->first;
197         if (boost::dynamic_pointer_cast<DirectoryNode>(i->second))
198             output << "/";
199         output << "\n";
200     }
201 }
202
203 prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
204 {
205     Path newDir (cwd_);
206     if (! skipping()) {
207         try {
208             traverseDirectory(dir, newDir);
209         }
210         catch (IgnoreCommandException &) {
211             newDir.clear();
212         }
213     }
214     dirstack_.push_back(Path());
215     dirstack_.back().swap(cwd_);
216     cwd_.swap(newDir);
217 }
218
219 prefix_ void senf::console::Executor::popd()
220 {
221     if (! dirstack_.empty()) {
222         cwd_.swap(dirstack_.back());
223         dirstack_.pop_back();
224     }
225 }
226
227 prefix_ void senf::console::Executor::exit()
228 {
229     throw ExitException();
230 }
231
232 prefix_ void senf::console::Executor::help(std::ostream & output,
233                                            ParseCommandInfo::TokensRange path)
234 {
235     GenericNode const & node (traverseNode(path));
236     // output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
237     node.help(output);
238     output << std::flush;
239 }
240
241 prefix_ senf::console::GenericNode &
242 senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
243 {
244     if (path.empty())
245         return *cwd_.back().lock();
246     try {
247         Path dir (cwd_);
248         traverseDirectory(boost::make_iterator_range(
249                               path.begin(),
250                               boost::prior(path.end())),
251                           dir);
252         DirectoryNode & base (*dir.back().lock());
253         std::string const & name (complete(base, boost::prior(path.end())->value()));
254         if (policy_)
255             policy_( base, name );
256         return dir.back().lock()->get(name);
257     }
258     catch (UnknownNodeNameException &) {
259         throw InvalidPathException();
260     }
261 }
262
263 prefix_ void
264 senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
265                                            Path & dir)
266 {
267     try {
268         ParseCommandInfo::TokensRange::const_iterator i (path.begin());
269         ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
270         for (; i != i_end; ++i) {
271             if (*i == NoneToken()) {
272                 if (i == path.begin()) {
273                     dir.clear();
274                     dir.push_back(root_);
275                 }
276             }
277             else if (*i == WordToken("..")) {
278                 if (dir.size() > 1)
279                     dir.pop_back();
280             }
281             else if (*i ==  WordToken("."))
282                 ;
283             else {
284                 DirectoryNode & base (*dir.back().lock());
285                 std::string name (complete(base, i->value()));
286                 if (policy_)
287                     policy_( base, name );
288                 dir.push_back(base[name].thisptr());
289             }
290         }
291     }
292     catch (std::bad_cast &) {
293         throw InvalidDirectoryException();
294     }
295     catch (UnknownNodeNameException &) {
296         throw InvalidDirectoryException();
297     }
298 }
299
300 prefix_ std::string senf::console::Executor::complete(DirectoryNode & dir,
301                                                       std::string const & name)
302 {
303     if (! dir.hasChild(name)) {
304         DirectoryNode::ChildrenRange completions (dir.completions(name));
305         if (has_one_elt(completions))
306             return completions.begin()->first;
307     }
308     return name;
309 }
310
311 ///////////////////////////////cc.e////////////////////////////////////////
312 #undef prefix_
313 //#include "Executor.mpp"
314
315 \f
316 // Local Variables:
317 // mode: c++
318 // fill-column: 100
319 // comment-column: 40
320 // c-file-style: "senf"
321 // indent-tabs-mode: nil
322 // ispell-local-dictionary: "american"
323 // compile-command: "scons -u test"
324 // End: