• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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