config_file_iterator.cpp

来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 681 行 · 第 1/2 页

CPP
681
字号
//  (C) Copyright Gennadiy Rozental 2005-2008.//  Use, modification, and distribution are subject to the//  Boost Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//  See http://www.boost.org/libs/test for the library home page.////  File        : $RCSfile$////  Version     : $Revision: 49312 $////  Description : flexible configuration file iterator implementation// ***************************************************************************// Boost.Runtime.Parameter#include <boost/test/utils/runtime/config.hpp>#include <boost/test/utils/runtime/file/config_file_iterator.hpp>#include <boost/test/utils/runtime/validation.hpp>#include <boost/test/utils/runtime/env/environment.hpp>// Boost#include <boost/utility.hpp>#include <boost/scoped_array.hpp>#include <boost/bind.hpp>// Boost.Test#include <boost/test/utils/basic_cstring/compare.hpp>#include <boost/test/utils/algorithm.hpp>#include <boost/test/utils/iterator/token_iterator.hpp>#include <boost/test/utils/assign_op.hpp>// STL#include <memory>#include <map>#include <list>#include <vector>#include <fstream>#include <cctype>#include <iostream>namespace boost {namespace BOOST_RT_PARAM_NAMESPACE {namespace file {// ************************************************************************** //// **************              symbol_to_value_map             ************** //// ************************************************************************** //template<typename ValueType>struct symbol_to_value_map : std::map<cstring, ValueType> {    template<typename ParamType>    void    add( cstring name, ParamType const& value )    {        using namespace unit_test;        m_name_store.push_back( dstring() );        assign_op( m_name_store.back(), name, 0 );        assign_op( (*this)[m_name_store.back()], value, 0 );    }    void    remove( cstring name )    {        std::list<dstring>::iterator it = std::find( m_name_store.begin(), m_name_store.end(), name );        m_name_store.erase( it );        erase( name );    }private:    std::list<dstring> m_name_store;};// ************************************************************************** //// **************                 symbol_table_t               ************** //// ************************************************************************** //typedef symbol_to_value_map<dstring> symbol_table_t;// ************************************************************************** //// **************              command_handler_map             ************** //// ************************************************************************** //typedef symbol_to_value_map<config_file_iterator::command_handler>    command_handler_map;// ************************************************************************** //// **************               is_valid_identifier            ************** //// ************************************************************************** //static boolis_valid_identifier( cstring const& source ){    if( source.is_empty() )        return false;    cstring::const_iterator it = source.begin();    if( !std::isalpha( *it ) )        return false;    while( ++it < source.end() ) {        if( !std::isalnum( *it ) && *it != BOOST_RT_PARAM_LITERAL( '_' ) && *it != BOOST_RT_PARAM_LITERAL( '-' ) )            return false;    }    return true;}// ************************************************************************** //// **************                 include_level                ************** //// ************************************************************************** //struct include_level;typedef std::auto_ptr<include_level> include_level_ptr;struct include_level : noncopyable{    // Constructor    explicit            include_level( cstring file_name, cstring path_separators, include_level* parent = 0 );    // Data members    std::ifstream       m_stream;    location            m_curr_location;    include_level_ptr   m_parent;};//____________________________________________________________________________//include_level::include_level( cstring file_name, cstring path_separators, include_level* parent_ ): m_parent( parent_ ){    if( file_name.is_empty() )        return;    assign_op( m_curr_location.first, file_name, 0 );    m_curr_location.second = 0;    m_stream.open( m_curr_location.first.c_str() );    if( !m_stream.is_open() && !!m_parent.get() ) {        cstring            parent_path = m_parent->m_curr_location.first;        cstring::iterator  it          = unit_test::find_last_of( parent_path.begin(), parent_path.end(),                                                                  path_separators.begin(),                                                                  path_separators.end() );        if( it != parent_path.end() ) {            assign_op( m_curr_location.first, cstring( parent_path.begin(), it+1 ), 0 );            m_curr_location.first.append( file_name.begin(), file_name.end() );            m_stream.clear();            m_stream.open( m_curr_location.first.c_str() );        }    }    BOOST_RT_PARAM_VALIDATE_LOGIC( m_stream.is_open(), BOOST_RT_PARAM_LITERAL( "couldn't open file " ) << file_name );}//____________________________________________________________________________//// ************************************************************************** //// **************          config_file_iterator::Impl          ************** //// ************************************************************************** //struct config_file_iterator::Impl : noncopyable {    // Constructor    Impl();    bool                get_next_line( cstring& next_line );    void                process_command_line( cstring line );    void                process_include( cstring line );    void                process_define( cstring line );    void                process_undef( cstring line );    void                process_ifdef( cstring line );    void                process_ifndef( cstring line );    void                process_else( cstring line );    void                process_endif( cstring line );    boost::optional<cstring>                        get_macro_value( cstring macro_name, bool ignore_missing = true );    void                substitute_macros( cstring& where );    bool                is_active_line() { return m_inactive_ifdef_level == 0; }    static bool         match_front( cstring str, cstring pattern )    {        return str.size() >= pattern.size() && str.substr( 0, pattern.size() ) == pattern;    }    static bool         match_back( cstring str, cstring pattern )    {        return str.size() >= pattern.size() && str.substr( str.size() - pattern.size() ) == pattern;    }    // Configurable parameters    dstring          m_path_separators;    char_type           m_line_delimeter;    dstring          m_sl_comment_delimeter;    dstring          m_command_delimeter;    dstring          m_line_beak;    dstring          m_macro_ref_begin;    dstring          m_macro_ref_end;    dstring          m_include_kw;    dstring          m_define_kw;    dstring          m_undef_kw;    dstring          m_ifdef_kw;    dstring          m_ifndef_kw;    dstring          m_else_kw;    dstring          m_endif_kw;    std::size_t         m_buffer_size;    bool                m_trim_trailing_spaces;    bool                m_trim_leading_spaces;    bool                m_skip_empty_lines;    bool                m_detect_missing_macro;    // Data members    dstring          m_post_subst_line;    scoped_array<char>  m_buffer;    include_level_ptr   m_curr_level;    symbol_table_t      m_symbols_table;    std::vector<bool>   m_conditional_states;    std::size_t         m_inactive_ifdef_level;    command_handler_map m_command_handler_map;};//____________________________________________________________________________//config_file_iterator::Impl::Impl(): m_path_separators( BOOST_RT_PARAM_LITERAL( "/\\" ) ), m_line_delimeter( BOOST_RT_PARAM_LITERAL( '\n' ) ), m_sl_comment_delimeter( BOOST_RT_PARAM_LITERAL( "#" ) ), m_command_delimeter( BOOST_RT_PARAM_LITERAL( "$" ) ), m_line_beak( BOOST_RT_PARAM_LITERAL( "\\" ) ), m_macro_ref_begin( BOOST_RT_PARAM_LITERAL( "$" ) ), m_macro_ref_end( BOOST_RT_PARAM_LITERAL( "$" ) ), m_include_kw( BOOST_RT_PARAM_LITERAL( "include" ) ), m_define_kw( BOOST_RT_PARAM_LITERAL( "define" ) ), m_undef_kw( BOOST_RT_PARAM_LITERAL( "undef" ) ), m_ifdef_kw( BOOST_RT_PARAM_LITERAL( "ifdef" ) ), m_ifndef_kw( BOOST_RT_PARAM_LITERAL( "ifndef" ) ), m_else_kw( BOOST_RT_PARAM_LITERAL( "else" ) ), m_endif_kw( BOOST_RT_PARAM_LITERAL( "endif" ) ), m_buffer_size( 8192 ), m_trim_trailing_spaces( true ), m_trim_leading_spaces( false ), m_skip_empty_lines( true ), m_detect_missing_macro( true ), m_inactive_ifdef_level( 0 ){}//____________________________________________________________________________//boolconfig_file_iterator::Impl::get_next_line( cstring& line ){    bool broken_line = false;    line.clear();    while( !m_curr_level->m_stream.eof() || !!m_curr_level->m_parent.get() ) {        // 10. Switch to upper include level if current one is finished        // 20.  Read/append next file line        // 30.  Increment line number        // 40.  Remove comments        // 50.  Remove trailing and leading spaces        // 60.  Skip empty string        // 70.  Concatenate broken lines if needed. Put the result into line        // 80.  If line is not completed, try to finish it by reading the next line        // 90.  Process command line        // 100. Substitute macros references with their definitions        // 110. Next line found.        if( m_curr_level->m_stream.eof() ) {                                                // 10 //            m_curr_level = m_curr_level->m_parent;            continue;        }        std::ifstream&  input   = m_curr_level->m_stream;        char_type* buffer_insert_pos = broken_line ? m_buffer.get() + line.size() : m_buffer.get();        input.getline( buffer_insert_pos, (std::streamsize)(m_buffer_size - line.size()),   // 20 //                       m_line_delimeter );        cstring next_line( buffer_insert_pos,                           input.gcount() > 0                             ? buffer_insert_pos + (input.eof() ? input.gcount() : (input.gcount()-1))                             : buffer_insert_pos );        m_curr_level->m_curr_location.second++;                                             // 30 //        cstring::size_type comment_pos = next_line.find( m_sl_comment_delimeter );        if( comment_pos != cstring::npos )            next_line.trim_right( next_line.begin()+comment_pos );                          // 40 //        if( m_trim_trailing_spaces )                                                        // 50 //            next_line.trim_right();        if( m_trim_leading_spaces && !broken_line )            next_line.trim_left();        if( next_line.is_empty() ) {                                                        // 60 //            if( m_skip_empty_lines )                continue;            else                next_line.assign( buffer_insert_pos, buffer_insert_pos );        }        line = broken_line ? cstring( line.begin(), next_line.end() ) : next_line;          // 70 //        broken_line = match_back( line, m_line_beak );        if( broken_line ) {                                                                 // 80 //            line.trim_right( 1 );            continue;        }        if( match_front( line, m_command_delimeter ) ) {                                    // 90 //            process_command_line( line );            continue;        }        if( !is_active_line() )            continue;        substitute_macros( line );                                                          // 100 //        return true;                                                                        // 110 //    }    BOOST_RT_PARAM_VALIDATE_LOGIC( !broken_line, BOOST_RT_PARAM_LITERAL( "broken line is not completed" ) );    BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() == 0,                                   BOOST_RT_PARAM_LITERAL( "matching endif command is missing" ) );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?