1 //  (C) Copyright Gennadiy Rozental 2005-2014.
2 //  Use, modification, and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 //  See http://www.boost.org/libs/test for the library home page.
7 //
8 //  File        : $RCSfile$
9 //
10 //  Version     : $Revision$
11 //
12 //  Description : flexible configuration file iterator implementation
13 // ***************************************************************************
14 
15 // Boost.Runtime.Parameter
16 #include <boost/test/utils/runtime/config.hpp>
17 
18 #include <boost/test/utils/runtime/file/config_file_iterator.hpp>
19 #include <boost/test/utils/runtime/validation.hpp>
20 
21 #ifndef UNDER_CE
22 #include <boost/test/utils/runtime/env/environment.hpp>
23 #endif
24 
25 
26 // Boost
27 #include <boost/scoped_array.hpp>
28 #include <boost/bind.hpp>
29 #include <boost/noncopyable.hpp>
30 
31 // Boost.Test
32 #include <boost/test/utils/basic_cstring/compare.hpp>
33 #include <boost/test/utils/algorithm.hpp>
34 #include <boost/test/utils/iterator/token_iterator.hpp>
35 #include <boost/test/utils/assign_op.hpp>
36 
37 // STL
38 #include <memory>
39 #include <map>
40 #include <list>
41 #include <vector>
42 #include <fstream>
43 #include <cctype>
44 #include <iostream>
45 
46 namespace boost {
47 
48 namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE {
49 
50 namespace file {
51 
52 // ************************************************************************** //
53 // **************              symbol_to_value_map             ************** //
54 // ************************************************************************** //
55 
56 template<typename ValueType>
57 struct symbol_to_value_map : std::map<cstring, ValueType> {
58     template<typename ParamType>
addboost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::file::symbol_to_value_map59     void    add( cstring name, ParamType const& value )
60     {
61         using namespace unit_test;
62 
63         m_name_store.push_back( dstring() );
64 
65         assign_op( m_name_store.back(), name, 0 );
66         assign_op( (*this)[m_name_store.back()], value, 0 );
67     }
removeboost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::file::symbol_to_value_map68     void    remove( cstring name )
69     {
70         std::list<dstring>::iterator it = std::find( m_name_store.begin(), m_name_store.end(), name );
71 
72         m_name_store.erase( it );
73 
74         this->erase( name );
75     }
76 
77 private:
78     std::list<dstring> m_name_store;
79 };
80 
81 // ************************************************************************** //
82 // **************                 symbol_table_t               ************** //
83 // ************************************************************************** //
84 
85 typedef symbol_to_value_map<dstring> symbol_table_t;
86 
87 // ************************************************************************** //
88 // **************              command_handler_map             ************** //
89 // ************************************************************************** //
90 
91 typedef symbol_to_value_map<config_file_iterator::command_handler>    command_handler_map;
92 
93 // ************************************************************************** //
94 // **************               is_valid_identifier            ************** //
95 // ************************************************************************** //
96 
97 static bool
is_valid_identifier(cstring const & source)98 is_valid_identifier( cstring const& source )
99 {
100     if( source.is_empty() )
101         return false;
102 
103     cstring::const_iterator it = source.begin();
104 
105     if( !std::isalpha( *it ) )
106         return false;
107 
108     while( ++it < source.end() ) {
109         if( !std::isalnum( *it ) && *it != BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '_' ) && *it != BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '-' ) )
110             return false;
111     }
112 
113     return true;
114 }
115 
116 // ************************************************************************** //
117 // **************                 include_level                ************** //
118 // ************************************************************************** //
119 
120 struct include_level;
121 typedef std::auto_ptr<include_level> include_level_ptr;
122 
123 struct include_level : noncopyable
124 {
125     // Constructor
126     explicit            include_level( cstring file_name, cstring path_separators, include_level* parent = 0 );
127 
128     // Data members
129     std::ifstream       m_stream;
130     location            m_curr_location;
131     include_level_ptr   m_parent;
132 };
133 
134 //____________________________________________________________________________//
135 
include_level(cstring file_name,cstring path_separators,include_level * parent_)136 include_level::include_level( cstring file_name, cstring path_separators, include_level* parent_ )
137 : m_parent( parent_ )
138 {
139     if( file_name.is_empty() )
140         return;
141 
142     assign_op( m_curr_location.first, file_name, 0 );
143     m_curr_location.second = 0;
144 
145     m_stream.open( m_curr_location.first.c_str() );
146 
147     if( !m_stream.is_open() && !!m_parent.get() ) {
148         cstring            parent_path = m_parent->m_curr_location.first;
149         cstring::iterator  it          = unit_test::find_last_of( parent_path.begin(), parent_path.end(),
150                                                                   path_separators.begin(),
151                                                                   path_separators.end() );
152 
153         if( it != parent_path.end() ) {
154             assign_op( m_curr_location.first, cstring( parent_path.begin(), it+1 ), 0 );
155             m_curr_location.first.append( file_name.begin(), file_name.end() );
156             m_stream.clear();
157             m_stream.open( m_curr_location.first.c_str() );
158         }
159     }
160 
161     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_stream.is_open(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "can't open file " ) << file_name );
162 }
163 
164 //____________________________________________________________________________//
165 
166 // ************************************************************************** //
167 // **************          config_file_iterator::Impl          ************** //
168 // ************************************************************************** //
169 
170 struct config_file_iterator::Impl : noncopyable {
171     // Constructor
172     Impl();
173 
174     bool                get_next_line( cstring& next_line );
175 
176     void                process_command_line( cstring line );
177     void                process_include( cstring line );
178     void                process_define( cstring line );
179     void                process_undef( cstring line );
180     void                process_ifdef( cstring line );
181     void                process_ifndef( cstring line );
182     void                process_else( cstring line );
183     void                process_endif( cstring line );
184 
185     boost::optional<cstring>
186                         get_macro_value( cstring macro_name, bool ignore_missing = true );
187     void                substitute_macros( cstring& where );
188 
is_active_lineboost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::file::config_file_iterator::Impl189     bool                is_active_line() { return m_inactive_ifdef_level == 0; }
190 
match_frontboost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::file::config_file_iterator::Impl191     static bool         match_front( cstring str, cstring pattern )
192     {
193         return str.size() >= pattern.size() && str.substr( 0, pattern.size() ) == pattern;
194     }
match_backboost::BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE::file::config_file_iterator::Impl195     static bool         match_back( cstring str, cstring pattern )
196     {
197         return str.size() >= pattern.size() && str.substr( str.size() - pattern.size() ) == pattern;
198     }
199 
200     // Configurable parameters
201     dstring          m_path_separators;
202     char_type           m_line_delimeter;
203     dstring          m_sl_comment_delimeter;
204     dstring          m_command_delimeter;
205     dstring          m_line_beak;
206     dstring          m_macro_ref_begin;
207     dstring          m_macro_ref_end;
208 
209     dstring          m_include_kw;
210     dstring          m_define_kw;
211     dstring          m_undef_kw;
212     dstring          m_ifdef_kw;
213     dstring          m_ifndef_kw;
214     dstring          m_else_kw;
215     dstring          m_endif_kw;
216 
217     std::size_t         m_buffer_size;
218 
219     bool                m_trim_trailing_spaces;
220     bool                m_trim_leading_spaces;
221     bool                m_skip_empty_lines;
222     bool                m_detect_missing_macro;
223 
224     // Data members
225     dstring          m_post_subst_line;
226     scoped_array<char>  m_buffer;
227     include_level_ptr   m_curr_level;
228     symbol_table_t      m_symbols_table;
229     std::vector<bool>   m_conditional_states;
230     std::size_t         m_inactive_ifdef_level;
231     command_handler_map m_command_handler_map;
232 };
233 
234 //____________________________________________________________________________//
235 
Impl()236 config_file_iterator::Impl::Impl()
237 : m_path_separators( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "/\\" ) )
238 , m_line_delimeter( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( '\n' ) )
239 , m_sl_comment_delimeter( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "#" ) )
240 , m_command_delimeter( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "$" ) )
241 , m_line_beak( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "\\" ) )
242 , m_macro_ref_begin( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "$" ) )
243 , m_macro_ref_end( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "$" ) )
244 
245 , m_include_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "include" ) )
246 , m_define_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "define" ) )
247 , m_undef_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "undef" ) )
248 , m_ifdef_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "ifdef" ) )
249 , m_ifndef_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "ifndef" ) )
250 , m_else_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "else" ) )
251 , m_endif_kw( BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "endif" ) )
252 
253 , m_buffer_size( 8192 )
254 
255 , m_trim_trailing_spaces( true )
256 , m_trim_leading_spaces( false )
257 , m_skip_empty_lines( true )
258 , m_detect_missing_macro( true )
259 
260 , m_inactive_ifdef_level( 0 )
261 {}
262 
263 //____________________________________________________________________________//
264 
265 bool
get_next_line(cstring & line)266 config_file_iterator::Impl::get_next_line( cstring& line )
267 {
268     bool broken_line = false;
269 
270     line.clear();
271 
272     while( !m_curr_level->m_stream.eof() || !!m_curr_level->m_parent.get() ) {
273         // 10. Switch to upper include level if current one is finished
274         // 20.  Read/append next file line
275         // 30.  Increment line number
276         // 40.  Remove comments
277         // 50.  Remove trailing and leading spaces
278         // 60.  Skip empty string
279         // 70.  Concatenate broken lines if needed. Put the result into line
280         // 80.  If line is not completed, try to finish it by reading the next line
281         // 90.  Process command line
282         // 100. Substitute macros references with their definitions
283         // 110. Next line found.
284 
285         if( m_curr_level->m_stream.eof() ) {                                                // 10 //
286             m_curr_level = m_curr_level->m_parent;
287             continue;
288         }
289 
290         std::ifstream&  input   = m_curr_level->m_stream;
291         char_type* buffer_insert_pos = broken_line ? m_buffer.get() + line.size() : m_buffer.get();
292 
293         input.getline( buffer_insert_pos, (std::streamsize)(m_buffer_size - line.size()),   // 20 //
294                        m_line_delimeter );
295 
296         cstring next_line( buffer_insert_pos,
297                            input.gcount() > 0
298                              ? buffer_insert_pos + (input.eof() ? input.gcount() : (input.gcount()-1))
299                              : buffer_insert_pos );
300 
301 
302         m_curr_level->m_curr_location.second++;                                             // 30 //
303 
304         cstring::size_type comment_pos = next_line.find( m_sl_comment_delimeter );
305         if( comment_pos != cstring::npos )
306             next_line.trim_right( next_line.begin()+comment_pos );                          // 40 //
307 
308         if( m_trim_trailing_spaces )                                                        // 50 //
309             next_line.trim_right();
310         if( m_trim_leading_spaces && !broken_line )
311             next_line.trim_left();
312 
313         if( next_line.is_empty() ) {                                                        // 60 //
314             if( m_skip_empty_lines )
315                 continue;
316             else
317                 next_line.assign( buffer_insert_pos, buffer_insert_pos );
318         }
319 
320         line = broken_line ? cstring( line.begin(), next_line.end() ) : next_line;          // 70 //
321 
322         broken_line = match_back( line, m_line_beak );
323         if( broken_line ) {                                                                 // 80 //
324             line.trim_right( 1 );
325             continue;
326         }
327 
328         if( match_front( line, m_command_delimeter ) ) {                                    // 90 //
329             process_command_line( line );
330             continue;
331         }
332 
333         if( !is_active_line() )
334             continue;
335 
336         substitute_macros( line );                                                          // 100 //
337 
338         return true;                                                                        // 110 //
339     }
340 
341     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( !broken_line, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "broken line is not completed" ) );
342     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_conditional_states.size() == 0,
343                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "matching endif command is missing" ) );
344 
345     return false;
346 }
347 
348 //____________________________________________________________________________//
349 
350 boost::optional<cstring>
get_macro_value(cstring macro_name,bool ignore_missing)351 config_file_iterator::Impl::get_macro_value( cstring macro_name, bool ignore_missing )
352 {
353     symbol_table_t::const_iterator it = m_symbols_table.find( macro_name );
354 
355     if( it == m_symbols_table.end() ) {
356         boost::optional<cstring> macro_value; // !! variable actually may have different type
357 
358         #ifndef UNDER_CE
359         env::get( macro_name, macro_value );
360         #endif
361 
362         BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( macro_value || ignore_missing || !m_detect_missing_macro,
363             BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Unknown macro \"" ) << macro_name << BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "\"" ) );
364 
365         if( !macro_value ) {
366             if( !ignore_missing )
367                 macro_value = cstring();
368         }
369         else
370             m_symbols_table.add( macro_name, *macro_value );
371 
372         return macro_value;
373     }
374 
375     return boost::optional<cstring>( cstring( it->second ) );
376 }
377 
378 //____________________________________________________________________________//
379 
380 void
process_command_line(cstring line)381 config_file_iterator::Impl::process_command_line( cstring line )
382 {
383     line.trim_left( m_command_delimeter.size() );
384 
385     unit_test::string_token_iterator tit( line, unit_test::max_tokens = 2 );
386 
387     command_handler_map::const_iterator it = m_command_handler_map.find( *tit );
388 
389     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( it != m_command_handler_map.end(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "Invalid command " ) << *tit );
390 
391     ++tit;
392 
393     (it->second)( *tit );
394 }
395 
396 //____________________________________________________________________________//
397 
398 void
process_include(cstring line)399 config_file_iterator::Impl::process_include( cstring line )
400 {
401     using namespace unit_test;
402 
403     if( !is_active_line() )
404         return;
405 
406     string_token_iterator tit( line, kept_delimeters = dt_none );
407 
408     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( tit != string_token_iterator(),
409                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "include file name missing" ) );
410 
411     cstring include_file_name = *tit;
412 
413     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( ++tit == string_token_iterator(),
414                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "unexpected tokens at the end of include command" ) );
415 
416     substitute_macros( include_file_name );
417 
418     m_curr_level.reset( new include_level( include_file_name, m_path_separators, m_curr_level.release() ) );
419 }
420 
421 //____________________________________________________________________________//
422 
423 void
process_define(cstring line)424 config_file_iterator::Impl::process_define( cstring line )
425 {
426     using namespace unit_test;
427 
428     if( !is_active_line() )
429         return;
430 
431     string_token_iterator tit( line, (kept_delimeters = dt_none, max_tokens = 2 ));
432 
433     cstring macro_name = *tit;
434     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ),
435                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) );
436 
437     cstring macro_value = *(++tit);
438     substitute_macros( macro_value );
439 
440     m_symbols_table.add( macro_name, macro_value );
441 }
442 
443 //____________________________________________________________________________//
444 
445 void
process_undef(cstring line)446 config_file_iterator::Impl::process_undef( cstring line )
447 {
448     if( !is_active_line() )
449         return;
450 
451     cstring macro_name = line;
452     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ),
453                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) );
454 
455     m_symbols_table.remove( macro_name );
456 }
457 
458 //____________________________________________________________________________//
459 
460 void
process_ifdef(cstring line)461 config_file_iterator::Impl::process_ifdef( cstring line )
462 {
463     m_conditional_states.push_back( true );
464     if( !is_active_line() )
465         return;
466 
467     cstring macro_name = line;
468     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ),
469                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) );
470 
471     if( !get_macro_value( macro_name ) )
472         m_inactive_ifdef_level = m_conditional_states.size();
473 }
474 
475 //____________________________________________________________________________//
476 
477 void
process_ifndef(cstring line)478 config_file_iterator::Impl::process_ifndef( cstring line )
479 {
480     m_conditional_states.push_back( true );
481     if( !is_active_line() )
482         return;
483 
484     cstring macro_name = line;
485     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ),
486                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "invalid macro name" ) );
487 
488     if( get_macro_value( macro_name ) )
489         m_inactive_ifdef_level = m_conditional_states.size();
490 }
491 
492 //____________________________________________________________________________//
493 
494 void
process_else(cstring line)495 config_file_iterator::Impl::process_else( cstring line )
496 {
497     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0 && m_conditional_states.back(),
498                                    BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "else without matching if" ) );
499 
500     m_inactive_ifdef_level = m_conditional_states.size() == m_inactive_ifdef_level ? 0 : m_conditional_states.size();
501 
502     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "unexpected tokens at the end of else command" ) );
503 }
504 
505 //____________________________________________________________________________//
506 
507 void
process_endif(cstring line)508 config_file_iterator::Impl::process_endif( cstring line )
509 {
510     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "endif without matching if" ) );
511 
512     if( m_conditional_states.size() == m_inactive_ifdef_level )
513         m_inactive_ifdef_level = 0;
514 
515     m_conditional_states.pop_back();
516     BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "unexpected tokens at the end of endif command" ) );
517 }
518 
519 //____________________________________________________________________________//
520 
521 void
substitute_macros(cstring & where)522 config_file_iterator::Impl::substitute_macros( cstring& where )
523 {
524     m_post_subst_line.clear();
525     cstring::size_type pos;
526 
527     while( (pos = where.find( m_macro_ref_begin )) != cstring::npos ) {
528         m_post_subst_line.append( where.begin(), pos );
529 
530         where.trim_left( where.begin() + pos + m_macro_ref_begin.size() );
531 
532         pos = where.find( m_macro_ref_end );
533 
534         BOOST_TEST_UTILS_RUNTIME_PARAM_VALIDATE_LOGIC( pos != cstring::npos, BOOST_TEST_UTILS_RUNTIME_PARAM_LITERAL( "incomplete macro reference" ) );
535 
536         cstring value = *get_macro_value( where.substr( 0, pos ), false );
537         m_post_subst_line.append( value.begin(), value.size() );
538 
539         where.trim_left( where.begin() + pos + m_macro_ref_end.size() );
540     }
541 
542     if( !m_post_subst_line.empty() ) {
543         m_post_subst_line.append( where.begin(), where.size() );
544         where = m_post_subst_line;
545     }
546 }
547 
548 //____________________________________________________________________________//
549 
550 // ************************************************************************** //
551 // **************      runtime::file::config_file_iterator      ************** //
552 // ************************************************************************** //
553 
554 void
construct()555 config_file_iterator::construct()
556 {
557     m_pimpl.reset( new Impl );
558 }
559 
560 //____________________________________________________________________________//
561 
562 void
load(cstring file_name)563 config_file_iterator::load( cstring file_name )
564 {
565   m_pimpl->m_curr_level.reset( new include_level( file_name, m_pimpl->m_path_separators ) );
566   m_pimpl->m_buffer.reset( new char[m_pimpl->m_buffer_size] );
567 
568   register_command_handler( m_pimpl->m_include_kw, boost::bind( &Impl::process_include, m_pimpl.get(), _1 ) );
569   register_command_handler( m_pimpl->m_define_kw, boost::bind( &Impl::process_define, m_pimpl.get(), _1 ) );
570   register_command_handler( m_pimpl->m_undef_kw, boost::bind( &Impl::process_undef, m_pimpl.get(), _1 ) );
571   register_command_handler( m_pimpl->m_ifdef_kw, boost::bind( &Impl::process_ifdef, m_pimpl.get(), _1 ) );
572   register_command_handler( m_pimpl->m_ifndef_kw, boost::bind( &Impl::process_ifndef, m_pimpl.get(), _1 ) );
573   register_command_handler( m_pimpl->m_else_kw, boost::bind( &Impl::process_else, m_pimpl.get(), _1 ) );
574   register_command_handler( m_pimpl->m_endif_kw, boost::bind( &Impl::process_endif, m_pimpl.get(), _1 ) );
575 
576   init();
577 }
578 
579 //____________________________________________________________________________//
580 
581 location const&
curr_location()582 config_file_iterator::curr_location()
583 {
584     return m_pimpl->m_curr_level->m_curr_location;
585 }
586 
587 //____________________________________________________________________________//
588 
589 void
register_command_handler(cstring command_kw,command_handler const & ch)590 config_file_iterator::register_command_handler( cstring command_kw, command_handler const& ch )
591 {
592     m_pimpl->m_command_handler_map.add( command_kw, ch );
593 }
594 
595 //____________________________________________________________________________//
596 
597 bool
get()598 config_file_iterator::get()
599 {
600     return m_pimpl->get_next_line( m_value );
601 }
602 
603 //____________________________________________________________________________//
604 
605 void
set_parameter(rtti::id_t id,cstring value)606 config_file_iterator::set_parameter( rtti::id_t id, cstring value )
607 {
608     BOOST_RTTI_SWITCH( id ) {
609         BOOST_RTTI_CASE( cfg_detail::path_separators_t )
610             assign_op( m_pimpl->m_path_separators        , value, 0 );
611         BOOST_RTTI_CASE( cfg_detail::sl_comment_delimeter_t )
612             assign_op( m_pimpl->m_sl_comment_delimeter   , value, 0 );
613         BOOST_RTTI_CASE( cfg_detail::command_delimeter_t )
614             assign_op( m_pimpl->m_command_delimeter      , value, 0 );
615         BOOST_RTTI_CASE( cfg_detail::line_beak_t )
616             assign_op( m_pimpl->m_line_beak              , value, 0 );
617         BOOST_RTTI_CASE( cfg_detail::macro_ref_begin_t )
618             assign_op( m_pimpl->m_macro_ref_begin        , value, 0 );
619         BOOST_RTTI_CASE( cfg_detail::macro_ref_end_t )
620             assign_op( m_pimpl->m_macro_ref_end          , value, 0 );
621         BOOST_RTTI_CASE( cfg_detail::include_kw_t )
622             assign_op( m_pimpl->m_include_kw             , value, 0 );
623         BOOST_RTTI_CASE( cfg_detail::define_kw_t )
624             assign_op( m_pimpl->m_define_kw              , value, 0 );
625         BOOST_RTTI_CASE( cfg_detail::undef_kw_t )
626             assign_op( m_pimpl->m_undef_kw               , value, 0 );
627         BOOST_RTTI_CASE( cfg_detail::ifdef_kw_t )
628             assign_op( m_pimpl->m_ifdef_kw               , value, 0 );
629         BOOST_RTTI_CASE( cfg_detail::ifndef_kw_t )
630             assign_op( m_pimpl->m_ifndef_kw              , value, 0 );
631         BOOST_RTTI_CASE( cfg_detail::else_kw_t )
632             assign_op( m_pimpl->m_else_kw                , value, 0 );
633         BOOST_RTTI_CASE( cfg_detail::endif_kw_t )
634             assign_op( m_pimpl->m_endif_kw               , value, 0 );
635     }
636 }
637 
638 //____________________________________________________________________________//
639 
640 void
set_parameter(rtti::id_t id,bool value)641 config_file_iterator::set_parameter( rtti::id_t id, bool value )
642 {
643     BOOST_RTTI_SWITCH( id ) {
644         BOOST_RTTI_CASE( cfg_detail::trim_leading_spaces_t )
645             m_pimpl->m_trim_leading_spaces  = value;
646         BOOST_RTTI_CASE( cfg_detail::trim_trailing_spaces_t )
647             m_pimpl->m_trim_trailing_spaces = value;
648         BOOST_RTTI_CASE( cfg_detail::skip_empty_lines_t )
649             m_pimpl->m_skip_empty_lines     = value;
650         BOOST_RTTI_CASE( cfg_detail::detect_missing_macro_t )
651             m_pimpl->m_detect_missing_macro = value;
652     }
653 }
654 
655 //____________________________________________________________________________//
656 
657 void
set_parameter(rtti::id_t id,char_type value)658 config_file_iterator::set_parameter( rtti::id_t id, char_type value )
659 {
660     BOOST_RTTI_SWITCH( id ) {
661         BOOST_RTTI_CASE( cfg_detail::line_delimeter_t )
662             m_pimpl->m_line_delimeter       = value;
663     }
664 }
665 
666 //____________________________________________________________________________//
667 
668 void
set_parameter(rtti::id_t id,std::size_t value)669 config_file_iterator::set_parameter( rtti::id_t id, std::size_t value )
670 {
671     BOOST_RTTI_SWITCH( id ) {
672         BOOST_RTTI_CASE( cfg_detail::buffer_size_t )
673             m_pimpl->m_buffer_size          = value;
674     }
675 }
676 
677 //____________________________________________________________________________//
678 
679 } // namespace file
680 
681 } // namespace BOOST_TEST_UTILS_RUNTIME_PARAM_NAMESPACE
682 
683 } // namespace boost
684 
685 // EOF
686