1 // Copyright (c) 2016 Klemens D. Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 
7 #ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
8 #define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
9 
10 #include <boost/algorithm/string/trim.hpp>
11 #include <boost/algorithm/string/replace.hpp>
12 #include <boost/process/shell.hpp>
13 #include <boost/process/detail/windows/handler.hpp>
14 
15 #include <vector>
16 #include <string>
17 #include <iterator>
18 
19 
20 namespace boost
21 {
22 namespace process
23 {
24 namespace detail
25 {
26 namespace windows
27 {
28 
build_args(const std::string & exe,std::vector<std::string> && data)29 inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
30 {
31     std::string st = exe;
32 
33     //put in quotes if it has spaces or double quotes
34     if(!exe.empty())
35     {
36         auto it = st.find_first_of(" \"");
37 
38         if(it != st.npos)//contains spaces.
39         {
40             // double existing quotes
41             boost::replace_all(st, "\"", "\"\"");
42 
43             // surround with quotes
44             st.insert(st.begin(), '"');
45             st += '"';
46         }
47     }
48 
49     for (auto & arg : data)
50     {
51         if(!arg.empty())
52         {
53             auto it = arg.find_first_of(" \"");//contains space or double quotes?
54             if(it != arg.npos)//yes
55             {
56                 // double existing quotes
57                 boost::replace_all(arg, "\"", "\"\"");
58 
59                 // surround with quotes
60                 arg.insert(arg.begin(), '"');
61                 arg += '"';
62             }
63         }
64 
65         if (!st.empty())//first one does not need a preceeding space
66             st += ' ';
67 
68         st += arg;
69     }
70     return st;
71 }
72 
build_args(const std::wstring & exe,std::vector<std::wstring> && data)73 inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
74 {
75     std::wstring st = exe;
76 
77     //put in quotes if it has spaces or double quotes
78     if(!exe.empty())
79     {
80         auto it = st.find_first_of(L" \"");
81 
82         if(it != st.npos)//contains spaces or double quotes.
83         {
84             // double existing quotes
85             boost::replace_all(st, L"\"", L"\"\"");
86 
87             // surround with quotes
88             st.insert(st.begin(), L'"');
89             st += L'"';
90         }
91     }
92 
93     for(auto & arg : data)
94     {
95         if(!arg.empty())
96         {
97             auto it = arg.find_first_of(L" \"");//contains space or double quotes?
98             if(it != arg.npos)//yes
99             {
100                 // double existing quotes
101                 boost::replace_all(arg, L"\"", L"\"\"");
102 
103                 // surround with quotes
104                 arg.insert(arg.begin(), L'"');
105                 arg += '"';
106             }
107         }
108 
109         if (!st.empty())//first one does not need a preceeding space
110             st += L' ';
111 
112         st += arg;
113     }
114     return st;
115 }
116 
117 template<typename Char>
118 struct exe_cmd_init : handler_base_ext
119 {
120     using value_type  = Char;
121     using string_type = std::basic_string<value_type>;
122 
c_argboost::process::detail::windows::exe_cmd_init123     static const char*    c_arg(char)    { return "/c";}
c_argboost::process::detail::windows::exe_cmd_init124     static const wchar_t* c_arg(wchar_t) { return L"/c";}
125 
exe_cmd_initboost::process::detail::windows::exe_cmd_init126     exe_cmd_init(const string_type & exe, bool cmd_only = false)
127                 : exe(exe), args({}), cmd_only(cmd_only) {};
exe_cmd_initboost::process::detail::windows::exe_cmd_init128     exe_cmd_init(string_type && exe, bool cmd_only = false)
129                 : exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
130 
exe_cmd_initboost::process::detail::windows::exe_cmd_init131     exe_cmd_init(string_type && exe, std::vector<string_type> && args)
132             : exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
133     template <class Executor>
on_setupboost::process::detail::windows::exe_cmd_init134     void on_setup(Executor& exec) const
135     {
136 
137         if (cmd_only && args.empty())
138             exec.cmd_line = exe.c_str();
139         else
140         {
141             exec.exe = exe.c_str();
142             exec.cmd_line = args.c_str();
143         }
144     }
exe_argsboost::process::detail::windows::exe_cmd_init145     static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
146     {
147         return exe_cmd_init<Char>(std::move(exe), std::move(args));
148     }
cmdboost::process::detail::windows::exe_cmd_init149     static exe_cmd_init<Char> cmd(string_type&& cmd)
150     {
151         return exe_cmd_init<Char>(std::move(cmd), true);
152     }
exe_args_shellboost::process::detail::windows::exe_cmd_init153     static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
154     {
155         std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
156         args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
157         string_type sh = get_shell(Char());
158 
159         return exe_cmd_init<Char>(std::move(sh), std::move(args_));
160     }
161 
get_shellboost::process::detail::windows::exe_cmd_init162     static std:: string get_shell(char)    {return shell(). string(codecvt()); }
get_shellboost::process::detail::windows::exe_cmd_init163     static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
164 
cmd_shellboost::process::detail::windows::exe_cmd_init165     static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
166     {
167         std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
168         string_type sh = get_shell(Char());
169 
170         return exe_cmd_init<Char>(
171                 std::move(sh),
172                 std::move(args));
173     }
174 private:
175     string_type exe;
176     string_type args;
177     bool cmd_only;
178 };
179 
180 }
181 
182 
183 
184 }
185 }
186 }
187 
188 
189 
190 #endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
191