switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Utils / Console / Parse.cc
index 40a61fc..ff3bc51 100644 (file)
@@ -1,24 +1,29 @@
 // $Id$
 //
-// Copyright (C) 2008 
+// Copyright (C) 2008
 // Fraunhofer Institute for Open Communication Systems (FOKUS)
-// Competence Center NETwork research (NET), St. Augustin, GERMANY
-//     Stefan Bund <g0dil@berlios.de>
 //
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
+// The contents of this file are subject to the Fraunhofer FOKUS Public License
+// Version 1.0 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at 
+// http://senf.berlios.de/license.html
 //
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
+// The Fraunhofer FOKUS Public License Version 1.0 is based on, 
+// but modifies the Mozilla Public License Version 1.1.
+// See the full license text for the amendments.
 //
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the
-// Free Software Foundation, Inc.,
-// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+// Software distributed under the License is distributed on an "AS IS" basis, 
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
+// for the specific language governing rights and limitations under the License.
+//
+// The Original Code is Fraunhofer FOKUS code.
+//
+// The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
+// (registered association), Hansastraße 27 c, 80686 Munich, Germany.
+// All Rights Reserved.
+//
+// Contributor(s):
+//   Stefan Bund <g0dil@berlios.de>
 
 /** \file
     \brief Parse non-inline non-template implementation */
 
 // Custom includes
 #include <cerrno>
+#include <sys/stat.h>
 #include <boost/iterator/transform_iterator.hpp>
-#include <boost/spirit/iterator/file_iterator.hpp>
-#include <boost/spirit/iterator/position_iterator.hpp>
+#include <senf/config.hh>
+
+#if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
+#  include <boost/spirit/include/classic_file_iterator.hpp>
+#  include <boost/spirit/include/classic_position_iterator.hpp>
+#else
+#  include <boost/spirit/iterator/file_iterator.hpp>
+#  include <boost/spirit/iterator/position_iterator.hpp>
+#endif
+
 #include <senf/Utils/Exception.hh>
 #include <senf/Utils/senfassert.hh>
 
 //#include "Parse.mpp"
 #define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 
 namespace senf {
 namespace console {
@@ -94,7 +108,7 @@ namespace detail {
         void popDirectory()
             { info_->clear();
               info_->builtin(ParseCommandInfo::BuiltinPOPD); }
-        
+
         void builtin_exit()
             { info_->clear();
               info_->builtin(ParseCommandInfo::BuiltinEXIT); }
@@ -119,7 +133,7 @@ namespace detail {
 
 }}}
 
-///////////////////////////////////////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 // senf::console::Token
 
 prefix_ senf::console::Token::Token(TokenType type, std::string token,
@@ -144,15 +158,15 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const
         "Word" };
     // The real table is:
     //     static const int bitPosition[32] = {
-    //          0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8, 
+    //          0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8,
     //         31, 27, 13, 23, 21, 19, 16,  7, 26, 12, 18,  6, 11,  5, 10,  9 };
     // However, we have replaced all values >= sizeof(tokenTypeName) with 0
     // and have added 1 to all the remaining values
     static const int bitPosition[32] = {
-        1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9, 
+        1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
         0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
     // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
-    os << tokenTypeName[ token.type() 
+    os << tokenTypeName[ token.type()
                          ? bitPosition[(((token.type() & -token.type()) * 0x077CB531UL) >> 27) & 31]
                          : 0 ]
        << "('"
@@ -161,7 +175,7 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const
     return os;
 }
 
-///////////////////////////////////////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 // senf::console::ParseCommandInfo
 
 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
@@ -182,7 +196,7 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
         char const * builtins[] = { 0, "cd", "ls", "lr", "pushd", "popd", "exit", "help" };
         stream << "builtin-" << builtins[info.builtin()];
     }
-        
+
     ParseCommandInfo::ArgumentsRange args (info.arguments());
     for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
         ParseCommandInfo::token_iterator j (i->begin());
@@ -200,7 +214,7 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
     return stream;
 }
 
-///////////////////////////////////////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 // senf::console::ParseCommandInfo::ArgumentIterator
 
 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
@@ -242,7 +256,7 @@ prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 // senf::console::CommandParser
 
 #ifndef DOXYGEN
@@ -261,9 +275,9 @@ struct senf::console::CommandParser::Impl
 #endif
 
 namespace {
-    
+
     template <class Error>
-    void throwParserError(Error const & err) 
+    void throwParserError(Error const & err)
     {
         static char const * msg [] = { "end of statement expected",
                                        "path expected",
@@ -276,8 +290,11 @@ namespace {
 
 }
 
-namespace boost { 
+namespace boost {
 namespace spirit {
+#if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
+namespace classic {
+#endif
 
     template <>
     struct position_policy<senf::console::detail::FilePositionWithIndex>
@@ -304,6 +321,9 @@ namespace spirit {
             }
     };
 
+#if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
+}
+#endif
 }}
 
 prefix_ senf::console::CommandParser::CommandParser()
@@ -317,38 +337,38 @@ prefix_ senf::console::CommandParser::~CommandParser()
 // we would need to expose the Impl member to the public, which we don't want to do.
 
 template <class Iterator>
-prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator npb, Iterator npe, 
+prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator npb, Iterator npe,
                                                          std::string const & source, Callback cb)
 {
-    typedef boost::spirit::position_iterator<
+    typedef detail::boost_spirit::position_iterator<
         Iterator, detail::FilePositionWithIndex> PositionIterator;
     PositionIterator b (npb, npe, source);
     PositionIterator e (npe, npe, source);
     ParseCommandInfo info;
     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
-    boost::spirit::parse_info<PositionIterator> result;
+    detail::boost_spirit::parse_info<PositionIterator> result;
 
-    for(;;) {
-        result = boost::spirit::parse(
+    for (;;) {
+        result = detail::boost_spirit::parse(
             b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
         b = result.stop;
-        if (b == e) 
+        if (b == e)
             return e.base();
         info.clear();
         try {
-            result = boost::spirit::parse(b, e,
+            result = detail::boost_spirit::parse(b, e,
                                           impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
                                           impl().grammar.use_parser<Impl::Grammar::SkipParser>());
         }
-        catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
+        catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
             if (impl().grammar.incremental && ex.where == e)
                 return b.base();
             else
                 throwParserError(ex);
         }
         // Otherwise the error handling in the parser is broken
-        SENF_ASSERT( result.hit );
-        if (! info.empty()) 
+        SENF_ASSERT( result.hit, "Internal parser failure (error handling broken?)" );
+        if (! info.empty())
             try {
                 cb(info);
             }
@@ -368,27 +388,40 @@ prefix_ void senf::console::CommandParser::parse(std::string const & command, Ca
 
 prefix_ void senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
 {
-    boost::spirit::file_iterator<> i (filename);
-    if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
-    boost::spirit::file_iterator<> const i_end (i.make_end());
+    // file_iterator sets errno to EINVAL and returns error when file size is 0
+    // so we check the file size before
+    struct stat statBuf;
+    if (stat( filename.c_str(), &statBuf) != 0)
+        throw SystemException(filename, errno SENF_EXC_DEBUGINFO);
+    if (statBuf.st_size == 0) return;
+    detail::boost_spirit::file_iterator<> i (filename);
+    if (!i) {
+        if (errno == 0)
+            // hmm.. errno==0 but the file_iterator is false; something is wrong but we
+            // do not know what exactly, so we throw a SystemeException with EINVAL
+            throw SystemException(filename, EINVAL SENF_EXC_DEBUGINFO);
+        else
+            throw SystemException(filename, errno SENF_EXC_DEBUGINFO);
+    }
+    detail::boost_spirit::file_iterator<> const i_end (i.make_end());
     parseLoop(i, i_end, filename, cb);
 }
 
 prefix_ void senf::console::CommandParser::parseArguments(std::string const & arguments,
                                                           ParseCommandInfo & info)
 {
-    typedef boost::spirit::position_iterator<
+    typedef detail::boost_spirit::position_iterator<
         std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
     PositionIterator b (arguments.begin(), arguments.end(), std::string("<unknown>"));
     PositionIterator e (arguments.end(), arguments.end(), std::string("<unknown>"));
     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
-    boost::spirit::parse_info<PositionIterator> result;
+    detail::boost_spirit::parse_info<PositionIterator> result;
     try {
-        result = boost::spirit::parse( b, e, 
+        result = detail::boost_spirit::parse( b, e,
                                        impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
                                        impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
     }
-    catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
+    catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
         throwParserError(ex);
     }
     if (! result.full) {
@@ -401,18 +434,18 @@ prefix_ void senf::console::CommandParser::parseArguments(std::string const & ar
 prefix_ void senf::console::CommandParser::parsePath(std::string const & path,
                                                      ParseCommandInfo & info)
 {
-    typedef boost::spirit::position_iterator<
+    typedef detail::boost_spirit::position_iterator<
         std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
     PositionIterator b (path.begin(), path.end(), std::string("<unknown>"));
     PositionIterator e (path.end(), path.end(), std::string("<unknown>"));
     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
-    boost::spirit::parse_info<PositionIterator> result;
+    detail::boost_spirit::parse_info<PositionIterator> result;
     try {
-        result = boost::spirit::parse( b, e, 
+        result = detail::boost_spirit::parse( b, e,
                                        impl().grammar.use_parser<Impl::Grammar::PathParser>(),
                                        impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
     }
-    catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
+    catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
         throwParserError(ex);
     }
     if (! result.full) {
@@ -439,11 +472,11 @@ prefix_ std::string::size_type
 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
 {
     SetIncremental si (*this);
-    return std::distance( commands.begin(), 
+    return std::distance( commands.begin(),
                           parseLoop(commands.begin(), commands.end(), "<unknown>", cb) );
 }
 
-///////////////////////////////////////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 // Character sets
 
 prefix_ bool senf::console::CommandParser::isSpecialChar(char ch)
@@ -471,7 +504,7 @@ prefix_ bool senf::console::CommandParser::isWordChar(char ch)
     return Impl::Grammar::word_p.test(ch);
 }
 
-/////////////////////////////cc.e////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 #undef prefix_
 //#include "Parse.mpp"