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 + -
显示快捷键?