blob: b9110e0e79365ac24d96dd4195e101d9783fde73 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#define _BSD_SOURCE
#include "Command.h"
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include "TraceStream.h"
#include "core.h"
#include "main.h"
using namespace std;
namespace rr {
bool ParsedOption::verify_valid_int(int64_t min, int64_t max) const {
if (int_value < min || int_value > max) {
fprintf(
stderr,
"Value %s for parameter %s was not valid (allowed range %lld-%lld)\n",
value.c_str(), arg.c_str(), (long long)min, (long long)max);
return false;
}
return true;
}
static vector<Command*>* command_list;
Command::Command(const char* name, const char* help) : name(name), help(help) {
if (!command_list) {
command_list = new vector<Command*>();
}
command_list->push_back(this);
}
Command* Command::command_for_name(const std::string& name) {
for (auto& it : *command_list) {
if (strcmp(it->name, name.c_str()) == 0) {
return it;
}
}
return nullptr;
}
bool Command::less_than_by_name(Command* c1, Command* c2) {
return strcmp(c1->name, c2->name) < 0;
}
void Command::print_help_all(FILE* out) {
vector<Command*> cmds;
for (auto& it : *command_list) {
if (!it->help) {
continue;
}
cmds.push_back(it);
}
sort(cmds.begin(), cmds.end(), less_than_by_name);
for (auto& it : cmds) {
const char* c = strchr(it->help, '\n');
if (c) {
fprintf(out, "%.*s\n", (int)(c - it->help), it->help);
} else {
fputs(it->help, out);
}
}
}
void Command::print_help(FILE* out) {
if (help) {
fputs(help, out);
print_global_options(out);
} else {
print_usage(out);
}
}
static bool consume_args(std::vector<std::string>& args, size_t count) {
args.erase(args.begin(), args.begin() + count);
return true;
}
static void assign_param(ParsedOption* opt, const char* s) {
opt->value = s;
opt->int_value = INT64_MIN;
if (!opt->value.empty()) {
char* end;
int64_t v = strtoll(s, &end, 0);
if (*end == 0) {
opt->int_value = v;
}
}
}
bool Command::parse_option(std::vector<std::string>& args,
const OptionSpec* option_specs, size_t count,
ParsedOption* out) {
if (args.size() == 0 || args[0][0] != '-') {
return false;
}
out->arg = args[0];
for (size_t i = 0; i < count; ++i) {
if (args[0][1] == option_specs[i].short_name && args[0][1] >= 32) {
out->short_name = option_specs[i].short_name;
switch (option_specs[i].param) {
case NO_PARAMETER:
if (args[0][2] == 0) {
return consume_args(args, 1);
}
return false;
case HAS_PARAMETER:
if (args[0][2] == '=') {
assign_param(out, args[0].c_str() + 3);
return consume_args(args, 1);
}
if (args[0][2] != 0) {
assign_param(out, args[0].c_str() + 2);
return consume_args(args, 1);
}
if (args.size() >= 2) {
assign_param(out, args[1].c_str());
return consume_args(args, 2);
}
return false;
default:
DEBUG_ASSERT(0 && "Unknown parameter type");
}
} else if (args[0][1] == '-') {
size_t equals = args[0].find('=');
size_t cmp_len = (equals == string::npos ? 9999 : equals) - 2;
if (cmp_len >= strlen(option_specs[i].long_name) &&
strncmp(args[0].c_str() + 2, option_specs[i].long_name, cmp_len) == 0) {
out->short_name = option_specs[i].short_name;
switch (option_specs[i].param) {
case NO_PARAMETER:
return consume_args(args, 1);
case HAS_PARAMETER:
if (equals == string::npos) {
if (args.size() >= 2) {
assign_param(out, args[1].c_str());
return consume_args(args, 2);
}
return false;
}
assign_param(out, args[0].c_str() + equals + 1);
return consume_args(args, 1);
default:
DEBUG_ASSERT(0 && "Unknown parameter type");
}
}
}
}
return false;
}
bool Command::verify_not_option(std::vector<std::string>& args) {
if (args.size() > 0 && args[0][0] == '-') {
if (args[0].length() == 2 && args[0][1] == '-') {
args.erase(args.begin());
return true;
}
fprintf(stderr, "Invalid option %s\n", args[0].c_str());
return false;
}
return true;
}
bool Command::parse_optional_trace_dir(vector<string>& args, string* out) {
if (!verify_not_option(args)) {
return false;
}
if (args.size() > 0) {
*out = args[0];
args.erase(args.begin());
} else {
*out = string();
}
return true;
}
bool Command::parse_literal(std::vector<std::string>& args, const char* lit) {
if (args.size() > 0 && args[0] == lit) {
args.erase(args.begin());
return true;
} else {
return false;
}
}
} // namespace rr