Added RTPPacket Parser to DefaultBundle
[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 <cerrno>
31 #include <boost/iterator/transform_iterator.hpp>
32 #include <boost/spirit/iterator/file_iterator.hpp>
33 #include "../Utils/Exception.hh"
34
35 //#include "Parse.mpp"
36 #define prefix_
37 ///////////////////////////////cc.p////////////////////////////////////////
38
39 namespace senf {
40 namespace console {
41 namespace detail {
42
43 #ifndef DOXYGEN
44
45     struct ParseDispatcher
46     {
47         ParseCommandInfo * info_;
48
49         struct BindInfo {
50             BindInfo( ParseDispatcher & d, ParseCommandInfo & info)
51                 : dispatcher (d) { dispatcher.info_ = &info; }
52             ~BindInfo() { dispatcher.info_ = 0; }
53
54             ParseDispatcher & dispatcher;
55         };
56
57         void beginCommand(std::vector<Token> & command)
58             { info_->clear();
59               info_->command(command); }
60
61         void endCommand()
62             { }
63
64         void pushToken(Token const & token)
65             { info_->addToken(token); }
66
67         void builtin_cd(std::vector<Token> & path)
68             { info_->clear();
69               info_->builtin(ParseCommandInfo::BuiltinCD);
70               setBuiltinPathArg(path); }
71
72         void builtin_ls(std::vector<Token> & path)
73             { info_->clear();
74               info_->builtin(ParseCommandInfo::BuiltinLS);
75               setBuiltinPathArg(path); }
76
77         void pushDirectory(std::vector<Token> & path)
78             { info_->clear();
79               info_->builtin(ParseCommandInfo::BuiltinPUSHD);
80               setBuiltinPathArg(path); }
81
82         void popDirectory()
83             { info_->clear();
84               info_->builtin(ParseCommandInfo::BuiltinPOPD); }
85         
86         void builtin_exit()
87             { info_->clear();
88               info_->builtin(ParseCommandInfo::BuiltinEXIT); }
89
90         void builtin_help(std::vector<Token> & path)
91             { info_->clear();
92               info_->builtin(ParseCommandInfo::BuiltinHELP);
93               setBuiltinPathArg(path); }
94
95         void setBuiltinPathArg(std::vector<Token> & path)
96             {
97                 pushToken(ArgumentGroupOpenToken());
98                 for (std::vector<Token>::const_iterator i (path.begin());
99                      i != path.end(); ++i)
100                     pushToken(*i);
101                 pushToken(ArgumentGroupCloseToken());
102             }
103     };
104
105 #endif
106
107 }}}
108
109 ///////////////////////////////////////////////////////////////////////////
110 // senf::console::Token
111
112 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
113 {
114     static char const * tokenTypeName[] = {
115         "None",
116         "PathSeparator",
117         "ArgumentGroupOpen",
118         "ArgumentGroupClose",
119         "DirectoryGroupOpen",
120         "DirectoryGroupClose",
121         "CommandTerminator",
122         "OtherPunctuation",
123         "BasicString",
124         "HexString",
125         "Word" };
126     // The real table is:
127     //     static const int bitPosition[32] = {
128     //          0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8, 
129     //         31, 27, 13, 23, 21, 19, 16,  7, 26, 12, 18,  6, 11,  5, 10,  9 };
130     // However, we have replaced all values >= sizeof(tokenTypeName) with 0
131     // and have added 1 to all the remaining values
132     static const int bitPosition[32] = {
133         1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9, 
134         0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
135     // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
136     os << tokenTypeName[ token.type() 
137                          ? bitPosition[((token.type() & -token.type()) * 0x077CB531UL) >> 27]
138                          : 0 ]
139        << "('"
140        << token.value()
141        << "')";
142     return os;
143 }
144
145 ///////////////////////////////////////////////////////////////////////////
146 // senf::console::ParseCommandInfo
147
148 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
149                                                  ParseCommandInfo const & info)
150 {
151     if (info.builtin() == ParseCommandInfo::NoBuiltin) {
152         ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
153         ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
154         if (i != i_end) {
155             for (;;) {
156                 stream << i->value();
157                 if ( ++i != i_end ) stream << "/";
158                 else                break;
159             }
160         }
161     }
162     else {
163         char const * builtins[] = { 0, "cd", "ls", "pushd", "popd", "exit", "help" };
164         stream << "builtin-" << builtins[info.builtin()];
165     }
166         
167     ParseCommandInfo::ArgumentsRange args (info.arguments());
168     for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
169         ParseCommandInfo::token_iterator j (i->begin());
170         stream << " [";
171         if ( j != i->end() ) {
172             for (;;) {
173                 stream << "'" << j->value() << "'";
174                 if ( ++j != i->end() ) stream << ' ';
175                 else                   break;
176             }
177         }
178         stream << "]";
179     }
180
181     return stream;
182 }
183
184 ///////////////////////////////////////////////////////////////////////////
185 // senf::console::ParseCommandInfo::ArgumentIterator
186
187 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
188     const
189 {
190     if (b_->is(Token::ArgumentGroupOpen)) {
191         unsigned level (0);
192         e_ = b_;
193         for (;;) {
194             if (e_->is(Token::ArgumentGroupOpen))
195                 ++ level;
196             else if (e_->is(Token::ArgumentGroupClose)) {
197                 -- level;
198                 if (level == 0)
199                     break;
200             }
201             ++e_;
202         }
203     }
204     ++ e_;
205 }
206
207 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
208 {
209     e_ = b_;
210     --b_;
211     if (b_->is(Token::ArgumentGroupClose)) {
212         unsigned level (0);
213         for (;;) {
214             if (b_->is(Token::ArgumentGroupClose))
215                 ++ level;
216             else if (b_->is(Token::ArgumentGroupOpen)) {
217                 -- level;
218                 if (level == 0)
219                     break;
220             }
221             --b_;
222         }
223     }
224 }
225
226 ///////////////////////////////////////////////////////////////////////////
227 // senf::console::CommandParser
228
229 #ifndef DOXYGEN
230
231 struct senf::console::CommandParser::Impl
232 {
233     typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
234
235     detail::ParseDispatcher dispatcher;
236     Grammar::Context context;
237     Grammar grammar;
238
239     Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
240 };
241
242 #endif
243
244 prefix_ senf::console::CommandParser::CommandParser()
245     : impl_ (new Impl())
246 {}
247
248 prefix_ senf::console::CommandParser::~CommandParser()
249 {}
250
251 // This template member is placed here, since it is ONLY called from the implementation.  Otherwise,
252 // we would need to expose the Impl member to the public, which we don't want to do.
253
254 template <class Iterator>
255 prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator b, Iterator e, Callback cb)
256 {
257     ParseCommandInfo info;
258     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
259     boost::spirit::parse_info<Iterator> result;
260
261     for(;;) {
262         result = boost::spirit::parse(
263             b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
264         b = result.stop;
265         if (b == e) 
266             return e;
267         info.clear();
268         result = boost::spirit::parse(b, e,
269                                       impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
270                                       impl().grammar.use_parser<Impl::Grammar::SkipParser>());
271         if (! result.hit) 
272             return b;
273         if (! info.empty()) 
274             cb(info);
275         b = result.stop;
276     }
277 }
278
279 prefix_ bool senf::console::CommandParser::parse(std::string const & command, Callback cb)
280 {
281     return parseLoop(command.begin(), command.end(), cb) == command.end();
282 }
283
284 prefix_ bool senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
285 {
286     boost::spirit::file_iterator<> i (filename);
287     if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
288     boost::spirit::file_iterator<> const i_end (i.make_end());
289     
290     return parseLoop(i, i_end, cb) == i_end;
291 }
292
293 prefix_ bool senf::console::CommandParser::parseArguments(std::string const & arguments,
294                                                           ParseCommandInfo & info)
295 {
296     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
297     return boost::spirit::parse( arguments.begin(), arguments.end(), 
298                                  impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
299                                  impl().grammar.use_parser<Impl::Grammar::SkipParser>()
300         ).full;
301 }
302
303 struct senf::console::CommandParser::SetIncremental
304 {
305     SetIncremental(CommandParser & parser) : parser_ (parser) {
306         parser_.impl().grammar.incremental = true;
307     }
308
309     ~SetIncremental() {
310         parser_.impl().grammar.incremental = false;
311     }
312
313     CommandParser & parser_;
314 };
315
316 prefix_ std::string::size_type
317 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
318 {
319     SetIncremental si (*this);
320     return std::distance( commands.begin(), 
321                           parseLoop(commands.begin(), commands.end(), cb) );
322 }
323
324 ///////////////////////////////////////////////////////////////////////////
325 // senf::console::SyntaxErrorException
326
327 prefix_ char const * senf::console::SyntaxErrorException::what()
328     const throw()
329 {
330     return message().empty() ? "syntax error" : message().c_str();
331 }
332
333 ///////////////////////////////cc.e////////////////////////////////////////
334 #undef prefix_
335 //#include "Parse.mpp"
336
337 \f
338 // Local Variables:
339 // mode: c++
340 // fill-column: 100
341 // comment-column: 40
342 // c-file-style: "senf"
343 // indent-tabs-mode: nil
344 // ispell-local-dictionary: "american"
345 // compile-command: "scons -u test"
346 // End: