From: Armaan Bhojwani Date: Sat, 15 May 2021 16:21:53 +0000 (-0400) Subject: Major restructuring X-Git-Url: https://git.armaanb.net/?p=gen-shell.git;a=commitdiff_plain;h=HEAD Major restructuring Fix build system and repository layout, remove unused options, improve code style. My programming skills have improved a lot since first writing this program, and this commit fixes most of the rookie mistakes that I made. --- diff --git a/.build.yml b/.build.yml deleted file mode 100644 index fb8f236..0000000 --- a/.build.yml +++ /dev/null @@ -1,14 +0,0 @@ -image: archlinux -packages: - - readline - - cmake - - gcc -sources: - - https://git.sr.ht/~armaan/gen-shell -tasks: - - cmake: | - cd gen-shell - cmake . - make -artifacts: - - gen-shell/src/gen-shell diff --git a/.gitignore b/.gitignore index e64a8f6..33f3ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,39 +1,2 @@ -*.d -*.slo -*.lo -*.o -*.obj -*.gch -*.pch -*.so -*.dylib -*.dll -*.a -*.mod -*.smod -*.exe -*.out -*.app gen-shell -CMakeLists.txt.user -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake -_deps -CPackConfig.cmake -CPackSourceConfig.cmake -commit.h -commit.h.in -*-prefix/ -*~ -.fuse_hidden* -.directory -.Trash-* -.nfs* -cmake.h +*.o diff --git a/.gitmodules b/.gitmodules index e895022..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "Sarge"] - path = Sarge - url = https://github.com/MayaPosch/Sarge diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 31151de..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -cmake_minimum_required (VERSION 2.8) -set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") -set (HAVE_CMAKE true) - -project (gen-shell) -include (CXXSniffer) - -include (CheckFunctionExists) -include (CheckStructHasMember) -include (CheckCXXCompilerFlag) - -# include the readline library finder module -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") - -# find readline -message ("-- Looking for GNU Readline") -find_package (Readline REQUIRED) -if (READLINE_FOUND) - set (HAVE_READLINE true) - set (GEN-SHELL_INCLUDE_DIRS ${GEN-SHELL_INCLUDE_DIRS} ${READLINE_INCLUDE_DIR}) - set (GEN-SHELL_LIBRARIES ${GEN-SHELL_LIBRARIES} ${READLINE_LIBRARIES}) -endif (READLINE_FOUND) - -message ("-- Configuring cmake.h") -configure_file ( - ${CMAKE_SOURCE_DIR}/cmake.h.in - ${CMAKE_SOURCE_DIR}/cmake.h) - -add_subdirectory (src) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..26bddec --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +all: + ${CC} -o gen-shell src/*.cpp ${CFLAGS} -lstdc++ -lreadline ${LDFLAGS} + +install: all + cp gen-shell /usr/local/bin/gen-shell + +uninstall: + rm /usr/local/bin/gen-shell + +.PHONY: all diff --git a/README.md b/README.md index 516bbcb..5b0e835 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,18 @@ # gen-shell -[![builds.sr.ht status](https://builds.sr.ht/~armaan/gen-shell/commits/.build.yml.svg)](https://builds.sr.ht/~armaan/gen-shell/commits/.build.yml?) - -A simple way to turn any command into a shell with arrow key/history support (if compiled with libreadline). Forked from [taskshell](https://github.com/GothenburgBitFactory/taskshell). +A simple way to turn any command into a REPL with arrow key/history support. ## Usage See `gen-shell --help` ## Installation -### From a binary -Binaries can be downloaded from [here](https://builds.sr.ht/~armaan/gen-shell/commits/.build.yml). NB: these binaries are compiled against libreadline version 8 - -### From source Dependencies: - - cmake (2.8 or higher) - - make - - g++ (sometimes packaged as gcc-c++ or gcc-g++) - - libreadline development files (7 or 8 is fine, 5 is untested) (optional, but highly recommended) + - POSIX make + - a c++ compiler and standard library + - libreadline development files (7 or 8 is fine, 5 is untested) ```bash -git clone https://git.sr.ht/~armaan/gen-shell -cd gen-shell -cmake . -sudo make install +make +make install ``` ## License Following suit from taskshell, gen-shell is MIT licensed by Armaan Bhojwani, 2021. Gen-shell is forked from taskshell, which was developed by [these people](https://github.com/GothenburgBitFactory/taskshell/blob/master/AUTHORS). diff --git a/Sarge b/Sarge deleted file mode 160000 index 5c0b2a7..0000000 --- a/Sarge +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5c0b2a714aca97de16bb0a1b2f723681f69f3307 diff --git a/branding/logo.png b/branding/logo.png deleted file mode 100644 index 4824efd..0000000 Binary files a/branding/logo.png and /dev/null differ diff --git a/branding/logo.xcf b/branding/logo.xcf deleted file mode 100644 index 106ebf7..0000000 Binary files a/branding/logo.xcf and /dev/null differ diff --git a/cmake.h.in b/cmake.h.in deleted file mode 100644 index e905598..0000000 --- a/cmake.h.in +++ /dev/null @@ -1,60 +0,0 @@ -/* cmake.h.in. Creates cmake.h during a cmake run */ - -/* Product identification */ -#define PRODUCT_TASKSH 1 - -/* Package information */ -#define PACKAGE "${PACKAGE}" -#define VERSION "${VERSION}" -#define PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" -#define PACKAGE_NAME "${PACKAGE_NAME}" -#define PACKAGE_TARNAME "${PACKAGE_TARNAME}" -#define PACKAGE_VERSION "${PACKAGE_VERSION}" -#define PACKAGE_STRING "${PACKAGE_STRING}" - -#define CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" - -/* Localization */ -#define PACKAGE_LANGUAGE ${PACKAGE_LANGUAGE} -#define LANGUAGE_ENG_USA ${LANGUAGE_ENG_USA} - -/* git information */ -#cmakedefine HAVE_COMMIT - -/* cmake information */ -#cmakedefine HAVE_CMAKE -#define CMAKE_VERSION "${CMAKE_VERSION}" - -/* Compiling platform */ -#cmakedefine LINUX -#cmakedefine DARWIN -#cmakedefine CYGWIN -#cmakedefine FREEBSD -#cmakedefine OPENBSD -#cmakedefine NETBSD -#cmakedefine HAIKU -#cmakedefine SOLARIS -#cmakedefine KFREEBSD -#cmakedefine GNUHURD -#cmakedefine UNKNOWN - -/* Found the Readline library */ -#cmakedefine HAVE_READLINE - -/* Found the pthread library */ -#cmakedefine HAVE_LIBPTHREAD - -/* Found wordexp.h */ -#cmakedefine HAVE_WORDEXP - -/* Found tm.tm_gmtoff struct member */ -#cmakedefine HAVE_TM_GMTOFF - -/* Found st.st_birthtime struct member */ -#cmakedefine HAVE_ST_BIRTHTIME - -/* Functions */ -#cmakedefine HAVE_GET_CURRENT_DIR_NAME -#cmakedefine HAVE_TIMEGM -#cmakedefine HAVE_UUID_UNPARSE_LOWER - diff --git a/cmake/CXXSniffer.cmake b/cmake/CXXSniffer.cmake deleted file mode 100644 index cf6482a..0000000 --- a/cmake/CXXSniffer.cmake +++ /dev/null @@ -1,51 +0,0 @@ -message ("-- Configuring C++11") -message ("-- System: ${CMAKE_SYSTEM_NAME}") - -include (CheckCXXCompilerFlag) - -# NOTE: Phase out -std=gnu++0x and --std=c++0x as soon as realistically possible. -CHECK_CXX_COMPILER_FLAG("-std=c++11" _HAS_CXX11) -CHECK_CXX_COMPILER_FLAG("-std=c++0x" _HAS_CXX0X) -CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" _HAS_GNU0X) - -if (_HAS_CXX11) - set (_CXX11_FLAGS "-std=c++11") -elseif (_HAS_CXX0X) - message (WARNING "Enabling -std=c++0x draft compile flag. Your compiler does not support the standard '-std=c++11' option. Consider upgrading.") - set (_CXX11_FLAGS "-std=c++0x") -elseif (_HAS_GNU0X) - message (WARNING "Enabling -std=gnu++0x draft compile flag. Your compiler does not support the standard '-std=c++11' option. Consider upgrading.") - set (_CXX11_FLAGS "-std=gnu++0x") -else (_HAS_CXX11) - message (FATAL_ERROR "C++11 support missing. Try upgrading your C++ compiler.") -endif (_HAS_CXX11) - -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set (LINUX true) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set (DARWIN true) - set (_CXX11_FLAGS "${_CXX11_FLAGS} -stdlib=libc++") -elseif (${CMAKE_SYSTEM_NAME} MATCHES "kFreeBSD") - set (KFREEBSD true) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") - set (FREEBSD true) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") - set (OPENBSD true) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") - set (NETBSD true) -elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") - set (SOLARIS true) -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "GNU") - set (GNUHURD true) -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN") - set (CYGWIN true) - # NOTE: Not setting -std=gnu++0x leads to compile errors even with - # GCC 4.8.3, and debugging those leads to insanity. Adding this - # workaround instead of fixing Cygwin. - set (_CXX11_FLAGS "-std=gnu++0x") -else (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set (UNKNOWN true) -endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - -set (CMAKE_CXX_FLAGS "${_CXX11_FLAGS} ${CMAKE_CXX_FLAGS}") -set (CMAKE_CXX_FLAGS "-Wall -Wextra -Wsign-compare -Wreturn-type ${CMAKE_CXX_FLAGS}") diff --git a/cmake/Modules/FindReadline.cmake b/cmake/Modules/FindReadline.cmake deleted file mode 100644 index 8fdaec1..0000000 --- a/cmake/Modules/FindReadline.cmake +++ /dev/null @@ -1,81 +0,0 @@ -# - Find the readline library -# This module defines -# READLINE_INCLUDE_DIR, path to readline/readline.h, etc. -# READLINE_LIBRARIES, the libraries required to use READLINE. -# READLINE_FOUND, If false, do not try to use READLINE. -# also defined, but not for general use are -# READLINE_readline_LIBRARY, where to find the READLINE library. -# READLINE_ncurses_LIBRARY, where to find the ncurses library [might not be defined] - -# Apple readline does not support readline hooks -# So we look for another one by default -IF (APPLE OR FREEBSD) - FIND_PATH (READLINE_INCLUDE_DIR NAMES readline/readline.h PATHS - /usr/include/ - /sw/include - /opt/local/include - /opt/include - /usr/local/include - NO_DEFAULT_PATH - ) -ENDIF (APPLE OR FREEBSD) -FIND_PATH (READLINE_INCLUDE_DIR NAMES readline/readline.h) - - -# Apple readline does not support readline hooks -# So we look for another one by default -IF (APPLE OR FREEBSD) - FIND_LIBRARY (READLINE_readline_LIBRARY NAMES readline PATHS - /usr/lib - /sw/lib - /opt/local/lib - /opt/lib - /usr/local/lib - NO_DEFAULT_PATH - ) -ENDIF (APPLE OR FREEBSD) -FIND_LIBRARY (READLINE_readline_LIBRARY NAMES readline) - -# Sometimes readline really needs ncurses -IF (APPLE OR FREEBSD) - FIND_LIBRARY (READLINE_ncurses_LIBRARY NAMES ncurses PATHS - /usr/lib - /sw/lib - /opt/local/lib - /opt/lib - /usr/local/lib - /usr/lib - NO_DEFAULT_PATH - ) -ENDIF (APPLE OR FREEBSD) -FIND_LIBRARY (READLINE_ncurses_LIBRARY NAMES ncurses) - -MARK_AS_ADVANCED ( - READLINE_INCLUDE_DIR - READLINE_readline_LIBRARY - READLINE_ncurses_LIBRARY - ) - -SET (READLINE_FOUND "NO" ) -IF (READLINE_INCLUDE_DIR) - IF (READLINE_readline_LIBRARY) - SET (READLINE_FOUND "YES" ) - SET (READLINE_LIBRARIES - ${READLINE_readline_LIBRARY} - ) - - # some readline libraries depend on ncurses - IF (READLINE_ncurses_LIBRARY) - SET (READLINE_LIBRARIES ${READLINE_LIBRARIES} ${READLINE_ncurses_LIBRARY}) - ENDIF (READLINE_ncurses_LIBRARY) - - ENDIF (READLINE_readline_LIBRARY) -ENDIF (READLINE_INCLUDE_DIR) - -IF (READLINE_FOUND) - MESSAGE (STATUS "Found readline library") -ELSE (READLINE_FOUND) - IF (READLINE_FIND_REQUIRED) - MESSAGE (FATAL_ERROR "Could not find readline -- please give some paths to CMake") - ENDIF (READLINE_FIND_REQUIRED) -ENDIF (READLINE_FOUND) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index ecd29b1..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required (VERSION 2.8) -include_directories (${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src - ${GEN-SHELL_INCLUDE_DIRS}) - -set (gen-shell_SRCS ../Sarge/src/sarge.cpp) - -add_library (gen-shell STATIC ${gen-shell_SRCS}) - -add_executable (gen-shell_executable main.cpp) - -target_link_libraries (gen-shell_executable gen-shell ${GEN-SHELL_LIBRARIES}) - -set_property (TARGET gen-shell_executable PROPERTY OUTPUT_NAME "gen-shell") - -install (TARGETS gen-shell_executable DESTINATION /usr/bin/) diff --git a/src/main.cpp b/src/main.cpp index 516f223..ae69ebb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,74 +1,59 @@ -// gen-shell - the generic shell +// gen-shell - the generic REPL // Copyright (c) 2021, Armaan Bhojwani -#include #include -#include <../Sarge/src/sarge.h> +#include "sarge.h" + #include #include -#ifdef HAVE_READLINE #include #include -#endif //////////////////////////////////////////////////////////////////////////////// using namespace std; -const std::string getResponse(const std::string & prompt) { +const std::string +getResponse(const std::string & prompt) { std::string response { "" }; // Display prompt, get input -#ifdef HAVE_READLINE char * line_read = readline(prompt.c_str()); if (!line_read) { std::cout << "\n"; response = ""; } else { - // Save history - if ( * line_read) + if (*line_read) { add_history(line_read); + } response = std::string(line_read); free(line_read); } -#else - std::cout << prompt; - std::getline(std::cin, response); - if (std::cin.eof() == 1) { - std::cout << "\n"; - response = ""; - } -#endif return response; } //////////////////////////////////////////////////////////////////////////////// -int main(int argc, char** argv) +int +main(int argc, char** argv) { - // Command line arguments Sarge sarge; - sarge.setArgument("a", "after", - "Command to execute before leaving the shell", true); - sarge.setArgument("b", "before", - "Command to execute before entering the shell", true); - sarge.setArgument("c", "command", "Command to convert to shell", true); - sarge.setArgument("h", "help", "Get help.", false); + sarge.setArgument("c", "command", "Command to convert to REPL", true); + sarge.setArgument("h", "help", "Show this message.", false); sarge.setArgument("p", "prompt", "Define a custom prompt", true); - sarge.setArgument("", "no-space", - "Dont automatically add spaces after custom prompt and command", true); - sarge.setDescription("Make a shell from any executable"); + sarge.setArgument("q", "quotes", "Treat whole input as argv[1]", false); + sarge.setDescription("Make a REPL from any executable"); sarge.setUsage("gen-shell "); if (!sarge.parseArguments(argc, argv)) { - std::cerr << "Couldn't parse arguments..." << std::endl; + std::cerr << "Could not parse command line arguments" << std::endl; return 1; } @@ -77,47 +62,29 @@ int main(int argc, char** argv) return 0; } - bool space = true; - if (sarge.exists("no-space")) { - space = false; - } - - // Define input command string arg_cmd; sarge.getFlag("command", arg_cmd); - if ( space ) - arg_cmd += " "; - // Define prompt string prompt = ""; sarge.getFlag("prompt", prompt); - if ( prompt == "" ) - { + if (prompt == "") { prompt = "% "; - } else if ( space ) { - prompt += " "; } - // Execute before-command - string before_command; - sarge.getFlag("before", before_command); - system (before_command.c_str ()); - - // Execute after-command - string after_command; - sarge.getFlag("after", after_command); - // Do the stuffs! while (true) { auto command = getResponse(prompt); - if (command == "" || command == "exit" || command == "quit" ) - { - system (after_command.c_str ()); + if (command == "" || command == "exit" || command == "quit" ) { return 0; } else { - string whole_command = arg_cmd + command; - system (whole_command.c_str ()); + string whole_command = arg_cmd + " "; + if (sarge.exists("quotes")) { + whole_command = whole_command + "\"" + command + "\""; + } else { + whole_command += command; + } + system(whole_command.c_str()); } } } diff --git a/src/sarge.cpp b/src/sarge.cpp new file mode 100644 index 0000000..eb7d14f --- /dev/null +++ b/src/sarge.cpp @@ -0,0 +1,201 @@ +/* + sarge.cpp - Implementation file for the Sarge command line argument parser project. + + Revision 0 + + Features: + - + + Notes: + - + + 2019/03/16, Maya Posch + +*/ + + +#include "sarge.h" + +#include + + +// --- SET ARGUMENT --- +void Sarge::setArgument(std::string arg_short, std::string arg_long, std::string desc, bool hasVal) { + std::unique_ptr arg(new Argument); + arg->arg_short = arg_short; + arg->arg_long = arg_long; + arg->description = desc; + arg->hasValue = hasVal; + args.push_back(std::move(arg)); + + // Set up links. + if (!arg_short.empty()) { + argNames.insert(std::pair(arg_short, args.back().get())); + } + + if (!arg_long.empty()) { + argNames.insert(std::pair(arg_long, args.back().get())); + } +} + + +// --- SET ARGUMENTS --- +void Sarge::setArguments(std::vector args) { + for (Argument a : args) { + setArgument(a.arg_short, a.arg_long, a.description, a.hasValue); + } +} + + +// --- PARSE ARGUMENTS --- +bool Sarge::parseArguments(int argc, char** argv) { + // The first argument is the name of the executable. After it we loop through the remaining + // arguments, linking flags and values. + execName = std::string(argv[0]); + bool expectValue = false; + std::map::const_iterator flag_it; + for (int i = 1; i < argc; ++i) { + // Each flag will start with a '-' character. Multiple flags can be joined together in the + // same string if they're the short form flag type (one character per flag). + std::string entry(argv[i]); + + if (expectValue) { + // Copy value. + flag_it->second->value = entry; + expectValue = false; + } + else if (entry.compare(0, 1, "-") == 0) { + if (textArguments.size() > 0) { + std::cerr << "Flags not allowed after text arguments." << std::endl; + } + + // Parse flag. + // First check for the long form. + if (entry.compare(0, 2, "--") == 0) { + // Long form of flag. + entry.erase(0, 2); // Erase the double dash since we no longer need it. + + flag_it = argNames.find(entry); + if (flag_it == argNames.end()) { + // Flag wasn't found. Abort. + std::cerr << "Long flag " << entry << " wasn't found." << std::endl; + return false; + } + + // Mark as found. + flag_it->second->parsed = true; + ++flagCounter; + + if (flag_it->second->hasValue) { + expectValue = true; // Next argument has to be a value string. + } + } + else { + // Parse short form flag. Parse all of them sequentially. Only the last one + // is allowed to have an additional value following it. + entry.erase(0, 1); // Erase the dash. + for (int i = 0; i < entry.length(); ++i) { + std::string k(&(entry[i]), 1); + flag_it = argNames.find(k); + if (flag_it == argNames.end()) { + // Flag wasn't found. Abort. + std::cerr << "Short flag " << k << " wasn't found." << std::endl; + return false; + } + + // Mark as found. + flag_it->second->parsed = true; + ++flagCounter; + + if (flag_it->second->hasValue) { + if (i != (entry.length() - 1)) { + // Flag isn't at end, thus cannot have value. + std::cerr << "Flag " << k << " needs to be followed by a value string." + << std::endl; + return false; + } else { + expectValue = true; // Next argument has to be a value string. + } + } + } + } + } + else { + // Add to text argument vector. + textArguments.push_back(entry); + } + } + + parsed = true; + + return true; +} + + +// --- GET FLAG --- +// Returns whether the flag was found, along with the value if relevant. +bool Sarge::getFlag(std::string arg_flag, std::string &arg_value) { + if (!parsed) { return false; } + + std::map::const_iterator it = argNames.find(arg_flag); + if (it == argNames.end()) { return false; } + if (!it->second->parsed) { return false; } + + if (it->second->hasValue) { arg_value = it->second->value; } + + return true; +} + + +// --- EXISTS --- +// Returns whether the flag was found. +bool Sarge::exists(std::string arg_flag) { + if (!parsed) { return false; } + + std::map::const_iterator it = argNames.find(arg_flag); + if (it == argNames.end()) { return false; } + if (!it->second->parsed) { return false; } + + return true; +} + + +// --- GET TEXT ARGUMENT --- +// Updates the value parameter with the text argument (unbound value) if found. +// Index starts at 0. +// Returns true if found, else false. +bool Sarge::getTextArgument(uint32_t index, std::string &value) { + if (index < textArguments.size()) { value = textArguments.at(index); return true; } + + return false; +} + + +// --- PRINT HELP --- +// Prints out the application description, usage and available options. +void Sarge::printHelp() { + std::cout << std::endl << description << std::endl; + std::cout << std::endl << "Usage:" << std::endl; + std::cout << "\t" << usage << std::endl; + std::cout << std::endl; + std::cout << "Options: " << std::endl; + + // Determine whitespace needed between arg_long and description. + int count = 1; + std::vector >::const_iterator it; + for (it = args.cbegin(); it != args.cend(); ++it) { + if ((*it)->arg_long.size() > count) { + count = (*it)->arg_long.size(); + } + } + + count += 3; // Number of actual spaces between the longest arg_long and description. + + // Print out the options. + for (it = args.cbegin(); it != args.cend(); ++it) { + std::cout << ((*it)->arg_short.empty() ? " " : "-" + (*it)->arg_short + ", ") + << "--" << (*it)->arg_long; + std::cout << std::string(count - (*it)->arg_long.size(), ' ') << (*it)->description + << std::endl; + } +} diff --git a/src/sarge.h b/src/sarge.h new file mode 100644 index 0000000..ab24c72 --- /dev/null +++ b/src/sarge.h @@ -0,0 +1,54 @@ +/* + sarge.h - Header file for the Sarge command line argument parser project. + + Revision 0 + + Notes: + - + + 2019/03/16, Maya Posch + +*/ + + +#include +#include +#include +#include + + +struct Argument { + Argument() : hasValue(false), parsed(false) { /* */ } + std::string arg_short; + std::string arg_long; + std::string description; + bool hasValue; + std::string value; + bool parsed; +}; + + + +class Sarge { + std::vector > args; + std::map argNames; + bool parsed = false; + int flagCounter = 0; + std::string execName; + std::string description; + std::string usage; + std::vector textArguments; + +public: + void setArgument(std::string arg_short, std::string arg_long, std::string desc, bool hasVal); + void setArguments(std::vector args); + void setDescription(std::string desc) { this->description = desc; } + void setUsage(std::string use) { this->usage = use; } + bool parseArguments(int argc, char** argv); + bool getFlag(std::string arg_flag, std::string &arg_value); + bool exists(std::string arg_flag); + bool getTextArgument(uint32_t index, std::string &value); + void printHelp(); + int flagCount() { return flagCounter; } + std::string executableName() { return execName; } +};