#include "CommandLineInterpreter.h" #include "BoostLog.h" #include #include #include CommandLineInterpreter::CommandLineInterpreter(const DescriptionPointer &description, const std::string &prompt) : m_description(description), m_prompt(prompt) {} void CommandLineInterpreter::interpret(std::istream &inputStream) { std::string command; std::cout << m_prompt << std::flush; while (std::getline(inputStream, command, '\n')) { handleReadLine(command); std::cout << m_prompt << std::flush; } } void CommandLineInterpreter::handleReadLine(std::string line) { using namespace boost::program_options; if (m_description.expired()) { LOG(error) << "description has expired."; return; } auto description = m_description.lock(); std::vector args; // huu, ugly... args = splitCommandLine(std::string("--") + line); try { variables_map vm; store(command_line_parser(args).options(*description).run(), vm); notify(vm); } catch (boost::program_options::unknown_option &e) { std::cerr << "error: " << e.what() << std::endl; } catch (boost::program_options::invalid_command_line_syntax &e) { std::cerr << "error: " << e.what() << std::endl; } catch (boost::program_options::validation_error &e) { std::cerr << "error: " << e.what() << std::endl; } } std::vector CommandLineInterpreter::splitCommandLine(const std::string &input) { std::vector result; std::string::const_iterator i = input.begin(), e = input.end(); for (; i != e; ++i) if (!isspace((unsigned char)*i)) break; if (i != e) { std::string current; bool inside_quoted = false; int backslash_count = 0; for (; i != e; ++i) { if (*i == '"') { // '"' preceded by even number (n) of backslashes generates // n/2 backslashes and is a quoted block delimiter if (backslash_count % 2 == 0) { current.append(backslash_count / 2, '\\'); inside_quoted = !inside_quoted; // '"' preceded by odd number (n) of backslashes generates // (n-1)/2 backslashes and is literal quote. } else { current.append(backslash_count / 2, '\\'); current += '"'; } backslash_count = 0; } else if (*i == '\\') { ++backslash_count; } else { // Not quote or backslash. All accumulated backslashes should be // added if (backslash_count) { current.append(backslash_count, '\\'); backslash_count = 0; } if (isspace((unsigned char)*i) && !inside_quoted) { // Space outside quoted section terminate the current argument result.push_back(current); current.resize(0); for (; i != e && isspace((unsigned char)*i); ++i) ; --i; } else { current += *i; } } } // If we have trailing backslashes, add them if (backslash_count) current.append(backslash_count, '\\'); // If we have non-empty 'current' or we're still in quoted // section (even if 'current' is empty), add the last token. if (!current.empty() || inside_quoted) result.push_back(current); } return result; }