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