Console: Implement current directory management and builtins (cd, dirstack, ls)
[senf.git] / Console / Parse.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 Parse non-inline non-template implementation */
25
26 #include "Parse.hh"
27 #include "Parse.ih"
28
29 // Custom includes
30 #include "../Utils/String.hh"
31 #include <boost/iterator/transform_iterator.hpp>
32
33 //#include "Parse.mpp"
34 #define prefix_
35 ///////////////////////////////cc.p////////////////////////////////////////
36
37 namespace senf {
38 namespace console {
39 namespace detail {
40
41     struct ParserAccess
42     {
43         static void init(ParseCommandInfo & info)
44             { info.init(); }
45
46         static void setBuiltin(ParseCommandInfo & info, ParseCommandInfo::BuiltinCommand builtin)
47             { info.setBuiltin(builtin); }
48
49         static void setCommand(ParseCommandInfo & info, std::vector<std::string> & commandPath)
50             { info.setCommand(commandPath); }
51
52         static void startArgument(ParseCommandInfo & info)
53             { info.startArgument(); }
54
55         static void endArgument(ParseCommandInfo & info)
56             { info.endArgument(); }
57
58         static void addToken(ParseCommandInfo & info, ArgumentToken const & token)
59             { info.addToken(token); }
60
61         static void finalize(ParseCommandInfo & info)
62             { info.finalize(); }
63
64         static ArgumentToken makeToken(std::string const & token)
65             { return ArgumentToken(token); }
66     };
67
68     struct ParseDispatcher
69     {
70         ParseCommandInfo info_;
71         CommandParser::Callback cb_;
72
73         struct BindInfo {
74             BindInfo( ParseDispatcher & d, CommandParser::Callback cb)
75                 : dispatcher (d) { dispatcher.cb_ = cb; }
76             ~BindInfo() { dispatcher.cb_  = 0; }
77
78             ParseDispatcher & dispatcher;
79         };
80
81         void beginCommand(std::vector<std::string> & command)
82             { ParserAccess::init(info_);
83               ParserAccess::setCommand(info_, command); }
84
85         void endCommand()
86             { ParserAccess::finalize(info_); cb_(info_); }
87
88         void pushArgument(std::string const & argument)
89             { ParserAccess::startArgument(info_); 
90               ParserAccess::addToken(info_, ParserAccess::makeToken(argument)); 
91               ParserAccess::endArgument(info_); }
92
93         void openGroup()
94             { ParserAccess::startArgument(info_); }
95
96         void closeGroup()
97             { ParserAccess::endArgument(info_); }
98
99         void pushPunctuation(std::string const & token)
100             { ParserAccess::addToken(info_, ParserAccess::makeToken(token)); }
101
102         void pushWord(std::string const & token)
103             { ParserAccess::addToken(info_, ParserAccess::makeToken(token)); }
104
105         void builtin_cd(std::vector<std::string> & path)
106             { ParserAccess::init(info_);
107               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD);
108               setBuiltinPathArg(path);
109               ParserAccess::finalize(info_); cb_(info_); }
110
111         void builtin_ls(std::vector<std::string> & path)
112             { ParserAccess::init(info_);
113               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS);
114               setBuiltinPathArg(path);
115               ParserAccess::finalize(info_); cb_(info_); }
116
117         void pushDirectory(std::vector<std::string> & path)
118             { ParserAccess::init(info_);
119               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD);
120               setBuiltinPathArg(path);
121               ParserAccess::finalize(info_); cb_(info_); }
122
123         void popDirectory()
124             { ParserAccess::init(info_);
125               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD);
126               ParserAccess::finalize(info_); cb_(info_); }
127         
128         void builtin_exit()
129             { ParserAccess::init(info_);
130               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
131               ParserAccess::finalize(info_); cb_(info_); }
132
133         void setBuiltinPathArg(std::vector<std::string> & path)
134             {
135                 ParserAccess::startArgument(info_);
136                 for (std::vector<std::string>::const_iterator i (path.begin());
137                      i != path.end(); ++i)
138                     ParserAccess::addToken(info_, ParserAccess::makeToken(*i));
139                 ParserAccess::endArgument(info_);
140             }
141     };
142
143 }}}
144
145 ///////////////////////////////////////////////////////////////////////////
146 // senf::console::ParseCommandInfo
147
148 struct senf::console::ParseCommandInfo::MakeRange
149 {
150     typedef ParseCommandInfo::argument_value_type result_type;
151     
152     MakeRange() {}
153     MakeRange(ParseCommandInfo::token_iterator b) : b_ (b) {}
154     
155     senf::console::ParseCommandInfo::token_iterator b_;
156     
157     result_type operator()(TempArguments::iterator::value_type const & v) const {
158         return result_type( b_ + v.first, b_ + v.second );
159     }
160 };
161
162 prefix_ void senf::console::ParseCommandInfo::finalize()
163 {
164     arguments_.resize( tempArguments_.size() );
165
166     std::copy( boost::make_transform_iterator( tempArguments_.begin(), 
167                                                MakeRange(tokens_.begin()) ),
168                boost::make_transform_iterator( tempArguments_.end(), 
169                                                MakeRange() ),
170                arguments_.begin() );
171
172     tempArguments_.clear();
173 }
174
175 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
176                                                  ParseCommandInfo const & info)
177 {
178     if (info.builtin() == ParseCommandInfo::NoBuiltin) 
179         stream << senf::stringJoin(info.commandPath(), "/");
180     else {
181         char const * builtins[] = { "", "cd", "ls", "pushd", "popd", "exit" };
182         stream << "builtin-" << builtins[info.builtin()];
183     }
184         
185     ParseCommandInfo::ArgumentsRange args (info.arguments());
186     for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
187         ParseCommandInfo::token_iterator j (i->begin());
188         stream << " [";
189         if ( j != i->end() ) {
190             for (;;) {
191                 stream << "'" << j->value() << "'";
192                 if ( ++j != i->end() ) stream << ' ';
193                 else                   break;
194             }
195         }
196         stream << "]";
197     }
198
199     return stream;
200 }
201
202 ///////////////////////////////////////////////////////////////////////////
203 // senf::console::CommandParser
204
205 struct senf::console::CommandParser::Impl
206 {
207     typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
208
209     detail::ParseDispatcher dispatcher;
210     Grammar::Context context;
211     Grammar grammar;
212
213     Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
214 };
215
216 prefix_ senf::console::CommandParser::CommandParser()
217     : impl_ (new Impl())
218 {}
219
220 prefix_ senf::console::CommandParser::~CommandParser()
221 {}
222
223 prefix_ bool senf::console::CommandParser::parse(std::string command, Callback cb)
224 {
225     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb);
226 #   warning don't use c_str() in parse and add istream parser. Implement error checking in parser.
227     return boost::spirit::parse( command.c_str(), 
228                                  impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
229                                  impl().grammar.use_parser<Impl::Grammar::SkipParser>()
230         ).full;
231 }
232
233 ///////////////////////////////cc.e////////////////////////////////////////
234 #undef prefix_
235 //#include "Parse.mpp"
236
237 \f
238 // Local Variables:
239 // mode: c++
240 // fill-column: 100
241 // comment-column: 40
242 // c-file-style: "senf"
243 // indent-tabs-mode: nil
244 // ispell-local-dictionary: "american"
245 // compile-command: "scons -u test"
246 // End: