6 #include <winapi/cmd_line.hpp>
8 #include <winapi/utf8.hpp>
9 #include <winapi/utils.hpp>
11 #include <boost/algorithm/string.hpp>
29 std::vector<std::string> narrow_all(
int argc,
wchar_t** argv) {
30 std::vector<std::string> utf;
32 for (
int i = 0; i < argc; ++i)
33 utf.emplace_back(narrow(argv[i]));
37 CommandLine do_parse(std::wstring src) {
40 throw std::runtime_error{
"Command line cannot be an empty string"};
44 std::unique_ptr<wchar_t*, LocalDelete> argv{::CommandLineToArgvW(src.c_str(), &argc)};
46 if (argv.get() == NULL) {
47 throw error::windows(GetLastError(),
"CommandLineToArgvW");
50 throw std::runtime_error{
"Command line must contain at least one token"};
53 return CommandLine{narrow_all(argc, argv.get())};
56 std::string split_argv0(std::vector<std::string>& argv) {
58 throw std::range_error{
"argv must contain at least one element"};
61 argv.erase(argv.begin());
65 std::vector<std::string> escape_all(
const std::vector<std::string>& xs) {
66 std::vector<std::string> escaped;
67 escaped.reserve(xs.size());
68 for (
const auto& x : xs)
69 escaped.emplace_back(CommandLine::escape(x));
76 return do_parse(::GetCommandLineW());
80 return do_parse(widen(src));
85 throw std::range_error{
"argc must be a positive number"};
90 m_argv0 = split_argv0(m_args);
93 std::string CommandLine::escape(
const std::string& arg) {
94 std::ostringstream safe;
97 for (
auto it = arg.cbegin(); it != arg.cend(); ++it) {
98 std::size_t numof_backslashes = 0;
100 for (; it != arg.cend() && *it ==
'\\'; ++it)
103 if (it == arg.cend()) {
104 safe << std::string(2 * numof_backslashes,
'\\');
110 safe << std::string(2 * numof_backslashes + 1,
'\\');
114 safe << std::string(numof_backslashes,
'\\');
125 std::string CommandLine::escape_cmd(
const std::string& arg) {
126 static constexpr
auto escape_symbol =
'^';
127 static const std::string dangerous_symbols{
"^!\"%&()<>|"};
129 auto safe = escape(arg);
130 for (
const auto danger : dangerous_symbols) {
131 std::ostringstream replacement;
132 replacement << escape_symbol << danger;
133 boost::replace_all(safe, std::string{danger}, replacement.str());
139 return boost::algorithm::join(escape_argv(), std::string{token_sep()});
143 return boost::algorithm::join(escape_args(), std::string{token_sep()});
152 std::vector<std::string> CommandLine::escape_args()
const {
156 std::vector<std::string> CommandLine::escape_argv()
const {
Command line for the current process or for launching new processes.
static CommandLine from_main(int argc, wchar_t *argv[])
std::string get_argv0() const
static CommandLine query()
static CommandLine parse(const std::string &src)
std::vector< std::string > get_argv() const
std::string to_string() const
const std::vector< std::string > & get_args() const
std::string args_to_string() const
Make std::system_error work with GetLastError().