Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / process / detail / posix / basic_cmd.hpp
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_POSIX_BASIC_CMD_HPP_
8 #define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
9
10 #include <boost/process/detail/posix/handler.hpp>
11 #include <boost/process/detail/posix/cmd.hpp>
12 #include <boost/algorithm/string/replace.hpp>
13 #include <boost/process/shell.hpp>
14 #include <boost/algorithm/string/trim.hpp>
15 #include <boost/algorithm/string/join.hpp>
16 #include <string>
17 #include <vector>
18
19 namespace boost
20 {
21 namespace process
22 {
23 namespace detail
24 {
25 namespace posix
26 {
27
28
29 inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
30 {
31     std::string st = exe;
32     for (auto & arg : data)
33     {
34         boost::replace_all(arg, "\"", "\\\"");
35
36         auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
37         if (it != arg.end())//ok, contains spaces.
38         {
39             //the first one is put directly onto the output,
40             //because then I don't have to copy the whole string
41             arg.insert(arg.begin(), '"' );
42             arg += '"'; //thats the post one.
43         }
44
45         if (!st.empty())//first one does not need a preceeding space
46             st += ' ';
47
48         st += arg;
49     }
50     return  st ;
51 }
52
53 inline std::vector<std::string>  build_args(const std::string & data)
54 {
55     std::vector<std::string>  st;
56     
57     typedef std::string::const_iterator itr_t;
58
59     //normal quotes outside can be stripped, inside ones marked as \" will be replaced.
60     auto make_entry = [](const itr_t & begin, const itr_t & end)
61     {
62         std::string data;
63         if ((*begin == '"') && (*(end-1) == '"'))
64             data.assign(begin+1, end-1);
65         else
66             data.assign(begin, end);
67
68         boost::replace_all(data, "\\\"", "\"");
69         return data;
70
71     };
72
73     bool in_quote = false;
74
75     auto part_beg = data.cbegin();
76     auto itr = data.cbegin();
77
78     for (; itr != data.cend(); itr++)
79     {
80         if (*itr == '"')
81             in_quote ^= true;
82
83         if (!in_quote && (*itr == ' '))
84         {
85             //alright, got a space
86
87             if ((itr != data.cbegin()) && (*(itr -1) != ' ' ))
88                 st.push_back(make_entry(part_beg, itr));
89
90             part_beg = itr+1;
91         }
92     }
93     if (part_beg != itr)
94         st.emplace_back(make_entry(part_beg, itr));
95
96
97     return st;
98 }
99
100 template<typename Char>
101 struct exe_cmd_init;
102
103 template<>
104 struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
105 {
106     exe_cmd_init(const exe_cmd_init & ) = delete;
107     exe_cmd_init(exe_cmd_init && ) = default;
108     exe_cmd_init(std::string && exe, std::vector<std::string> && args)
109             : exe(std::move(exe)), args(std::move(args)) {};
110     template <class Executor>
111     void on_setup(Executor& exec) 
112     {
113         if (exe.empty()) //cmd style
114         {
115             exec.exe = args.front().c_str();
116             exec.cmd_style = true;
117         }
118         else
119             exec.exe = &exe.front();
120
121
122         if (!args.empty())
123         {
124             cmd_impl = make_cmd();
125             exec.cmd_line = cmd_impl.data();
126         }
127     }
128     static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
129     static exe_cmd_init cmd     (std::string && cmd)
130     {
131         auto args = build_args(cmd);
132         return exe_cmd_init({}, std::move(args));
133     }
134
135     static exe_cmd_init exe_args_shell(std::string&& exe, std::vector<std::string> && args)
136     {
137         auto cmd = build_cmd_shell(std::move(exe), std::move(args));
138
139         std::vector<std::string> args_ = {"-c", std::move(cmd)};
140         std::string sh = shell().string();
141
142         return exe_cmd_init(std::move(sh), std::move(args_));
143     }
144     static exe_cmd_init cmd_shell(std::string&& cmd)
145     {
146         std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
147         std::string sh = shell().string();
148
149         return exe_cmd_init(
150                 std::move(sh),
151                 {std::move(args)});
152     }
153 private:
154     inline std::vector<char*> make_cmd();
155     std::string exe;
156     std::vector<std::string> args;
157     std::vector<char*> cmd_impl;
158 };
159
160 std::vector<char*> exe_cmd_init<char>::make_cmd()
161 {
162     std::vector<char*> vec;
163     if (!exe.empty())
164         vec.push_back(&exe.front());
165
166     for (auto & v : args)
167         vec.push_back(&v.front());
168
169     vec.push_back(nullptr);
170
171     return vec;
172 }
173
174
175 }}}}
176
177 #endif