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         return parse_config_file(strm, desc, allow_unregistered);
156     }
157 
158     template
159     BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
160     parse_config_file(const char* filename,
161                       const options_description& desc,
162                       bool allow_unregistered);
163 
164 #ifndef BOOST_NO_STD_WSTRING
165     template
166     BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t>
167     parse_config_file(const char* filename,
168                       const options_description& desc,
169                       bool allow_unregistered);
170 #endif
171 
172 
173 // This versio, which accepts any options without validation, is disabled,
174 // in the hope that nobody will need it and we cant drop it altogether.
175 // Besides, probably the right way to handle all options is the '*' name.
176 #if 0
177     BOOST_PROGRAM_OPTIONS_DECL parsed_options
178     parse_config_file(std::istream& is)
179     {
180         detail::config_file_iterator cf(is, false);
181         parsed_options result(0);
182         copy(cf, detail::config_file_iterator(),
183              back_inserter(result.options));
184         return result;
185     }
186 #endif
187 
188     BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description & desc,const function1<std::string,std::string> & name_mapper)189     parse_environment(const options_description& desc,
190                       const function1<std::string, std::string>& name_mapper)
191     {
192         parsed_options result(&desc);
193 
194         for(environment_iterator i(environ), e; i != e; ++i) {
195             string option_name = name_mapper(i->first);
196 
197             if (!option_name.empty()) {
198                 option n;
199                 n.string_key = option_name;
200                 n.value.push_back(i->second);
201                 result.options.push_back(n);
202             }
203         }
204 
205         return result;
206     }
207 
208     namespace detail {
209         class prefix_name_mapper {
210         public:
prefix_name_mapper(const std::string & prefix)211             prefix_name_mapper(const std::string& prefix)
212             : prefix(prefix)
213             {}
214 
operator ()(const std::string & s)215             std::string operator()(const std::string& s)
216             {
217                 string result;
218                 if (s.find(prefix) == 0) {
219                     for(string::size_type n = prefix.size(); n < s.size(); ++n)
220                     {
221                         // Intel-Win-7.1 does not understand
222             // push_back on string.
223                         result += static_cast<char>(tolower(s[n]));
224                     }
225                 }
226                 return result;
227             }
228         private:
229             std::string prefix;
230         };
231     }
232 
233     BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description & desc,const std::string & prefix)234     parse_environment(const options_description& desc,
235                       const std::string& prefix)
236     {
237         return parse_environment(desc, detail::prefix_name_mapper(prefix));
238     }
239 
240     BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description & desc,const char * prefix)241     parse_environment(const options_description& desc, const char* prefix)
242     {
243         return parse_environment(desc, string(prefix));
244     }
245 
246 
247 
248 
249 }}
250