basic_cmd.hpp 4.7 KB

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