1 // 2 // Copyright (c) 2012 Artyom Beilis (Tonkikh) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See 5 // accompanying file LICENSE or copy at 6 // http://www.boost.org/LICENSE_1_0.txt) 7 // 8 #ifndef BOOST_NOWIDE_ARGS_HPP_INCLUDED 9 #define BOOST_NOWIDE_ARGS_HPP_INCLUDED 10 11 #include <boost/config.hpp> 12 #ifdef BOOST_WINDOWS 13 #include <boost/nowide/stackstring.hpp> 14 #include <boost/nowide/windows.hpp> 15 #include <stdexcept> 16 #include <vector> 17 #endif 18 19 namespace boost { 20 namespace nowide { 21 #if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN) 22 class args 23 { 24 public: args(int &,char ** &)25 args(int&, char**&) 26 {} args(int &,char ** &,char ** &)27 args(int&, char**&, char**&) 28 {} 29 }; 30 31 #else 32 33 /// 34 /// \brief \c args is a class that temporarily replaces standard main() function arguments with their 35 /// equal, but UTF-8 encoded values under Microsoft Windows for the lifetime of the instance. 36 /// 37 /// The class uses \c GetCommandLineW(), \c CommandLineToArgvW() and \c GetEnvironmentStringsW() 38 /// in order to obtain Unicode-encoded values. 39 /// It does not relate to actual values of argc, argv and env under Windows. 40 /// 41 /// It restores the original values in its destructor (usually at the end of the \c main function). 42 /// 43 /// If any of the system calls fails, an exception of type std::runtime_error will be thrown 44 /// and argc, argv, env remain unchanged. 45 /// 46 /// \note The class owns the memory of the newly allocated strings. 47 /// So you need to keep it alive as long as you use the values. 48 /// 49 /// Usage: 50 /// \code 51 /// int main(int argc, char** argv, char** env) { 52 /// boost::nowide::args _(argc, argv, env); // Note the _ as a "don't care" name for the instance 53 /// // Use argv and env as usual, they are now UTF-8 encoded on Windows 54 /// return 0; // Memory held by args is released 55 /// } 56 /// \endcode 57 class args 58 { 59 public: 60 /// 61 /// Fix command line arguments 62 /// 63 args(int& argc, char**& argv) : 64 old_argc_(argc), old_argv_(argv), old_env_(0), old_argc_ptr_(&argc), old_argv_ptr_(&argv), old_env_ptr_(0) 65 { 66 fix_args(argc, argv); 67 } 68 /// 69 /// Fix command line arguments and environment 70 /// 71 args(int& argc, char**& argv, char**& env) : 72 old_argc_(argc), old_argv_(argv), old_env_(env), old_argc_ptr_(&argc), old_argv_ptr_(&argv), 73 old_env_ptr_(&env) 74 { 75 fix_args(argc, argv); 76 fix_env(env); 77 } 78 /// 79 /// Restore original argc, argv, env values, if changed 80 /// 81 ~args() 82 { 83 if(old_argc_ptr_) 84 *old_argc_ptr_ = old_argc_; 85 if(old_argv_ptr_) 86 *old_argv_ptr_ = old_argv_; 87 if(old_env_ptr_) 88 *old_env_ptr_ = old_env_; 89 } 90 91 private: 92 class wargv_ptr 93 { 94 wchar_t** p; 95 int argc; 96 97 public: 98 wargv_ptr() 99 { 100 p = CommandLineToArgvW(GetCommandLineW(), &argc); 101 } 102 ~wargv_ptr() 103 { 104 if(p) 105 LocalFree(p); 106 } 107 wargv_ptr(const wargv_ptr&) = delete; 108 wargv_ptr& operator=(const wargv_ptr&) = delete; 109 110 int size() const 111 { 112 return argc; 113 } 114 operator bool() const 115 { 116 return p != NULL; 117 } 118 const wchar_t* operator[](size_t i) const 119 { 120 return p[i]; 121 } 122 }; 123 class wenv_ptr 124 { 125 wchar_t* p; 126 127 public: 128 wenv_ptr() : p(GetEnvironmentStringsW()) 129 {} 130 ~wenv_ptr() 131 { 132 if(p) 133 FreeEnvironmentStringsW(p); 134 } 135 wenv_ptr(const wenv_ptr&) = delete; 136 wenv_ptr& operator=(const wenv_ptr&) = delete; 137 138 operator const wchar_t*() const 139 { 140 return p; 141 } 142 }; 143 144 void fix_args(int& argc, char**& argv) 145 { 146 const wargv_ptr wargv; 147 if(!wargv) 148 throw std::runtime_error("Could not get command line!"); 149 args_.resize(wargv.size() + 1, 0); 150 arg_values_.resize(wargv.size()); 151 for(int i = 0; i < wargv.size(); i++) 152 args_[i] = arg_values_[i].convert(wargv[i]); 153 argc = wargv.size(); 154 argv = &args_[0]; 155 } 156 void fix_env(char**& env) 157 { 158 const wenv_ptr wstrings; 159 if(!wstrings) 160 throw std::runtime_error("Could not get environment strings!"); 161 const wchar_t* wstrings_end = 0; 162 int count = 0; 163 for(wstrings_end = wstrings; *wstrings_end; wstrings_end += wcslen(wstrings_end) + 1) 164 count++; 165 env_.convert(wstrings, wstrings_end); 166 envp_.resize(count + 1, 0); 167 char* p = env_.get(); 168 int pos = 0; 169 for(int i = 0; i < count; i++) 170 { 171 if(*p != '=') 172 envp_[pos++] = p; 173 p += strlen(p) + 1; 174 } 175 env = &envp_[0]; 176 } 177 178 std::vector<char*> args_; 179 std::vector<short_stackstring> arg_values_; 180 stackstring env_; 181 std::vector<char*> envp_; 182 183 int old_argc_; 184 char** old_argv_; 185 char** old_env_; 186 187 int* old_argc_ptr_; 188 char*** old_argv_ptr_; 189 char*** old_env_ptr_; 190 }; 191 192 #endif 193 194 } // namespace nowide 195 } // namespace boost 196 #endif 197