source: NonGTP/Boost/boost/test/utils/runtime/file/config_file_iterator.cpp @ 857

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