📄 parser.cpp
字号:
// -*-c++-*-/*************************************************************************** parser.cpp Parser for config options ------------------- begin : 15-MAY-2003 copyright : (C) 2003 by The RoboCup Soccer Server Maintenance Group. email : sserver-admin@lists.sourceforge.net ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU LGPL as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any * * later version. * * * ***************************************************************************/#include "parser.hpp"#include <errno.h>#include "builder.hpp"#include "../lib/loader.hpp"#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_SSTREAM#include <sstream>#else#include <strstream>#endif#include <iterator>#include <boost/filesystem/operations.hpp>#include <boost/filesystem/fstream.hpp>#include <boost/filesystem/exception.hpp>// #define BOOST_SPIRIT_DEBUG#include <boost/spirit.hpp>#include <boost/function.hpp>#include <boost/bind.hpp>namespace {boolisQuated( const std::string & str ){ return ( str.length() >= 2 && ( ( *str.begin() == '\"' && *str.rbegin() == '\"' ) || ( *str.begin() == '\'' && *str.rbegin() == '\'' ) ) );}}namespace rcss{ namespace conf { const char* Parser::ErrorStrs[] = { "None", "'=' expected", "'::' expected", "value expected", "string expected" }; static std::string cleanString( std::string str ) { if( str.empty() ) return str; if( *str.begin() == '\'' ) { if( *str.rbegin() == '\'' ) str = str.substr( 1, str.length() - 2 ); else return str; for( std::string::size_type esc = str.find( "\\'" ); esc != std::string::npos; esc = str.find( "\\'" ) ) { str.replace( esc, 2, "'" ); } } else if( *str.begin() == '"' ) { if( *str.rbegin() == '"' ) str = str.substr( 1, str.length() - 2 ); else return str; for( std::string::size_type esc = str.find( "\\\"" ); esc != std::string::npos; esc = str.find( "\\\"" ) ) { str.replace( esc, 2, "\"" ); } } return str; } static std::string cleanString( const char* begin, const char* end ) { return cleanString( std::string( begin, end ) ); } static void setPath( const char* begin, const char* end ) { std::string spath = cleanString( begin, end ); boost::filesystem::path path; try { path = boost::filesystem::path( spath, &boost::filesystem::native ); } catch(...) { try { path = boost::filesystem::path( spath ); } catch(...) { return; } } if( !boost::filesystem::exists( path ) ) { // dir not found return; } if( !boost::filesystem::is_directory( path ) ) { // not a directoyr return; } lib::Loader::setPath( path ); } static void addPath( const char* begin, const char* end ) { std::string spath = cleanString( begin, end ); boost::filesystem::path path; try { path = boost::filesystem::path( spath, &boost::filesystem::native ); } catch(...) { try { path = boost::filesystem::path( spath ); } catch(...) { return; } } if( !boost::filesystem::exists( path ) ) { // dir not found return; } if( !boost::filesystem::is_directory( path ) ) { // not a directoyr return; } lib::Loader::addPath( path ); } class ParseErrorHandler { public: static boost::spirit::error_status<> parseError( const Parser* parser, const boost::spirit::rule<>::scanner_t& scanner, const boost::spirit::parser_error<Parser::Errors>& error) { std::string what; if( error.where + 10 > scanner.last ) what = std::string( error.where, scanner.last ); else what = std::string( error.where, error.where + 10 ); std::string::iterator newline = std::find( what.begin(), what.end(), '\n' ); if( newline != what.end() ) what = std::string( what.begin(), newline ); parser->m_builder.parseError( what, Parser::ErrorStrs[ error.descriptor ], parser->m_stack.front().m_name, parser->m_stack.front().m_lineno ); return boost::spirit::error_status<>(boost::spirit::error_status<>::fail); } }; Parser::Parser( Builder& builder ) : m_builder( builder ) { m_builder.addedToParser( *this ); } Parser::~Parser() { m_builder.removedFromParser(); } bool Parser::parse( int argc, const char * const * argv ) {#ifdef HAVE_SSTREAM std::stringstream strm;#else std::strstream strm;#endif if( argc > 1 ) { std::string arg( argv[1] ); if ( arg.find_first_of( " \t" ) != std::string::npos && ! isQuated( arg ) ) { strm << "\'" << arg << "\'"; } else { strm << arg; } } for( int i = 2; i < argc; ++i ) { std::string arg( argv[i] ); if ( arg.find_first_of( " \t" ) != std::string::npos && ! isQuated( arg ) ) { strm << ' ' << '\'' << arg << '\''; } else { strm << ' ' << arg; } }#ifndef HAVE_SSTREAM strm << std::ends;#else strm << std::flush;#endif bool res = rcss::Parser::parse( strm, "cmd line args" );#ifndef HAVE_SSTREAM strm.freeze( false );#endif return res; } bool Parser::parse( std::istream& strm ) { return rcss::Parser::parse( strm ); } bool Parser::parse( std::istream& strm, const std::string& name ) { return rcss::Parser::parse( strm, name ); } bool Parser::parse( const boost::filesystem::path& file ) { return rcss::Parser::parse( file ); } bool Parser::parseCreateConf( const boost::filesystem::path& conf_name, const std::string& module_name ) { std::string native_path = conf_name.native_file_string(); boost::filesystem::ifstream conf( conf_name ); if( !conf.is_open() ) { m_builder.creatingConfFile( native_path ); boost::filesystem::ofstream new_conf( conf_name ); if( new_conf.is_open() ) { m_builder.createConfFile( new_conf, module_name ); new_conf.close(); m_builder.createdConfFile( native_path ); return true; } else { m_builder.confCreationFailed( native_path, errno ); return false; } } else { bool rval = parse( conf, native_path ); conf.close(); return rval; } } bool Parser::doParse( std::istream& strm ) { m_builder.reset(); m_stack.push_front( StreamState( strm, getStreamName(), 1 ) ); bool rval = boostParse(); m_stack.pop_front(); rval = rval && m_builder.success(); return rval; } void Parser::countNewLines( const char* begin, const char* end ) { int count = 0; for( const char* i = begin; i != end; ++i ) if( '\n' == *i ) ++count; if( !m_stack.empty() ) m_stack.front().m_lineno += count; } bool Parser::include( const char* begin, const char* end ) { std::string incname = cleanString( begin, end ); boost::filesystem::path path; try { path = boost::filesystem::path( incname, &boost::filesystem::native ); } catch(...) { try { path = boost::filesystem::path( incname ); } catch( const std::exception& e ) { m_builder.includeFailed( incname, e.what(), m_stack.front().m_name, m_stack.front().m_lineno ); return false; } } boost::filesystem::path full_name; if( path.has_root_directory() ) { full_name = path; } else { const std::string& curr_path = m_stack.front().m_name; if( curr_path.empty() || curr_path == "cmd line args" || curr_path == "anonymous stream" ) { full_name = complete( path ); } else { boost::filesystem::path branch( curr_path, boost::filesystem::native ); branch = branch.branch_path(); full_name = branch / path; } } // check if the stream is already on the stack for( StreamStack::iterator i = m_stack.begin(); i != m_stack.end(); ++i ) { if( full_name.native_file_string() == i->m_name ) { // file already included so ignore it return true; } } if( boost::filesystem::exists( full_name ) ) { if( !boost::filesystem::is_directory( full_name ) ) { boost::filesystem::ifstream strm( full_name ); if( strm.is_open() && strm.good() ) { bool rval = parse( strm, full_name.native_file_string() ); strm.close(); return rval; } else { m_builder.includeFailed( full_name.native_file_string(), "read failed", m_stack.front().m_name, m_stack.front().m_lineno ); return false; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -