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 { |
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> |
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> |
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> |
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 |
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: |
220 | prefix_name_mapper(const std::string& prefix) |
221 | : prefix(prefix) |
222 | {} |
223 | |
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 |
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 |
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 | |