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