args.hpp 5.6 KB

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