• 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 #include <boost/config.hpp>
8 
9 #define BOOST_PROGRAM_OPTIONS_SOURCE
10 #include <boost/program_options/config.hpp>
11 #include <boost/program_options/parsers.hpp>
12 #include <boost/program_options/options_description.hpp>
13 #include <boost/program_options/positional_options.hpp>
14 #include <boost/program_options/detail/cmdline.hpp>
15 #include <boost/program_options/detail/config_file.hpp>
16 #include <boost/program_options/environment_iterator.hpp>
17 #include <boost/program_options/detail/convert.hpp>
18 
19 #include <boost/bind.hpp>
20 #include <boost/throw_exception.hpp>
21 
22 #include <cctype>
23 #include <fstream>
24 
25 #if !defined(__GNUC__) || __GNUC__ < 3
26 #include <iostream>
27 #else
28 #include <istream>
29 #endif
30 
31 #ifdef _WIN32
32 #include <stdlib.h>
33 #else
34 #include <unistd.h>
35 #endif
36 
37 // The 'environ' should be declared in some cases. E.g. Linux man page says:
38 // (This variable must be declared in the user program, but is declared in
39 // the header file unistd.h in case the header files came from libc4 or libc5,
40 // and in case they came from glibc and _GNU_SOURCE was defined.)
41 // To be safe, declare it here.
42 
43 // It appears that on Mac OS X the 'environ' variable is not
44 // available to dynamically linked libraries.
45 // See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
46 // See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
47 #if defined(__APPLE__) && defined(__DYNAMIC__)
48 // The proper include for this is crt_externs.h, however it's not
49 // available on iOS. The right replacement is not known. See
50 // https://svn.boost.org/trac/boost/ticket/5053
51 extern "C" { extern char ***_NSGetEnviron(void); }
52 #define environ (*_NSGetEnviron())
53 #else
54 #if defined(__MWERKS__)
55 #include <crtl.h>
56 #else
57 #if !defined(_WIN32) || defined(__COMO_VERSION__)
58 extern char** environ;
59 #endif
60 #endif
61 #endif
62 
63 using namespace std;
64 
65 namespace boost { namespace program_options {
66 
67 #ifndef BOOST_NO_STD_WSTRING
68     namespace {
woption_from_option(const option & opt)69         woption woption_from_option(const option& opt)
70         {
71             woption result;
72             result.string_key = opt.string_key;
73             result.position_key = opt.position_key;
74             result.unregistered = opt.unregistered;
75 
76             std::transform(opt.value.begin(), opt.value.end(),
77                            back_inserter(result.value),
78                            boost::bind(from_utf8, _1));
79 
80             std::transform(opt.original_tokens.begin(),
81                            opt.original_tokens.end(),
82                            back_inserter(result.original_tokens),
83                            boost::bind(from_utf8, _1));
84             return result;
85         }
86     }
87 
88     basic_parsed_options<wchar_t>
basic_parsed_options(const parsed_options & po)89     ::basic_parsed_options(const parsed_options& po)
90     : description(po.description),
91       utf8_encoded_options(po),
92       m_options_prefix(po.m_options_prefix)
93     {
94         for (unsigned i = 0; i < po.options.size(); ++i)
95             options.push_back(woption_from_option(po.options[i]));
96     }
97 #endif
98 
99     template<class charT>
100     basic_parsed_options<charT>
parse_config_file(std::basic_istream<charT> & is,const options_description & desc,bool allow_unregistered)101     parse_config_file(std::basic_istream<charT>& is,
102                       const options_description& desc,
103                       bool allow_unregistered)
104     {
105         set<string> allowed_options;
106 
107         const vector<shared_ptr<option_description> >& options = desc.options();
108         for (unsigned i = 0; i < options.size(); ++i)
109         {
110             const option_description& d = *options[i];
111 
112             if (d.long_name().empty())
113                 boost::throw_exception(
114                     error("abbreviated option names are not permitted in options configuration files"));
115 
116             allowed_options.insert(d.long_name());
117         }
118 
119         // Parser return char strings
120         parsed_options result(&desc);
121         copy(detail::basic_config_file_iterator<charT>(
122                  is, allowed_options, allow_unregistered),
123              detail::basic_config_file_iterator<charT>(),
124              back_inserter(result.options));
125         // Convert char strings into desired type.
126         return basic_parsed_options<charT>(result);
127     }
128 
129     template
130     BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
131     parse_config_file(std::basic_istream<char>& is,
132                       const options_description& desc,
133                       bool allow_unregistered);
134 
135 #ifndef BOOST_NO_STD_WSTRING
136     template
137     BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t>
138     parse_config_file(std::basic_istream<wchar_t>& is,
139                       const options_description& desc,
140                       bool allow_unregistered);
141 #endif
142 
143     template<class charT>
144     basic_parsed_options<charT>
parse_config_file(const char * filename,const options_description & desc,bool allow_unregistered)145     parse_config_file(const char* filename,
146                       const options_description& desc,
147                       bool allow_unregistered)
148     {
149         // Parser return char strings
150         std::basic_ifstream< charT > strm(filename);
151         if (!strm)
152         {
153             boost::throw_exception(reading_file(filename));
154         }
155 
156         basic_parsed_options<charT> result
157                 = parse_config_file(strm, desc, allow_unregistered);
158 
159         if (strm.bad())
160         {
161             boost::throw_exception(reading_file(filename));
162         }
163 
164         return result;
165     }
166 
167     template
168     BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
169     parse_config_file(const char* filename,
170                       const options_description& desc,
171                       bool allow_unregistered);
172 
173 #ifndef BOOST_NO_STD_WSTRING
174     template
175     BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t>
176     parse_config_file(const char* filename,
177                       const options_description& desc,
178                       bool allow_unregistered);
179 #endif
180 
181 
182 // This versio, which accepts any options without validation, is disabled,
183 // in the hope that nobody will need it and we cant drop it altogether.
184 // Besides, probably the right way to handle all options is the '*' name.
185 #if 0
186     BOOST_PROGRAM_OPTIONS_DECL parsed_options
187     parse_config_file(std::istream& is)
188     {
189         detail::config_file_iterator cf(is, false);
190         parsed_options result(0);
191         copy(cf, detail::config_file_iterator(),
192              back_inserter(result.options));
193         return result;
194     }
195 #endif
196 
197     BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description & desc,const function1<std::string,std::string> & name_mapper)198     parse_environment(const options_description& desc,
199                       const function1<std::string, std::string>& name_mapper)
200     {
201         parsed_options result(&desc);
202 
203         for(environment_iterator i(environ), e; i != e; ++i) {
204             string option_name = name_mapper(i->first);
205 
206             if (!option_name.empty()) {
207                 option n;
208                 n.string_key = option_name;
209                 n.value.push_back(i->second);
210                 result.options.push_back(n);
211             }
212         }
213 
214         return result;
215     }
216 
217     namespace detail {
218         class prefix_name_mapper {
219         public:
prefix_name_mapper(const std::string & prefix)220             prefix_name_mapper(const std::string& prefix)
221             : prefix(prefix)
222             {}
223 
operator ()(const std::string & s)224             std::string operator()(const std::string& s)
225             {
226                 string result;
227                 if (s.find(prefix) == 0) {
228                     for(string::size_type n = prefix.size(); n < s.size(); ++n)
229                     {
230                         // Intel-Win-7.1 does not understand
231             // push_back on string.
232                         result += static_cast<char>(tolower(s[n]));
233                     }
234                 }
235                 return result;
236             }
237         private:
238             std::string prefix;
239         };
240     }
241 
242     BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description & desc,const std::string & prefix)243     parse_environment(const options_description& desc,
244                       const std::string& prefix)
245     {
246         return parse_environment(desc, detail::prefix_name_mapper(prefix));
247     }
248 
249     BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description & desc,const char * prefix)250     parse_environment(const options_description& desc, const char* prefix)
251     {
252         return parse_environment(desc, string(prefix));
253     }
254 
255 
256 
257 
258 }}
259