mirror of
https://github.com/Cameron-Reed1/Cpp-Argument-Parser.git
synced 2025-01-11 00:06:47 +00:00
Compare commits
3 Commits
f8f5b4eafc
...
085236fb62
Author | SHA1 | Date | |
---|---|---|---|
085236fb62 | |||
1449f7e47c | |||
ea017d1d54 |
@ -6,13 +6,15 @@ namespace Arguments
|
|||||||
{
|
{
|
||||||
|
|
||||||
enum ERROR {
|
enum ERROR {
|
||||||
NO_ERROR = 0,
|
NO_ERROR = 0,
|
||||||
ERROR_UNKNOWN_ARGUMENT,
|
|
||||||
ERROR_UNKNOWN_POSITIONAL_ARGUMENT,
|
ERROR_UNKNOWN_ARGUMENT,
|
||||||
ERROR_MISSING_VALUE,
|
ERROR_UNKNOWN_POSITIONAL_ARGUMENT,
|
||||||
ERROR_MISSING_POSITIONAL_ARGUMENT,
|
|
||||||
|
ERROR_MISSING_VALUE,
|
||||||
|
ERROR_MISSING_POSITIONAL_ARGUMENT,
|
||||||
|
|
||||||
ERROR_INVALID_INT,
|
ERROR_INVALID_INT,
|
||||||
SPECIAL_CASE_HELP,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Parser
|
class Parser
|
||||||
@ -38,8 +40,6 @@ public:
|
|||||||
Argument(const char* name);
|
Argument(const char* name);
|
||||||
Argument(char name);
|
Argument(char name);
|
||||||
|
|
||||||
Argument& description(const char* desc);
|
|
||||||
|
|
||||||
Argument& alias(const char* alias);
|
Argument& alias(const char* alias);
|
||||||
Argument& alias(char alias);
|
Argument& alias(char alias);
|
||||||
|
|
||||||
@ -56,8 +56,6 @@ protected:
|
|||||||
const char* m_Name;
|
const char* m_Name;
|
||||||
char m_ShortName;
|
char m_ShortName;
|
||||||
|
|
||||||
const char* m_Description;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<const char*> m_Aliases;
|
std::vector<const char*> m_Aliases;
|
||||||
std::vector<char> m_ShortAliases;
|
std::vector<char> m_ShortAliases;
|
||||||
@ -112,16 +110,11 @@ class PositionalArgument
|
|||||||
public:
|
public:
|
||||||
PositionalArgument(bool required);
|
PositionalArgument(bool required);
|
||||||
|
|
||||||
void description(const char* desc);
|
|
||||||
|
|
||||||
virtual ERROR parseValue(Parser& state) = 0;
|
virtual ERROR parseValue(Parser& state) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool found;
|
bool found;
|
||||||
bool required;
|
bool required;
|
||||||
|
|
||||||
private:
|
|
||||||
const char* m_Description;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
43
Makefile
43
Makefile
@ -6,8 +6,9 @@ SOURCE_DIR = Src
|
|||||||
HEADER_DIR = Inc
|
HEADER_DIR = Inc
|
||||||
BUILD_DIR = bin
|
BUILD_DIR = bin
|
||||||
|
|
||||||
HEADER_INSTALL_DIR = /usr/local/include
|
INSTALL_PREFIX ?= /usr/local
|
||||||
INSTALL_DIR = /usr/local/lib
|
HEADER_INSTALL_DIR = $(INSTALL_PREFIX)/include
|
||||||
|
INSTALL_DIR = $(INSTALL_PREFIX)/lib
|
||||||
|
|
||||||
LIB_NAME = argParser
|
LIB_NAME = argParser
|
||||||
ifeq ($(TYPE), $(SHARED_TYPE))
|
ifeq ($(TYPE), $(SHARED_TYPE))
|
||||||
@ -44,59 +45,59 @@ all: $(BUILD_DIR)/$(LIB_FILE_NAME)
|
|||||||
|
|
||||||
ifneq ($(TYPE), $(SHARED_TYPE))
|
ifneq ($(TYPE), $(SHARED_TYPE))
|
||||||
shared: clean
|
shared: clean
|
||||||
@sed -i -e "s/^TYPE = .*$$/TYPE = $(SHARED_TYPE)/" Makefile
|
@sed -i -e "s/^TYPE = .*$$/TYPE = $(SHARED_TYPE)/" Makefile
|
||||||
|
|
||||||
.PHONY: shared
|
.PHONY: shared
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(TYPE), $(STATIC_TYPE))
|
ifneq ($(TYPE), $(STATIC_TYPE))
|
||||||
static: clean
|
static: clean
|
||||||
@sed -i -e "s/^TYPE = .*$$/TYPE = $(STATIC_TYPE)/" Makefile
|
@sed -i -e "s/^TYPE = .*$$/TYPE = $(STATIC_TYPE)/" Makefile
|
||||||
|
|
||||||
.PHONY: static
|
.PHONY: static
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(BUILD_DIR)/$(LIB_FILE_NAME): $(OBJECTS)
|
$(BUILD_DIR)/$(LIB_FILE_NAME): $(OBJECTS)
|
||||||
ifeq ($(TYPE), $(SHARED_TYPE))
|
ifeq ($(TYPE), $(SHARED_TYPE))
|
||||||
$(CXX) $^ $(CXXFLAGS) -shared -o $@
|
$(CXX) $^ $(CXXFLAGS) -shared -o $@
|
||||||
else
|
else
|
||||||
$(AR) $(ARFLAGS) $@ $^
|
$(AR) $(ARFLAGS) $@ $^
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c | $(BUILD_DIR)
|
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c | $(BUILD_DIR)
|
||||||
$(CC) -c $< $(CFLAGS) -o $@
|
$(CC) -c $< $(CFLAGS) -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp | $(BUILD_DIR)
|
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp | $(BUILD_DIR)
|
||||||
$(CXX) -c $< $(CXXFLAGS) -o $@
|
$(CXX) -c $< $(CXXFLAGS) -o $@
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
test: test.cpp all | $(BUILD_DIR)
|
test: test.cpp all | $(BUILD_DIR)
|
||||||
$(CXX) $< $(CXXFLAGS) -l$(LIB_NAME) -L$(BUILD_DIR) $(TESTFLAGS) -o $(BUILD_DIR)/test
|
$(CXX) $< $(CXXFLAGS) -l$(LIB_NAME) -L$(BUILD_DIR) $(TESTFLAGS) -o $(BUILD_DIR)/test
|
||||||
-$(BUILD_DIR)/test
|
-$(BUILD_DIR)/test
|
||||||
|
|
||||||
test_installed: test.cpp | $(BUILD_DIR)
|
test_installed: test.cpp | $(BUILD_DIR)
|
||||||
$(CXX) $< $(CXXFLAGS) -l$(LIB_NAME) -o $(BUILD_DIR)/test
|
$(CXX) $< $(CXXFLAGS) -l$(LIB_NAME) -o $(BUILD_DIR)/test
|
||||||
-$(BUILD_DIR)/test
|
-$(BUILD_DIR)/test
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
cp $(BUILD_DIR)/$(LIB_FILE_NAME) $(INSTALL_DIR)
|
cp $(BUILD_DIR)/$(LIB_FILE_NAME) $(INSTALL_DIR)
|
||||||
cp $(HEADERS) $(HEADER_INSTALL_DIR)
|
cp $(HEADERS) $(HEADER_INSTALL_DIR)
|
||||||
@chmod 0755 $(INSTALL_DIR)/$(LIB_FILE_NAME)
|
@chmod 0755 $(INSTALL_DIR)/$(LIB_FILE_NAME)
|
||||||
ifeq ($(TYPE), $(SHARED_TYPE))
|
ifeq ($(TYPE), $(SHARED_TYPE))
|
||||||
@ldconfig
|
@ldconfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
$(RM) $(INSTALL_DIR)/$(LIB_FILE_NAME)
|
$(RM) $(INSTALL_DIR)/$(LIB_FILE_NAME)
|
||||||
$(RM) $(addprefix $(HEADER_INSTALL_DIR)/, $(notdir $(HEADERS)))
|
$(RM) $(addprefix $(HEADER_INSTALL_DIR)/, $(notdir $(HEADERS)))
|
||||||
ifeq ($(TYPE), $(SHARED_TYPE))
|
ifeq ($(TYPE), $(SHARED_TYPE))
|
||||||
@ldconfig
|
@ldconfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) -r $(BUILD_DIR)
|
$(RM) -r $(BUILD_DIR)
|
||||||
|
|
||||||
.PHONY: all test install uninstall clean
|
.PHONY: all test install uninstall clean
|
||||||
|
|
||||||
|
19
README.md
Normal file
19
README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# v2
|
||||||
|
|
||||||
|
I never really liked the interface of v1, so after coming back to this project, I spent some time thinking about how it could be improved,
|
||||||
|
took some inspiration from Golangs flag module, and made v2, which has a simpler, more flexible interface with better type safety
|
||||||
|
|
||||||
|
For example:
|
||||||
|
- It doesn't cast char* to uint64_t and require you to cast it back
|
||||||
|
- It doesn't require you to create a parser object, you just call parse
|
||||||
|
- You don't have to add the arguments to that parser object, it's taken care of just by calling the constructor
|
||||||
|
- You aren't required to provide descriptions for you program and every argument
|
||||||
|
|
||||||
|
That last one means that v2 will _not_ take care of --help and -h for you. If you want a help menu, you have to create it yourself.
|
||||||
|
But help menus aren't always required and when you do want one, this gives you control over what it looks like
|
||||||
|
|
||||||
|
|
||||||
|
# How do I use this
|
||||||
|
|
||||||
|
Check out [test.cpp](test.cpp). It demonstrates the full scope of this library
|
||||||
|
|
@ -51,12 +51,6 @@ Argument::Argument(char name)
|
|||||||
arguments.push_back(this);
|
arguments.push_back(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Argument& Argument::description(const char* desc)
|
|
||||||
{
|
|
||||||
m_Description = desc;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Argument& Argument::alias(const char* alias)
|
Argument& Argument::alias(const char* alias)
|
||||||
{
|
{
|
||||||
m_Aliases.push_back(alias);
|
m_Aliases.push_back(alias);
|
||||||
@ -223,7 +217,7 @@ ERROR Bool::parseValue(Parser& state)
|
|||||||
|
|
||||||
|
|
||||||
PositionalArgument::PositionalArgument(bool required)
|
PositionalArgument::PositionalArgument(bool required)
|
||||||
: found(false), required(required), m_Description(nullptr)
|
: found(false), required(required)
|
||||||
{
|
{
|
||||||
if (required) {
|
if (required) {
|
||||||
for (PositionalArgument* arg: positionalArguments) {
|
for (PositionalArgument* arg: positionalArguments) {
|
||||||
@ -237,12 +231,6 @@ PositionalArgument::PositionalArgument(bool required)
|
|||||||
positionalArguments.push_back(this);
|
positionalArguments.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PositionalArgument::description(const char* desc)
|
|
||||||
{
|
|
||||||
m_Description = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PositionalInt::PositionalInt(int64_t defaultValue, bool required)
|
PositionalInt::PositionalInt(int64_t defaultValue, bool required)
|
||||||
: PositionalArgument(required), value(defaultValue) { }
|
: PositionalArgument(required), value(defaultValue) { }
|
||||||
|
|
||||||
|
42
test.cpp
42
test.cpp
@ -5,33 +5,33 @@
|
|||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
Arguments::String first('f', "none");
|
Arguments::String first('f', "none");
|
||||||
first.description("First arg");
|
first.alias("first");
|
||||||
|
|
||||||
Arguments::Int second("second", 0);
|
Arguments::Int second("second", 0);
|
||||||
second.description("Second arg").alias('s');
|
second.alias('s');
|
||||||
|
|
||||||
Arguments::Bool third("third");
|
Arguments::Bool third("third");
|
||||||
third.description("Third arg").alias("abc").alias('t');
|
third.alias("abc").alias('t');
|
||||||
|
|
||||||
Arguments::PositionalString name("", true);
|
Arguments::PositionalString name("", true);
|
||||||
Arguments::PositionalInt age(0, false);
|
Arguments::PositionalInt age(0, false);
|
||||||
|
|
||||||
if (Arguments::parse(argc, argv) != Arguments::NO_ERROR) {
|
if (Arguments::parse(argc, argv) != Arguments::NO_ERROR) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Found:" << std::endl;
|
std::cout << "Found:" << std::endl;
|
||||||
std::cout << "\tFirst: " << first.found << std::endl;
|
std::cout << "\tFirst: " << first.found << std::endl;
|
||||||
std::cout << "\tSecond: " << second.found << std::endl;
|
std::cout << "\tSecond: " << second.found << std::endl;
|
||||||
std::cout << "\tThird: " << third.found << std::endl;
|
std::cout << "\tThird: " << third.found << std::endl;
|
||||||
std::cout << "\tName: " << name.found << std::endl;
|
std::cout << "\tName: " << name.found << std::endl;
|
||||||
std::cout << "\tAge: " << age.found << std::endl;
|
std::cout << "\tAge: " << age.found << std::endl;
|
||||||
|
|
||||||
std::cout << std::endl << "Values:" << std::endl;
|
std::cout << std::endl << "Values:" << std::endl;
|
||||||
std::cout << "\tFirst: " << first.value << std::endl;
|
std::cout << "\tFirst: " << first.value << std::endl;
|
||||||
std::cout << "\tSecond: " << second.value << std::endl;
|
std::cout << "\tSecond: " << second.value << std::endl;
|
||||||
std::cout << "\tName: " << name.value << std::endl;
|
std::cout << "\tName: " << name.value << std::endl;
|
||||||
std::cout << "\tAge: " << age.value << std::endl;
|
std::cout << "\tAge: " << age.value << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user