1 // Copyright (c) 2016 Klemens D. Morgenstern
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)
7 #ifndef BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
8 #define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
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>
29 inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
32 for (auto & arg : data)
34 boost::replace_all(arg, "\"", "\\\"");
36 auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
37 if (it != arg.end())//ok, contains spaces.
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.
45 if (!st.empty())//first one does not need a preceeding space
53 inline std::vector<std::string> build_args(const std::string & data)
55 std::vector<std::string> st;
57 typedef std::string::const_iterator itr_t;
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)
63 if ((*begin == '"') && (*(end-1) == '"'))
64 data.assign(begin+1, end-1);
66 data.assign(begin, end);
68 boost::replace_all(data, "\\\"", "\"");
73 bool in_quote = false;
75 auto part_beg = data.cbegin();
76 auto itr = data.cbegin();
78 for (; itr != data.cend(); itr++)
83 if (!in_quote && (*itr == ' '))
85 //alright, got a space
87 if ((itr != data.cbegin()) && (*(itr -1) != ' ' ))
88 st.push_back(make_entry(part_beg, itr));
94 st.emplace_back(make_entry(part_beg, itr));
100 template<typename Char>
104 struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
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)
113 if (exe.empty()) //cmd style
115 exec.exe = args.front().c_str();
116 exec.cmd_style = true;
119 exec.exe = &exe.front();
124 cmd_impl = make_cmd();
125 exec.cmd_line = cmd_impl.data();
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)
131 auto args = build_args(cmd);
132 return exe_cmd_init({}, std::move(args));
135 static exe_cmd_init exe_args_shell(std::string&& exe, std::vector<std::string> && args)
137 auto cmd = build_cmd_shell(std::move(exe), std::move(args));
139 std::vector<std::string> args_ = {"-c", std::move(cmd)};
140 std::string sh = shell().string();
142 return exe_cmd_init(std::move(sh), std::move(args_));
144 static exe_cmd_init cmd_shell(std::string&& cmd)
146 std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
147 std::string sh = shell().string();
154 inline std::vector<char*> make_cmd();
156 std::vector<std::string> args;
157 std::vector<char*> cmd_impl;
160 std::vector<char*> exe_cmd_init<char>::make_cmd()
162 std::vector<char*> vec;
164 vec.push_back(&exe.front());
166 for (auto & v : args)
167 vec.push_back(&v.front());
169 vec.push_back(nullptr);