From fe03b65c8bd952ac26a516e23f4c04bb014455e9 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Fri, 16 Oct 2020 23:43:11 +0300 Subject: CommandLine: saner API --- src/cmd_line.cpp | 130 +++++++++++++++++++++++++++---------------------------- src/process.cpp | 2 +- 2 files changed, 66 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/cmd_line.cpp b/src/cmd_line.cpp index b771299..468bb96 100644 --- a/src/cmd_line.cpp +++ b/src/cmd_line.cpp @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include #include @@ -30,59 +30,11 @@ struct LocalDelete { void operator()(wchar_t* argv[]) const { ::LocalFree(argv); } }; -} // namespace - -CommandLine CommandLine::query() { - return build_from_string(::GetCommandLineW()); -} - -CommandLine CommandLine::build_from_main(int argc, wchar_t* argv[]) { - if (argc < 1) - throw std::range_error{"invalid argc value"}; - - std::string argv0{narrow(argv[0])}; - --argc; - ++argv; - - std::vector args; - args.reserve(argc); - - for (int i = 0; i < argc; ++i) - args.emplace_back(narrow(argv[i])); - - return {std::move(argv0), std::move(args)}; -} - -std::vector CommandLine::escape_args() const { - std::vector safe; - safe.reserve(args.size()); - for (const auto& arg : args) - safe.emplace_back(escape(arg)); - return safe; -} - -std::string CommandLine::join_args() const { - return boost::algorithm::join(escape_args(), std::string{sep()}); -} - -std::string CommandLine::join() const { - if (!has_argv0()) - throw std::logic_error{"argv[0] isn't defined"}; - std::ostringstream oss; - oss << escape_argv0(); - if (has_args()) - oss << sep() << join_args(); - return oss.str(); -} - -CommandLine CommandLine::build_from_string(const std::string& src) { - return build_from_string(widen(src)); -} - -CommandLine CommandLine::build_from_string(std::wstring src) { +CommandLine do_parse(std::wstring src) { boost::trim(src); - if (src.empty()) - return {}; + if (src.empty()) { + throw std::runtime_error{"Command line cannot be an empty string"}; + } int argc = 0; std::unique_ptr argv{::CommandLineToArgvW(src.c_str(), &argc)}; @@ -90,8 +42,9 @@ CommandLine CommandLine::build_from_string(std::wstring src) { if (argv.get() == NULL) throw error::windows(GetLastError(), "CommandLineToArgvW"); - if (argc == 0) - return {}; + if (argc == 0) { + throw std::runtime_error{"Command line must contain at least one token"}; + } std::string argv0{narrow(argv.get()[0])}; @@ -104,17 +57,31 @@ CommandLine CommandLine::build_from_string(std::wstring src) { return {std::move(argv0), std::move(args)}; } -std::string CommandLine::escape_for_cmd(const std::string& arg) { - BOOST_STATIC_CONSTEXPR auto escape_symbol = '^'; - static const std::string dangerous_symbols{"^!\"%&()<>|"}; +} // namespace - auto safe = escape(arg); - for (const auto danger : dangerous_symbols) { - std::ostringstream replacement; - replacement << escape_symbol << danger; - boost::replace_all(safe, std::string{danger}, replacement.str()); - } - return safe; +CommandLine CommandLine::query() { + return do_parse(::GetCommandLineW()); +} + +CommandLine CommandLine::parse(const std::string& src) { + return do_parse(widen(src)); +} + +CommandLine CommandLine::from_main(int argc, wchar_t* argv[]) { + if (argc < 1) + throw std::range_error{"argc must be a positive number"}; + + std::string argv0{narrow(argv[0])}; + --argc; + ++argv; + + std::vector args; + args.reserve(argc); + + for (int i = 0; i < argc; ++i) + args.emplace_back(narrow(argv[i])); + + return {std::move(argv0), std::move(args)}; } std::string CommandLine::escape(const std::string& arg) { @@ -154,4 +121,37 @@ std::string CommandLine::escape(const std::string& arg) { return safe; } +std::string CommandLine::escape_cmd(const std::string& arg) { + BOOST_STATIC_CONSTEXPR auto escape_symbol = '^'; + static const std::string dangerous_symbols{"^!\"%&()<>|"}; + + auto safe = escape(arg); + for (const auto danger : dangerous_symbols) { + std::ostringstream replacement; + replacement << escape_symbol << danger; + boost::replace_all(safe, std::string{danger}, replacement.str()); + } + return safe; +} + +std::string CommandLine::to_string() const { + std::ostringstream oss; + oss << escape(get_argv0()); + if (has_args()) + oss << token_sep() << args_to_string(); + return oss.str(); +} + +std::string CommandLine::args_to_string() const { + return boost::algorithm::join(escape_args(), std::string{token_sep()}); +} + +std::vector CommandLine::escape_args() const { + std::vector safe; + safe.reserve(args.size()); + for (const auto& arg : args) + safe.emplace_back(escape(arg)); + return safe; +} + } // namespace winapi diff --git a/src/process.cpp b/src/process.cpp index 508f9e1..f95bc56 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -52,7 +52,7 @@ Handle create_process(EscapedCommandLine cmd_line, Process::IO& io) { } EscapedCommandLine escape_command_line(const CommandLine& cmd_line) { - const auto unicode_cmd_line = widen(cmd_line.join()); + const auto unicode_cmd_line = widen(cmd_line.to_string()); EscapedCommandLine buffer; buffer.reserve(unicode_cmd_line.size() + 1); buffer.assign(unicode_cmd_line.cbegin(), unicode_cmd_line.cend()); -- cgit v1.2.3