aboutsummaryrefslogtreecommitdiffstats
path: root/native/dicttoolkit
diff options
context:
space:
mode:
authorKeisuke Kuroyanagi <ksk@google.com>2014-11-09 03:47:30 +0900
committerKeisuke Kuroyanagi <ksk@google.com>2014-11-21 12:25:30 +0900
commit1f8d4f47e445bd4316f3e09228cff6de64105f13 (patch)
tree82959f0819a17ce57d237271be191ce4aa416486 /native/dicttoolkit
parent681dbc295b07b9db6c32d1b7074e99d9e2fa651d (diff)
downloadlatinime-1f8d4f47e445bd4316f3e09228cff6de64105f13.tar.gz
latinime-1f8d4f47e445bd4316f3e09228cff6de64105f13.tar.xz
latinime-1f8d4f47e445bd4316f3e09228cff6de64105f13.zip
Implement ArgumentsParser::parseArguments and add tests.
Bug: 10059681 Change-Id: I6511a46c879d7a52d0bb4fcab445a66bc40db98c
Diffstat (limited to 'native/dicttoolkit')
-rw-r--r--native/dicttoolkit/src/command_executors/makedict_executor.cpp6
-rw-r--r--native/dicttoolkit/src/utils/arguments_and_options.h23
-rw-r--r--native/dicttoolkit/src/utils/arguments_parser.cpp81
-rw-r--r--native/dicttoolkit/src/utils/arguments_parser.h35
-rw-r--r--native/dicttoolkit/tests/utils/arguments_parser_test.cpp74
5 files changed, 195 insertions, 24 deletions
diff --git a/native/dicttoolkit/src/command_executors/makedict_executor.cpp b/native/dicttoolkit/src/command_executors/makedict_executor.cpp
index 8a84e8069..4b0a5aeea 100644
--- a/native/dicttoolkit/src/command_executors/makedict_executor.cpp
+++ b/native/dicttoolkit/src/command_executors/makedict_executor.cpp
@@ -24,6 +24,12 @@ namespace dicttoolkit {
const char *const MakedictExecutor::COMMAND_NAME = "makedict";
/* static */ int MakedictExecutor::run(const int argc, char **argv) {
+ const ArgumentsAndOptions argumentsAndOptions =
+ getArgumentsParser().parseArguments(argc, argv, true /* printErrorMessages */);
+ if (!argumentsAndOptions.isValid()) {
+ printUsage();
+ return 1;
+ }
fprintf(stderr, "Command '%s' has not been implemented yet.\n", COMMAND_NAME);
return 0;
}
diff --git a/native/dicttoolkit/src/utils/arguments_and_options.h b/native/dicttoolkit/src/utils/arguments_and_options.h
index d8f5985e5..2d81b1ecb 100644
--- a/native/dicttoolkit/src/utils/arguments_and_options.h
+++ b/native/dicttoolkit/src/utils/arguments_and_options.h
@@ -42,6 +42,29 @@ class ArgumentsAndOptions {
return mOptions.find(optionName) != mOptions.end();
}
+ const std::string &getOptionValue(const std::string &optionName) const {
+ const auto &it = mOptions.find(optionName);
+ ASSERT(it != mOptions.end());
+ return it->second;
+ }
+
+ bool hasArgument(const std::string &name) const {
+ const auto &it = mArguments.find(name);
+ return it != mArguments.end() && !it->second.empty();
+ }
+
+ const std::string &getSingleArgument(const std::string &name) const {
+ const auto &it = mArguments.find(name);
+ ASSERT(it != mArguments.end() && !it->second.empty());
+ return it->second.front();
+ }
+
+ const std::vector<std::string> &getVariableLengthArguments(const std::string &name) const {
+ const auto &it = mArguments.find(name);
+ ASSERT(it != mArguments.end());
+ return it->second;
+ }
+
private:
DISALLOW_ASSIGNMENT_OPERATOR(ArgumentsAndOptions);
diff --git a/native/dicttoolkit/src/utils/arguments_parser.cpp b/native/dicttoolkit/src/utils/arguments_parser.cpp
index 52cc7b21d..1451284f1 100644
--- a/native/dicttoolkit/src/utils/arguments_parser.cpp
+++ b/native/dicttoolkit/src/utils/arguments_parser.cpp
@@ -21,7 +21,7 @@
namespace latinime {
namespace dicttoolkit {
-const int ArgumentSpec::UNLIMITED_COUNT = -1;
+const size_t ArgumentSpec::UNLIMITED_COUNT = S_INT_MAX;
bool ArgumentsParser::validateSpecs() const {
std::unordered_set<std::string> argumentNameSet;
@@ -53,7 +53,7 @@ void ArgumentsParser::printUsage(const std::string &commandName,
const std::string &optionName = option.first;
const OptionSpec &spec = option.second;
printf(" [-%s", optionName.c_str());
- if (spec.takeValue()) {
+ if (spec.needsValue()) {
printf(" <%s>", spec.getValueName().c_str());
}
printf("]");
@@ -74,11 +74,11 @@ void ArgumentsParser::printUsage(const std::string &commandName,
const std::string &optionName = option.first;
const OptionSpec &spec = option.second;
printf(" -%s", optionName.c_str());
- if (spec.takeValue()) {
+ if (spec.needsValue()) {
printf(" <%s>", spec.getValueName().c_str());
}
printf("\t\t\t%s", spec.getDescription().c_str());
- if (spec.takeValue() && !spec.getDefaultValue().empty()) {
+ if (spec.needsValue() && !spec.getDefaultValue().empty()) {
printf("\tdefault: %s", spec.getDefaultValue().c_str());
}
printf("\n");
@@ -89,9 +89,76 @@ void ArgumentsParser::printUsage(const std::string &commandName,
printf("\n\n");
}
-const ArgumentsAndOptions ArgumentsParser::parseArguments(const int argc, char **argv) const {
- // TODO: Implement
- return ArgumentsAndOptions();
+const ArgumentsAndOptions ArgumentsParser::parseArguments(const int argc, char **argv,
+ const bool printErrorMessage) const {
+ if (argc <= 0) {
+ AKLOGE("Invalid argc (%d).", argc);
+ ASSERT(false);
+ return ArgumentsAndOptions();
+ }
+ std::unordered_map<std::string, std::string> options;
+ for (const auto &entry : mOptionSpecs) {
+ const std::string &optionName = entry.first;
+ const OptionSpec &optionSpec = entry.second;
+ if (optionSpec.needsValue() && !optionSpec.getDefaultValue().empty()) {
+ // Set default value.
+ options[optionName] = optionSpec.getDefaultValue();
+ }
+ }
+ std::unordered_map<std::string, std::vector<std::string>> arguments;
+ auto argumentSpecIt = mArgumentSpecs.cbegin();
+ for (int i = 1; i < argc; ++i) {
+ const std::string arg = argv[i];
+ if (arg.length() > 1 && arg[0] == '-') {
+ // option
+ const std::string optionName = arg.substr(1);
+ const auto it = mOptionSpecs.find(optionName);
+ if (it == mOptionSpecs.end()) {
+ if (printErrorMessage) {
+ fprintf(stderr, "Unknown option: '%s'\n", optionName.c_str());
+ }
+ return ArgumentsAndOptions();
+ }
+ std::string optionValue;
+ if (it->second.needsValue()) {
+ ++i;
+ if (i >= argc) {
+ if (printErrorMessage) {
+ fprintf(stderr, "Missing argument for option '%s'\n", optionName.c_str());
+ }
+ return ArgumentsAndOptions();
+ }
+ optionValue = argv[i];
+ }
+ options[optionName] = optionValue;
+ } else {
+ // argument
+ if (argumentSpecIt == mArgumentSpecs.end()) {
+ if (printErrorMessage) {
+ fprintf(stderr, "Too many arguments.\n");
+ }
+ return ArgumentsAndOptions();
+ }
+ arguments[argumentSpecIt->getName()].push_back(arg);
+ if (arguments[argumentSpecIt->getName()].size() >= argumentSpecIt->getMaxCount()) {
+ ++argumentSpecIt;
+ }
+ }
+ }
+
+ if (argumentSpecIt != mArgumentSpecs.end()) {
+ const auto &it = arguments.find(argumentSpecIt->getName());
+ const size_t minCount = argumentSpecIt->getMinCount();
+ const size_t actualcount = it == arguments.end() ? 0 : it->second.size();
+ if (minCount > actualcount) {
+ if (printErrorMessage) {
+ fprintf(stderr, "Not enough arguments. %zd argumant(s) required for <%s>\n",
+ minCount, argumentSpecIt->getName().c_str());
+ }
+ return ArgumentsAndOptions();
+ }
+ }
+ return ArgumentsAndOptions(std::move(options), std::move(arguments));
}
} // namespace dicttoolkit
diff --git a/native/dicttoolkit/src/utils/arguments_parser.h b/native/dicttoolkit/src/utils/arguments_parser.h
index 510a8722b..32bd328d4 100644
--- a/native/dicttoolkit/src/utils/arguments_parser.h
+++ b/native/dicttoolkit/src/utils/arguments_parser.h
@@ -35,29 +35,29 @@ class OptionSpec {
static OptionSpec keyValueOption(const std::string &valueName, const std::string &defaultValue,
const std::string &description) {
- return OptionSpec(true /* takeValue */, valueName, defaultValue, description);
+ return OptionSpec(true /* needsValue */, valueName, defaultValue, description);
}
static OptionSpec switchOption(const std::string &description) {
- return OptionSpec(false /* takeValue */, "" /* valueName */, "" /* defaultValue */,
+ return OptionSpec(false /* needsValue */, "" /* valueName */, "" /* defaultValue */,
description);
}
- bool takeValue() const { return mTakeValue; }
+ bool needsValue() const { return mNeedsValue; }
const std::string &getValueName() const { return mValueName; }
const std::string &getDefaultValue() const { return mDefaultValue; }
const std::string &getDescription() const { return mDescription; }
private:
- OptionSpec(const bool takeValue, const std::string &valueName, const std::string &defaultValue,
+ OptionSpec(const bool needsValue, const std::string &valueName, const std::string &defaultValue,
const std::string &description)
- : mTakeValue(takeValue), mValueName(valueName), mDefaultValue(defaultValue),
+ : mNeedsValue(needsValue), mValueName(valueName), mDefaultValue(defaultValue),
mDescription(description) {}
// Whether the option have to be used with a value or just a switch.
- // e.g. 'f' in "command -f /path/to/file" is mTakeValue == true.
- // 'f' in "command -f -t" is mTakeValue == false.
- bool mTakeValue;
+ // e.g. 'f' in "command -f /path/to/file" is mNeedsValue == true.
+ // 'f' in "command -f -t" is mNeedsValue == false.
+ bool mNeedsValue;
// Name of the value used to show usage.
std::string mValueName;
std::string mDefaultValue;
@@ -66,32 +66,32 @@ class OptionSpec {
class ArgumentSpec {
public:
- static const int UNLIMITED_COUNT;
+ static const size_t UNLIMITED_COUNT;
static ArgumentSpec singleArgument(const std::string &name, const std::string &description) {
return ArgumentSpec(name, 1 /* minCount */, 1 /* maxCount */, description);
}
- static ArgumentSpec variableLengthArguments(const std::string &name, const int minCount,
- const int maxCount, const std::string &description) {
+ static ArgumentSpec variableLengthArguments(const std::string &name, const size_t minCount,
+ const size_t maxCount, const std::string &description) {
return ArgumentSpec(name, minCount, maxCount, description);
}
const std::string &getName() const { return mName; }
- int getMinCount() const { return mMinCount; }
- int getMaxCount() const { return mMaxCount; }
+ size_t getMinCount() const { return mMinCount; }
+ size_t getMaxCount() const { return mMaxCount; }
const std::string &getDescription() const { return mDescription; }
private:
DISALLOW_DEFAULT_CONSTRUCTOR(ArgumentSpec);
- ArgumentSpec(const std::string &name, const int minCount, const int maxCount,
+ ArgumentSpec(const std::string &name, const size_t minCount, const size_t maxCount,
const std::string &description)
: mName(name), mMinCount(minCount), mMaxCount(maxCount), mDescription(description) {}
const std::string mName;
- const int mMinCount;
- const int mMaxCount;
+ const size_t mMinCount;
+ const size_t mMaxCount;
const std::string mDescription;
};
@@ -101,7 +101,8 @@ class ArgumentsParser {
const std::vector<ArgumentSpec> &&argumentSpecs)
: mOptionSpecs(std::move(optionSpecs)), mArgumentSpecs(std::move(argumentSpecs)) {}
- const ArgumentsAndOptions parseArguments(const int argc, char **argv) const;
+ const ArgumentsAndOptions parseArguments(const int argc, char **argv,
+ const bool printErrorMessage) const;
bool validateSpecs() const;
void printUsage(const std::string &commandName, const std::string &description) const;
diff --git a/native/dicttoolkit/tests/utils/arguments_parser_test.cpp b/native/dicttoolkit/tests/utils/arguments_parser_test.cpp
index e79425b87..58b499823 100644
--- a/native/dicttoolkit/tests/utils/arguments_parser_test.cpp
+++ b/native/dicttoolkit/tests/utils/arguments_parser_test.cpp
@@ -68,6 +68,80 @@ TEST(ArgumentsParserTests, TestValitadeSpecs) {
}
}
+int initArgv(char *mutableCommandLine, char **argv) {
+ bool readingSeparator = false;
+ int argc = 1;
+ argv[0] = mutableCommandLine;
+ const size_t length = strlen(mutableCommandLine);
+ for (size_t i = 0; i < length; ++i) {
+ if (mutableCommandLine[i] != ' ' && readingSeparator) {
+ readingSeparator = false;
+ argv[argc] = mutableCommandLine + i;
+ ++argc;
+ } else if (mutableCommandLine[i] == ' ' && !readingSeparator) {
+ readingSeparator = true;
+ mutableCommandLine[i] = '\0';
+ }
+ }
+ argv[argc] = nullptr;
+ return argc;
+}
+
+TEST(ArgumentsParserTests, TestParseArguments) {
+ std::unordered_map<std::string, OptionSpec> optionSpecs;
+ optionSpecs["a"] = OptionSpec::switchOption("description");
+ optionSpecs["b"] = OptionSpec::keyValueOption("valueName", "default", "description");
+ const std::vector<ArgumentSpec> argumentSpecs = {
+ ArgumentSpec::singleArgument("arg0", "description"),
+ ArgumentSpec::variableLengthArguments("arg1", 0 /* minCount */, 2 /* maxCount */,
+ "description"),
+ };
+ const ArgumentsParser parser =
+ ArgumentsParser(std::move(optionSpecs), std::move(argumentSpecs));
+
+ {
+ char kMutableCommandLine[1024] = "command arg";
+ char *argv[128] = {};
+ const int argc = initArgv(kMutableCommandLine, argv);
+ ASSERT_EQ(2, argc);
+ const ArgumentsAndOptions argumentsAndOptions = parser.parseArguments(
+ argc, argv, false /* printErrorMessages */);
+ EXPECT_FALSE(argumentsAndOptions.hasOption("a"));
+ EXPECT_EQ("default", argumentsAndOptions.getOptionValue("b"));
+ EXPECT_EQ("arg", argumentsAndOptions.getSingleArgument("arg0"));
+ EXPECT_FALSE(argumentsAndOptions.hasArgument("arg1"));
+ }
+ {
+ char kArgumentBuffer[1024] = "command -a arg arg";
+ char *argv[128] = {};
+ const int argc = initArgv(kArgumentBuffer, argv);
+ ASSERT_EQ(4, argc);
+ const ArgumentsAndOptions argumentsAndOptions = parser.parseArguments(
+ argc, argv, false /* printErrorMessages */);
+ EXPECT_TRUE(argumentsAndOptions.hasOption("a"));
+ EXPECT_EQ("default", argumentsAndOptions.getOptionValue("b"));
+ EXPECT_EQ("arg", argumentsAndOptions.getSingleArgument("arg0"));
+ EXPECT_TRUE(argumentsAndOptions.hasArgument("arg1"));
+ EXPECT_EQ(1u, argumentsAndOptions.getVariableLengthArguments("arg1").size());
+ }
+ {
+ char kArgumentBuffer[1024] = "command -b value arg arg1 arg2";
+ char *argv[128] = {};
+ const int argc = initArgv(kArgumentBuffer, argv);
+ ASSERT_EQ(6, argc);
+ const ArgumentsAndOptions argumentsAndOptions = parser.parseArguments(
+ argc, argv, false /* printErrorMessages */);
+ EXPECT_FALSE(argumentsAndOptions.hasOption("a"));
+ EXPECT_EQ("value", argumentsAndOptions.getOptionValue("b"));
+ EXPECT_EQ("arg", argumentsAndOptions.getSingleArgument("arg0"));
+ const std::vector<std::string> &arg1 =
+ argumentsAndOptions.getVariableLengthArguments("arg1");
+ EXPECT_EQ(2u, arg1.size());
+ EXPECT_EQ("arg1", arg1[0]);
+ EXPECT_EQ("arg2", arg1[1]);
+ }
+}
+
} // namespace
} // namespace dicttoolkit
} // namespace latinime