args.hpp 5.6 KB

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