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