• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Vladimir Prus 2002-2004.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt
4 // or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 
7 #ifndef BOOST_CONFIG_FILE_VP_2003_01_02
8 #define BOOST_CONFIG_FILE_VP_2003_01_02
9 
10 #include <iosfwd>
11 #include <string>
12 #include <set>
13 
14 #include <boost/noncopyable.hpp>
15 #include <boost/program_options/config.hpp>
16 #include <boost/program_options/option.hpp>
17 #include <boost/program_options/eof_iterator.hpp>
18 
19 #include <boost/detail/workaround.hpp>
20 #include <boost/program_options/detail/convert.hpp>
21 
22 #if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
23 #include <istream> // std::getline
24 #endif
25 
26 #include <boost/static_assert.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #include <boost/shared_ptr.hpp>
29 
30 #ifdef BOOST_MSVC
31 # pragma warning(push)
32 # pragma warning(disable: 4251) // class XYZ needs to have dll-interface to be used by clients of class XYZ
33 #endif
34 
35 
36 
37 namespace boost { namespace program_options { namespace detail {
38 
39     /** Standalone parser for config files in ini-line format.
40         The parser is a model of single-pass lvalue iterator, and
41         default constructor creates past-the-end-iterator. The typical usage is:
42         config_file_iterator i(is, ... set of options ...), e;
43         for(; i !=e; ++i) {
44             *i;
45         }
46 
47         Syntax conventions:
48 
49         - config file can not contain positional options
50         - '#' is comment character: it is ignored together with
51           the rest of the line.
52         - variable assignments are in the form
53           name '=' value.
54           spaces around '=' are trimmed.
55         - Section names are given in brackets.
56 
57          The actual option name is constructed by combining current section
58          name and specified option name, with dot between. If section_name
59          already contains dot at the end, new dot is not inserted. For example:
60          @verbatim
61          [gui.accessibility]
62          visual_bell=yes
63          @endverbatim
64          will result in option "gui.accessibility.visual_bell" with value
65          "yes" been returned.
66 
67          TODO: maybe, we should just accept a pointer to options_description
68          class.
69      */
70     class BOOST_PROGRAM_OPTIONS_DECL common_config_file_iterator
71         : public eof_iterator<common_config_file_iterator, option>
72     {
73     public:
common_config_file_iterator()74         common_config_file_iterator() { found_eof(); }
75         common_config_file_iterator(
76             const std::set<std::string>& allowed_options,
77             bool allow_unregistered = false);
78 
~common_config_file_iterator()79         virtual ~common_config_file_iterator() {}
80 
81     public: // Method required by eof_iterator
82 
83         void get();
84 
85 #if BOOST_WORKAROUND(_MSC_VER, <= 1900)
decrement()86         void decrement() {}
advance(difference_type)87         void advance(difference_type) {}
88 #endif
89 
90     protected: // Stubs for derived classes
91 
92         // Obtains next line from the config file
93         // Note: really, this design is a bit ugly
94         // The most clean thing would be to pass 'line_iterator' to
95         // constructor of this class, but to avoid templating this class
96         // we'd need polymorphic iterator, which does not exist yet.
getline(std::string &)97         virtual bool getline(std::string&) { return false; }
98 
99     private:
100         /** Adds another allowed option. If the 'name' ends with
101             '*', then all options with the same prefix are
102             allowed. For example, if 'name' is 'foo*', then 'foo1' and
103             'foo_bar' are allowed. */
104         void add_option(const char* name);
105 
106         // Returns true if 's' is a registered option name.
107         bool allowed_option(const std::string& s) const;
108 
109         // That's probably too much data for iterator, since
110         // it will be copied, but let's not bother for now.
111         std::set<std::string> allowed_options;
112         // Invariant: no element is prefix of other element.
113         std::set<std::string> allowed_prefixes;
114         std::string m_prefix;
115         bool m_allow_unregistered;
116     };
117 
118     template<class charT>
119     class basic_config_file_iterator : public common_config_file_iterator {
120     public:
basic_config_file_iterator()121         basic_config_file_iterator()
122         {
123             found_eof();
124         }
125 
126         /** Creates a config file parser for the specified stream.
127         */
128         basic_config_file_iterator(std::basic_istream<charT>& is,
129                                    const std::set<std::string>& allowed_options,
130                                    bool allow_unregistered = false);
131 
132     private: // base overrides
133 
134         bool getline(std::string&);
135 
136     private: // internal data
137         shared_ptr<std::basic_istream<charT> > is;
138     };
139 
140     typedef basic_config_file_iterator<char> config_file_iterator;
141     typedef basic_config_file_iterator<wchar_t> wconfig_file_iterator;
142 
143 
144     struct null_deleter
145     {
operator ()boost::program_options::detail::null_deleter146         void operator()(void const *) const {}
147     };
148 
149 
150     template<class charT>
151     basic_config_file_iterator<charT>::
basic_config_file_iterator(std::basic_istream<charT> & is,const std::set<std::string> & allowed_options,bool allow_unregistered)152     basic_config_file_iterator(std::basic_istream<charT>& is,
153                                const std::set<std::string>& allowed_options,
154                                bool allow_unregistered)
155     : common_config_file_iterator(allowed_options, allow_unregistered)
156     {
157         this->is.reset(&is, null_deleter());
158         get();
159     }
160 
161     // Specializing this function for wchar_t causes problems on
162     // borland and vc7, as well as on metrowerks. On the first two
163     // I don't know a workaround, so make use of 'to_internal' to
164     // avoid specialization.
165     template<class charT>
166     bool
getline(std::string & s)167     basic_config_file_iterator<charT>::getline(std::string& s)
168     {
169         std::basic_string<charT> in;
170         if (std::getline(*is, in)) {
171             s = to_internal(in);
172             return true;
173         } else {
174             return false;
175         }
176     }
177 
178     // Specialization is needed to workaround getline bug on Comeau.
179 #if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4303)) || \
180         (defined(__sgi) && BOOST_WORKAROUND(_COMPILER_VERSION, BOOST_TESTED_AT(741)))
181     template<>
182     bool
183     basic_config_file_iterator<wchar_t>::getline(std::string& s);
184 #endif
185 
186 
187 
188 }}}
189 
190 #ifdef BOOST_MSVC
191 # pragma warning(pop)
192 #endif
193 
194 #endif
195