161 lines
4.3 KiB
C
161 lines
4.3 KiB
C
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// Licensed under the MIT License.
|
||
|
|
||
|
#ifndef CMDPARSER_H
|
||
|
#define CMDPARSER_H
|
||
|
|
||
|
#include <map>
|
||
|
#include <vector>
|
||
|
#include <string>
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <utility>
|
||
|
#include <functional>
|
||
|
|
||
|
namespace CmdParser
|
||
|
{
|
||
|
typedef std::function<void(const std::vector<char *> &)> OptionHandlerFunc;
|
||
|
typedef std::function<void()> VoidHandlerFunc;
|
||
|
|
||
|
class ArgumentError : public std::runtime_error
|
||
|
{
|
||
|
public:
|
||
|
ArgumentError(const std::string option, const std::string message) :
|
||
|
std::runtime_error(message),
|
||
|
m_option(option),
|
||
|
m_message(message)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
const std::string option() const
|
||
|
{
|
||
|
return m_option;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
const std::string m_option, m_message;
|
||
|
};
|
||
|
|
||
|
class OptionParser
|
||
|
{
|
||
|
public:
|
||
|
OptionParser() {}
|
||
|
|
||
|
void RegisterOption(std::string option_list, std::string description, int arg_count, OptionHandlerFunc &&handler)
|
||
|
{
|
||
|
std::istringstream split(option_list);
|
||
|
std::ostringstream options_str;
|
||
|
std::string option;
|
||
|
bool first = true;
|
||
|
while (std::getline(split, option, '|'))
|
||
|
{
|
||
|
m_cmd_options[option] = OptionHandler{ arg_count, handler };
|
||
|
|
||
|
if (first)
|
||
|
{
|
||
|
options_str << option;
|
||
|
first = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
options_str << ", " << option;
|
||
|
}
|
||
|
}
|
||
|
m_cmd_usage.push_back(std::make_pair(options_str.str(), description));
|
||
|
}
|
||
|
|
||
|
void RegisterOption(std::string option_list, std::string description, VoidHandlerFunc &&handler)
|
||
|
{
|
||
|
RegisterOption(option_list, description, 0, [handler](const std::vector<char *> &) { handler(); });
|
||
|
}
|
||
|
|
||
|
void PrintOptions()
|
||
|
{
|
||
|
std::cout << " Options:" << std::endl;
|
||
|
size_t max_options_length = 0;
|
||
|
for (std::pair<std::string, std::string> usage : m_cmd_usage)
|
||
|
{
|
||
|
if (usage.first.length() > max_options_length)
|
||
|
max_options_length = usage.first.length();
|
||
|
}
|
||
|
for (std::pair<std::string, std::string> usage : m_cmd_usage)
|
||
|
{
|
||
|
std::cout << " " << usage.first << std::string(max_options_length - usage.first.length() + 2, ' ');
|
||
|
std::istringstream split(usage.second);
|
||
|
std::string line;
|
||
|
bool first = true;
|
||
|
while (std::getline(split, line))
|
||
|
{
|
||
|
if (first)
|
||
|
{
|
||
|
std::cout << line << std::endl;
|
||
|
first = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
std::cout << " " << std::string(max_options_length + 4, ' ') << line << std::endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Parse the command line arguments, and run the handler for each.
|
||
|
*
|
||
|
* Returns the number of remaining arguments after parsing.
|
||
|
* May throw ArgumentError if a handler fails.
|
||
|
*/
|
||
|
int ParseCmd(int argc, char **argv)
|
||
|
{
|
||
|
if (argc < 2)
|
||
|
return 0;
|
||
|
|
||
|
for (int i = 1; i < argc; i++)
|
||
|
{
|
||
|
std::string option = argv[i];
|
||
|
if (m_cmd_options.count(option) == 0)
|
||
|
return argc - i;
|
||
|
|
||
|
const OptionHandler &handler = m_cmd_options[option];
|
||
|
std::vector<char *> args;
|
||
|
if (i + handler.arg_count < argc)
|
||
|
{
|
||
|
for (int j = 0; j < handler.arg_count; j++)
|
||
|
{
|
||
|
args.push_back(argv[i + j + 1]);
|
||
|
}
|
||
|
try
|
||
|
{
|
||
|
handler.handler(args);
|
||
|
}
|
||
|
catch (ArgumentError &)
|
||
|
{
|
||
|
throw;
|
||
|
}
|
||
|
catch (std::exception &e)
|
||
|
{
|
||
|
throw ArgumentError(option, e.what());
|
||
|
}
|
||
|
i += handler.arg_count;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return argc - i - 1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
struct OptionHandler
|
||
|
{
|
||
|
int arg_count;
|
||
|
OptionHandlerFunc handler;
|
||
|
};
|
||
|
|
||
|
std::map<std::string, OptionHandler> m_cmd_options;
|
||
|
std::vector<std::pair<std::string, std::string>> m_cmd_usage;
|
||
|
};
|
||
|
} // namespace CmdParser
|
||
|
|
||
|
#endif /* CMDPARSER_H */
|