args.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //
  2. // Copyright (c) 2012 Artyom Beilis (Tonkikh)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt 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. ~args()
  28. {}
  29. };
  30. #else
  31. ///
  32. /// \brief args is a class that fixes standard main() function arguments and changes them to UTF-8 under
  33. /// Microsoft Windows.
  34. ///
  35. /// The class uses \c GetCommandLineW(), \c CommandLineToArgvW() and \c GetEnvironmentStringsW()
  36. /// in order to obtain the information. It does not relate to actual values of argc,argv and env
  37. /// under Windows.
  38. ///
  39. /// It restores the original values in its destructor
  40. ///
  41. /// If any of the system calls fails, an exception of type std::runtime_error will be thrown
  42. /// and argc, argv, env remain unchanged.
  43. ///
  44. /// \note the class owns the memory of the newly allocated strings
  45. ///
  46. class args
  47. {
  48. public:
  49. ///
  50. /// Fix command line arguments
  51. ///
  52. args(int& argc, char**& argv) :
  53. old_argc_(argc), old_argv_(argv), old_env_(0), old_argc_ptr_(&argc), old_argv_ptr_(&argv), old_env_ptr_(0)
  54. {
  55. fix_args(argc, argv);
  56. }
  57. ///
  58. /// Fix command line arguments and environment
  59. ///
  60. args(int& argc, char**& argv, char**& env) :
  61. old_argc_(argc), old_argv_(argv), old_env_(env), old_argc_ptr_(&argc), old_argv_ptr_(&argv),
  62. old_env_ptr_(&env)
  63. {
  64. fix_args(argc, argv);
  65. fix_env(env);
  66. }
  67. ///
  68. /// Restore original argc,argv,env values, if changed
  69. ///
  70. ~args()
  71. {
  72. if(old_argc_ptr_)
  73. *old_argc_ptr_ = old_argc_;
  74. if(old_argv_ptr_)
  75. *old_argv_ptr_ = old_argv_;
  76. if(old_env_ptr_)
  77. *old_env_ptr_ = old_env_;
  78. }
  79. private:
  80. class wargv_ptr
  81. {
  82. wchar_t** p;
  83. int argc;
  84. // Non-copyable
  85. wargv_ptr(const wargv_ptr&);
  86. wargv_ptr& operator=(const wargv_ptr&);
  87. public:
  88. wargv_ptr()
  89. {
  90. p = CommandLineToArgvW(GetCommandLineW(), &argc);
  91. }
  92. ~wargv_ptr()
  93. {
  94. if(p)
  95. LocalFree(p);
  96. }
  97. int size() const
  98. {
  99. return argc;
  100. }
  101. operator bool() const
  102. {
  103. return p != NULL;
  104. }
  105. const wchar_t* operator[](size_t i) const
  106. {
  107. return p[i];
  108. }
  109. };
  110. class wenv_ptr
  111. {
  112. wchar_t* p;
  113. // Non-copyable
  114. wenv_ptr(const wenv_ptr&);
  115. wenv_ptr& operator=(const wenv_ptr&);
  116. public:
  117. wenv_ptr() : p(GetEnvironmentStringsW())
  118. {}
  119. ~wenv_ptr()
  120. {
  121. if(p)
  122. FreeEnvironmentStringsW(p);
  123. }
  124. operator const wchar_t*() const
  125. {
  126. return p;
  127. }
  128. };
  129. void fix_args(int& argc, char**& argv)
  130. {
  131. const wargv_ptr wargv;
  132. if(!wargv)
  133. throw std::runtime_error("Could not get command line!");
  134. args_.resize(wargv.size() + 1, 0);
  135. arg_values_.resize(wargv.size());
  136. for(int i = 0; i < wargv.size(); i++)
  137. args_[i] = arg_values_[i].convert(wargv[i]);
  138. argc = wargv.size();
  139. argv = &args_[0];
  140. }
  141. void fix_env(char**& env)
  142. {
  143. const wenv_ptr wstrings;
  144. if(!wstrings)
  145. throw std::runtime_error("Could not get environment strings!");
  146. const wchar_t* wstrings_end = 0;
  147. int count = 0;
  148. for(wstrings_end = wstrings; *wstrings_end; wstrings_end += wcslen(wstrings_end) + 1)
  149. count++;
  150. env_.convert(wstrings, wstrings_end);
  151. envp_.resize(count + 1, 0);
  152. char* p = env_.get();
  153. int pos = 0;
  154. for(int i = 0; i < count; i++)
  155. {
  156. if(*p != '=')
  157. envp_[pos++] = p;
  158. p += strlen(p) + 1;
  159. }
  160. env = &envp_[0];
  161. }
  162. std::vector<char*> args_;
  163. std::vector<short_stackstring> arg_values_;
  164. stackstring env_;
  165. std::vector<char*> envp_;
  166. int old_argc_;
  167. char** old_argv_;
  168. char** old_env_;
  169. int* old_argc_ptr_;
  170. char*** old_argv_ptr_;
  171. char*** old_env_ptr_;
  172. };
  173. #endif
  174. } // namespace nowide
  175. } // namespace boost
  176. #endif