From f6c3135c2724be355f29eb60e45a6804d769ea3a Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Sat, 16 Apr 2016 19:21:39 +0200 Subject: [PATCH] Options handling rewritten with usage of popt.h. fixed #1 with stringtoargcargv.cpp. The command arguments are now passed as struct mshconsole::Params. Readme updated in oreder to mention stringtoargcargv.cpp. --- README.md | 9 +- msh-console-library/CMakeLists.txt | 2 +- msh-console-library/command.cpp | 172 +++++++------------- msh-console-library/command.h | 87 +++++----- msh-console-library/commandexecutor.h | 7 +- msh-console-library/commands.cpp | 6 +- msh-console-library/data.cpp | 56 ++++--- msh-console-library/datas.cpp | 19 +++ msh-console-library/option.cpp | 17 -- msh-console-library/option.h | 20 --- msh-console-library/shell.cpp | 48 ++---- msh-console-library/shell.h | 17 +- msh-console-library/stringtoargcargv.cpp | 192 +++++++++++++++++++++++ msh-console-library/stringtoargcargv.h | 45 ++++++ 14 files changed, 425 insertions(+), 272 deletions(-) create mode 100644 msh-console-library/datas.cpp delete mode 100644 msh-console-library/option.cpp delete mode 100644 msh-console-library/option.h create mode 100644 msh-console-library/stringtoargcargv.cpp create mode 100644 msh-console-library/stringtoargcargv.h diff --git a/README.md b/README.md index 341540d..b87655a 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,6 @@ Library that provides a bash-like interface for CLI C++ programs ### Credits Code based on "Write a Shell in C" - by Stephen Brennan (http://brennan.io/2015/01/16/write-a-shell-in-c/) The code has been slightly modified. +The code contains stringtoargcargv.cpp, a set of functions written by Bernhard Eder (http://web.archive.org/web/20121030075237/http://bbgen.net/blog/2011/06/string-to-argc-argv) for parsing a string into argc and argv. ### The library -The library can be compiled as shared library with the CMakeLists.txt file already in msh-console-library/, or it can be compiled with these commands: - -``` -cd msh-console-library -g++ -Wall -fPIC -std=c++11 -c command.cpp commands.cpp shell.cpp commandexecutor.cpp -g++ -shared -Wl,-soname,libmshconsole.so.1.0.0 -o libmshconsole.so.1.0.0 commandexecutor.o command.o commands.o shell.o -``` +The library can be compiled as shared library with the CMakeLists.txt file already in msh-console-library/. diff --git a/msh-console-library/CMakeLists.txt b/msh-console-library/CMakeLists.txt index 3ded61d..483d9aa 100644 --- a/msh-console-library/CMakeLists.txt +++ b/msh-console-library/CMakeLists.txt @@ -4,7 +4,7 @@ project(msh-console-library) cmake_minimum_required(VERSION 2.8) -SET(CMAKE_CXX_FLAGS "-std=c++11") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lpopt") FILE(GLOB sources *.cpp) FILE(GLOB headers *.h) diff --git a/msh-console-library/command.cpp b/msh-console-library/command.cpp index 46348ff..8263af5 100644 --- a/msh-console-library/command.cpp +++ b/msh-console-library/command.cpp @@ -1,137 +1,77 @@ #include "shell.h" namespace mshconsole { - Command::Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector argv)) : - name(n), funcCommand(funcptr){ + Command::Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector argv)) : + name(n), funcCommand(funcptr), optionNum(0){ checkObj(); } - void Command::addOption(Option *a){ - if(a->getOptionName().length()==1){ - shortOpts.push_back(a); - } - else longOpts.push_back(a); + void Command::addOption(const poptOption& a){ + if(a.arg!=NULL&&a.arg!=nullptr&&a.arg!=0) throw InvalidOptionException{}; + for(int i=0; i* args, CommandExecutor* c){ - if(args==nullptr) return -1; + int Command::execute(const struct Params& p, CommandExecutor* c){ + if(p.argc<=0) return -1; - //filling longData - Datas longData; - for(size_t i=0; id); + datas.push_back(tmp); } - //filling string for getopt and shortData - string getoptarg; - Datas shortData; - for(size_t i=0; igetOptionName()[0]); - } - getoptarg+=" -:"; - - //creating argv as char** for getopt compatibility - vector argv(args->size()); - size_t i; - for (i = 0; i < args->size(); ++i) - { - argv[i] = const_cast(&(args->operator[](i)[0])); - } - int argc=i; - - //TODO: quotes for long options - try{ - int c; - opterr=0; - optind=1; - while ((c = getopt (argc, argv.data(), getoptarg.c_str())) != -1){ - if((c>='a'&&c<='z')||(c>='A'&&c>='Z')){ - for(size_t i=0; igetOptionName()[0]){ - shortData[i]->set(true); - break; - } - } - } - else if(c=='-'){ - string l(optarg); - bool getout = false; - try{ - for(size_t i=0; igetOptionName()+"=")==0){ - if(!(longOpts[i]->hasFlag(Option::STRING))){ - throw NotRightArgException(); - } - longData[i]->set(l.substr(longOpts[i]->getOptionName().size()+1,l.size())); - getout = true; - break; - } - if(l==longOpts[i]->getOptionName()){ - longData[i]->set(true); - getout=true; - break; - } - } - } - catch(Data::MultipleDefinitionException){ - getout=false; - } - if(!getout) throw OptionNotParsedCorrectlyException(static_cast("--") + optarg); - } - else if(c=='?'){ - if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, "Unknown option character `\\x%x'.\n",optopt); - return -1; - } - else //abort(); - break; - } - - //demo of all options for debug (code to check) - /* - for(size_t i=0; igetOptionName() << ": "; - LongData* now = data[i]; - if(now->getState()==LongData::States::STRING) cout << now->getLongData(); - else cout << now->getBoolState(); - cout << "\n"; - } - for(size_t i=0; i(p.argv), opts.data(), 0); + poptSetOtherOptionHelp(pc, "[ARG...]"); + if (p.argc < 2 && opts.size()==0) { + poptPrintUsage(pc, stderr, 0); + return 1; } - //making one big Data vector - shortOpts.insert( - shortOpts.end(), - std::make_move_iterator(longOpts.begin()), - std::make_move_iterator(longOpts.end()) - ); + // process options and handle each val returned + int val; + while ((val = poptGetNextOpt(pc)) >= 0); - //deleting options and command name from argv - argv.erase(argv.begin()); //argv[0] = command name - for(int i=0; i nonOptionArgs; + while (poptPeekArg(pc) != NULL) + nonOptionArgs.push_back(const_cast(poptGetArg(pc))); + + return (*funcCommand)(c,datas,nonOptionArgs); } - string Command::getName(){ + const string& Command::getName(){ return this->name; } @@ -146,5 +86,5 @@ namespace mshconsole { } } } - const string Command::Data::EMPTY(""); + const struct poptOption Command::POPT_TERMINATOR = {NULL,'\0',POPT_ARG_NONE,NULL,-1,NULL,NULL}; } diff --git a/msh-console-library/command.h b/msh-console-library/command.h index 003b5c7..7d168a2 100644 --- a/msh-console-library/command.h +++ b/msh-console-library/command.h @@ -1,9 +1,12 @@ #ifndef COMMAND_H #define COMMAND_H +#pragma once #include #include -//#include "shell.h" -#include "option.h" +#include +extern "C"{ + #include +} #include "commandexecutor.h" using std::string; @@ -12,71 +15,67 @@ using std::vector; namespace mshconsole{ class Command { - class OptionNotParsedCorrectlyException { - string optarg; - public: - OptionNotParsedCorrectlyException(const string& s) : optarg(s) {} - string getOptarg(){ - return optarg; - } - }; - - class CommandNameNotValidException {}; - class NotRightArgException {}; const string name; void checkObj(); - vector longOpts; - vector shortOpts; + vector opts; + static const struct poptOption POPT_TERMINATOR; + size_t optionNum; public: class Data{ public: - enum States{ - STRING=4, - TRUE=2, - FALSE=1 + union Arg{ + int i; + char* s; + long l; + float f; + double d; + }; + enum Types{ + STRING, + INT, + LONG, + FLOAT, + DOUBLE }; - class MultipleDefinitionException{}; private: - string sData; - const Option* of; - enum States state; - static const string EMPTY; - bool isSDataValorized; - Data(const Option* o) : sData(), state(Data::FALSE), isSDataValorized(false), of(o) {} + union Arg d; + poptOption* of; + Data(poptOption* o) : of(o), d() {} + friend class mshconsole::Command; public: - void set(bool b); - void set(const string& s); - enum States getState() const; - const string& getData() const; - bool getBoolState() const; - friend class Command; - friend class Datas; + const union Arg& getArg() const; + enum Types getType() const; + int getInt() const; + char* getString() const; + long getLong() const; + float getFloat() const; + double getDouble() const; }; class Datas : public vector{ public: Data* getOptData(const string& optionName) const; + Data* getOptData(char opt) const; + Data* operator[](const string& opt) const; }; - Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector argv)); + class DuplicatedOptionException{}; + class CommandNameNotValidException{}; + class InvalidOptionException{}; + + Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector argv)); Command(const Command&); ~Command(); - string getName(); - int execute(const vector*, CommandExecutor*); - void addOption(Option* a); + const string& getName(); + int execute(const struct Params&, CommandExecutor*); + void addOption(const poptOption& option); private: - int (*funcCommand)(CommandExecutor* whoExecuted,const Datas& data, const vector argv); + int (*funcCommand)(CommandExecutor* whoExecuted,const Datas& data, const vector argv); }; - - - - } - - #endif // COMMAND_H diff --git a/msh-console-library/commandexecutor.h b/msh-console-library/commandexecutor.h index 58d2a40..7c335a2 100644 --- a/msh-console-library/commandexecutor.h +++ b/msh-console-library/commandexecutor.h @@ -1,5 +1,6 @@ #ifndef COMMANDEXECUTOR_H #define COMMANDEXECUTOR_H +#pragma once #include #include @@ -16,12 +17,16 @@ namespace mshconsole{ ExitException(int c=0) : code(c){} }; public: - virtual int executeCmd(std::vector* args) = 0; + virtual int executeCmd(const struct Params& args) = 0; virtual int executeCmd(const std::string& args) = 0; virtual size_t howManyCmds() const = 0; void exit(int code=0); CommandExecutor(); }; + struct Params{ + int argc; + char** argv; + }; } #endif // COMMANDEXECUTOR_H diff --git a/msh-console-library/commands.cpp b/msh-console-library/commands.cpp index 84501b7..6e6068c 100644 --- a/msh-console-library/commands.cpp +++ b/msh-console-library/commands.cpp @@ -14,10 +14,10 @@ namespace mshconsole { return commands.size(); } - int Shell::Commands::launch(const vector* args, bool launchThread){ + int Shell::Commands::launch(const struct Params& p, bool launchThread){ for(unsigned int i=0; i<(launchThread ? threadCommands.size() : commands.size()); i++){ - if((launchThread ? threadCommands[i]->getName() : commands[i]->getName())==args->operator [](0)){ - return (launchThread ? threadCommands[i]->execute(args, parent) : commands[i]->execute(args, parent)); + if((launchThread ? threadCommands[i]->getName() : commands[i]->getName())==p.argv[0]){ + return (launchThread ? threadCommands[i]->execute(p, parent) : commands[i]->execute(p, parent)); } } throw CommandNotFoundException(); diff --git a/msh-console-library/data.cpp b/msh-console-library/data.cpp index 3fdf9c8..c830664 100644 --- a/msh-console-library/data.cpp +++ b/msh-console-library/data.cpp @@ -1,30 +1,40 @@ #include "command.h" namespace mshconsole{ - void Command::Data::set(bool b){ - if(isSDataValorized) throw MultipleDefinitionException(); - b ? state=Data::TRUE : state=Data::FALSE; - isSDataValorized=true; + inline const union Command::Data::Arg& Command::Data::getArg() const{ + return d; } - void Command::Data::set(const string& s){ - if(isSDataValorized) throw MultipleDefinitionException(); - state=Data::STRING; - sData=s; - isSDataValorized=true; - } - enum Command::Data::States Command::Data::getState() const{ - return state; - } - const string& Command::Data::getData() const{ - if(state!=Data::STRING) return EMPTY; - else return sData; - } - bool Command::Data::getBoolState() const{ - return state!=Data::FALSE; - } - Command::Data* Command::Datas::getOptData(const string& opt) const{ - for(size_t i=0; iof->getOptionName()==opt) return operator[](i); + enum Command::Data::Types Command::Data::getType() const{ + if(of->argInfo & POPT_ARG_INT || of->argInfo & POPT_ARG_VAL || of->argInfo == POPT_ARG_NONE){ + return INT; } + else if(of->argInfo & POPT_ARG_STRING){ + return STRING; + } + else if(of->argInfo & POPT_ARG_LONG){ + return LONG; + } + else if(of->argInfo & POPT_ARG_FLOAT){ + return FLOAT; + } + else if(of->argInfo & POPT_ARG_DOUBLE){ + return DOUBLE; + } + //else return NULL; + } + int Command::Data::getInt() const{ + return d.i; + } + char* Command::Data::getString() const{ + return d.i ? d.s : const_cast(""); + } + long Command::Data::getLong() const{ + return d.l; + } + float Command::Data::getFloat() const{ + return d.f; + } + double Command::Data::getDouble() const{ + return d.d; } } diff --git a/msh-console-library/datas.cpp b/msh-console-library/datas.cpp new file mode 100644 index 0000000..62601a4 --- /dev/null +++ b/msh-console-library/datas.cpp @@ -0,0 +1,19 @@ +#include "command.h" + +namespace mshconsole { + Command::Data* Command::Datas::getOptData(const string& opt) const{ + for(size_t i=0; isize(); i++){ + if(opt == this->at(i)->of->longName) return this->at(i); + } + } + Command::Data* Command::Datas::getOptData(char opt) const{ + for(size_t i=0; isize(); i++){ + if(opt == this->at(i)->of->shortName) return this->at(i); + } + } + Command::Data* Command::Datas::operator [](const string& opt) const{ + if(opt.length()>2) return getOptData(opt); + if(opt.length()==1) return getOptData(opt[0]); + else return nullptr; + } +} diff --git a/msh-console-library/option.cpp b/msh-console-library/option.cpp deleted file mode 100644 index 36a565e..0000000 --- a/msh-console-library/option.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "option.h" - -namespace mshconsole{ - Option::Option(const string &s, States b): optionName(s), want(b){ - if(optionName.length()<1){ - throw OptionNameEmptyException{}; - } - } - - const string& Option::getOptionName() const{ - return optionName; - } - - bool Option::hasFlag(enum States s) const{ - return want & s; - } -} diff --git a/msh-console-library/option.h b/msh-console-library/option.h deleted file mode 100644 index 992c4c9..0000000 --- a/msh-console-library/option.h +++ /dev/null @@ -1,20 +0,0 @@ -#include -using std::string; - -namespace mshconsole{ - class Option{ - string optionName; - class OptionNameEmptyException{}; - public: - enum States{ - STRING=2, - BOOL=1 - }; - private: - enum States want; - public: - Option(const string& s, enum States b); - const string& getOptionName() const; - bool hasFlag(enum States s) const; - }; -} diff --git a/msh-console-library/shell.cpp b/msh-console-library/shell.cpp index 44fac0e..f988d15 100644 --- a/msh-console-library/shell.cpp +++ b/msh-console-library/shell.cpp @@ -43,7 +43,7 @@ namespace mshconsole { //launch loop string* line; - vector* args; + struct Params p; int exitCode; try{ do { @@ -59,10 +59,9 @@ namespace mshconsole { readSuccess = false; } }while(!readSuccess); - args = split_line(line); - executeCmd(args); - delete args; - } while (1); + p = split_line(line); + executeCmd(p); + } while (1); } catch(CommandExecutor::ExitException c) { exitCode=c.getCode(); } @@ -74,7 +73,7 @@ namespace mshconsole { return exitCode; } - int Shell::launchCmd(vector* args) + int Shell::launchCmd(const struct Params& p) { using std::exit; int status; @@ -86,19 +85,12 @@ namespace mshconsole { //execute threadCommand int a; try { - a=cmds.launch(args, true); + a=cmds.launch(p, true); } catch (CommandNotFoundException){ //execute bash command or program - vector argv(args->size() + 1); - size_t i; - for (i = 0; i != args->size()-1; ++i) - { - argv[i] = &(args->operator[](i)[0]); - } - argv[i] = NULL; - if((a=execvp(argv[0], argv.data())) == -1) { - cerr << name <<": command " << args->operator [](0) << " not found\n"; + if((a=execvp(p.argv[0], p.argv)) == -1) { + cerr << name <<": command " << p.argv[0] << " not found\n"; } exit(EXIT_FAILURE); } @@ -118,18 +110,17 @@ namespace mshconsole { return 1; } - int Shell::executeCmd(vector* args) + int Shell::executeCmd(const struct Params& p) { - if (args->operator [](0) == "\0") { - // An empty command was entered. + if (!p.argc) { //empty line return 1; } int ret; try { - ret = cmds.launch(args, false); + ret = cmds.launch(p, false); } catch(CommandNotFoundException) { - ret = launchCmd(args); + ret = launchCmd(p); } return ret; } @@ -181,17 +172,10 @@ namespace mshconsole { return buffer; } - vector* Shell::split_line(const string* line) - { - vector* tokens = new vector(); - string ln = *line; - istringstream is(ln); - int i; - for(i=0; getline(is, ln, ' '); i++){ - tokens->push_back(ln); - } - tokens->push_back("\0"); - return tokens; + struct Params Shell::split_line(const string* line){ + struct Params p; + stringToArgcArgv(*line, &(p.argc), &(p.argv)); + return p; } bool Shell::undoingLine = false; diff --git a/msh-console-library/shell.h b/msh-console-library/shell.h index 257b6dc..de6ef76 100644 --- a/msh-console-library/shell.h +++ b/msh-console-library/shell.h @@ -1,18 +1,19 @@ #ifndef SHELL_H #define SHELL_H +#pragma once + #include #include #include -#include -#include #include -#include #include +#include #include #include #include "command.h" -//#include "commands.h" +#include #include "commandexecutor.h" +#include "stringtoargcargv.h" using std::string; using std::cin; using std::cout; @@ -35,7 +36,7 @@ namespace mshconsole { Commands(Shell*); void add(Command*, bool isthread=false); size_t howMany() const; - int launch(const vector* args, bool launchThread=false); + int launch(const struct Params& args, bool launchThread=false); }; static bool undoingLine; @@ -46,10 +47,10 @@ namespace mshconsole { void (*shellPostSetup)(Shell *); bool notLoop; - int launchCmd(vector* args); + int launchCmd(const struct Params& args); static void EofHandler(int); string* read_line(); - vector* split_line(const string* line); + struct Params split_line(const string* line); class IsUndoingLineException {}; class CommandNotFoundException {}; @@ -69,7 +70,7 @@ namespace mshconsole { //for in-shell commands void addCmd(Command *cmd, bool isThread=false); size_t howManyCmds() const; - int executeCmd(vector* args); + int executeCmd(const struct Params& args); int executeCmd(const string& args); }; } diff --git a/msh-console-library/stringtoargcargv.cpp b/msh-console-library/stringtoargcargv.cpp new file mode 100644 index 0000000..b35d9ab --- /dev/null +++ b/msh-console-library/stringtoargcargv.cpp @@ -0,0 +1,192 @@ +/* stringtoargcargv.cpp -- Parsing a string to std::vector + + Copyright (C) 2011 Bernhard Eder + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Bernhard Eder blog_at_bbgen.net + +*/ + +#include "stringtoargcargv.h" + +/* + * Usage: + * int argc; + * char** argv; + * stringToArgcArgv("foo bar", &argc, &argv); + */ +void stringToArgcArgv(const std::string& str, int* argc, char*** argv) +{ + std::vector args = parse(str); + + *argv = (char**)std::malloc(args.size() * sizeof(char*)); + + int i=0; + for(std::vector::iterator it = args.begin(); + it != args.end(); + ++it, ++i) + { + std::string arg = *it; + (*argv)[i] = (char*)std::malloc((arg.length()+1) * sizeof(char)); + std::strcpy((*argv)[i], arg.c_str()); + } + + *argc = args.size(); +} + +std::vector parse(const std::string& args) +{ + std::stringstream ain(args); // used to iterate over input string + ain >> std::noskipws; // do not skip white spaces + std::vector oargs; // output list of arguments + + std::stringstream currentArg(""); + currentArg >> std::noskipws; + + // current state + enum State { + InArg, // currently scanning an argument + InArgQuote, // currently scanning an argument (which started with quotes) + OutOfArg // currently not scanning an argument + }; + State currentState = OutOfArg; + + char currentQuoteChar = '\0'; // to distinguish between ' and " quotations + // this allows to use "foo'bar" + + char c; + while(!ain.eof() && (ain >> c)) { // iterate char by char + + if(_isQuote(c)) { + switch(currentState) { + case OutOfArg: + currentArg.str(std::string()); + case InArg: + currentState = InArgQuote; + currentQuoteChar = c; + break; + + case InArgQuote: + if(c == currentQuoteChar) + currentState = InArg; + else + currentArg << c; + break; + } + + } + else if(_isWhitespace(c)) { + switch(currentState) { + case InArg: + oargs.push_back(currentArg.str()); + currentState = OutOfArg; + break; + case InArgQuote: + currentArg << c; + break; + case OutOfArg: + // nothing + break; + } + } + else if(_isEscape(c)) { + switch(currentState) { + case OutOfArg: + currentArg.str(std::string()); + currentState = InArg; + case InArg: + case InArgQuote: + if(ain.eof()) + { +#ifdef WIN32 + // Windows doesn't care about an escape character at the end. + // It just adds \ to the arg. + currentArg << c; +#else + throw(std::runtime_error("Found Escape Character at end of file.")); +#endif + } + else + { +#ifdef WIN32 + // Windows only escapes the " character. + // Every other character is just printed and the \ is added itself. + char c1 = c; + ain >> c; + if(c != '\"') + currentArg << c1; // only ignore \ when next char is " + ain.unget(); +#else + ain >> c; + currentArg << c; +#endif + } + break; + } + } + else { + switch(currentState) { + case InArg: + case InArgQuote: + currentArg << c; + break; + + case OutOfArg: + currentArg.str(std::string()); + currentArg << c; + currentState = InArg; + break; + } + } + } + + if(currentState == InArg) + oargs.push_back(currentArg.str()); + else if(currentState == InArgQuote) + throw(std::runtime_error("Starting quote has no ending quote.")); + + return oargs; +} + +bool _isQuote(char c) +{ + if(c == '\"') + return true; + else if(c == '\'') + return true; + + return false; +} + +bool _isEscape(char c) +{ + if(c == '\\') + return true; + + return false; +} + +bool _isWhitespace(char c) +{ + if(c == ' ') + return true; + else if(c == '\t') + return true; + + return false; +} diff --git a/msh-console-library/stringtoargcargv.h b/msh-console-library/stringtoargcargv.h new file mode 100644 index 0000000..b274b9b --- /dev/null +++ b/msh-console-library/stringtoargcargv.h @@ -0,0 +1,45 @@ +#ifndef STRINGTOARGCARGV_H +#define STRINGTOARGCARGV_H +#pragma once + +/* stringtoargcargv.cpp -- Parsing a string to std::vector + + Copyright (C) 2011 Bernhard Eder + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Bernhard Eder blog_at_bbgen.net + +*/ + +#include +#include +#include +#include +#include + +#include +#include + +bool _isQuote(char c); +bool _isEscape(char c); +bool _isEscape(char c); +bool _isWhitespace(char c); +std::vector parse(const std::string& args); +void stringToArgcArgv(const std::string& str, int* argc, char*** argv); + +#endif //STRINGTOARGCARGV_H