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
53extern "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__)
60extern char** environ;
61#endif
62#endif
63#endif
64
65using namespace std;
66using namespace boost::placeholders;
67
68namespace 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

source code of boost/libs/program_options/src/parsers.cpp