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.
This commit is contained in:
Claudio Maggioni 2016-04-16 19:21:39 +02:00
parent 709a2e6c1c
commit f6c3135c27
14 changed files with 425 additions and 272 deletions

View file

@ -3,11 +3,6 @@ Library that provides a bash-like interface for CLI C++ programs
### Credits ### Credits
Code based on "Write a Shell in C" - by Stephen Brennan (http://brennan.io/2015/01/16/write-a-shell-in-c/) 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 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
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: The library can be compiled as shared library with the CMakeLists.txt file already in msh-console-library/.
```
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
```

View file

@ -4,7 +4,7 @@
project(msh-console-library) project(msh-console-library)
cmake_minimum_required(VERSION 2.8) 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 sources *.cpp)
FILE(GLOB headers *.h) FILE(GLOB headers *.h)

View file

@ -1,137 +1,77 @@
#include "shell.h" #include "shell.h"
namespace mshconsole { namespace mshconsole {
Command::Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector<char*> argv)) : Command::Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector<const char*> argv)) :
name(n), funcCommand(funcptr){ name(n), funcCommand(funcptr), optionNum(0){
checkObj(); checkObj();
} }
void Command::addOption(Option *a){ void Command::addOption(const poptOption& a){
if(a->getOptionName().length()==1){ if(a.arg!=NULL&&a.arg!=nullptr&&a.arg!=0) throw InvalidOptionException{};
shortOpts.push_back(a); for(int i=0; i<opts.size(); i++)
} if(strcmp((opts[i].longName),(a.longName))==0||
else longOpts.push_back(a); opts[i].shortName==a.shortName)
throw DuplicatedOptionException();
opts.push_back(a);
optionNum++;
} }
int Command::execute(const vector<string>* args, CommandExecutor* c){ int Command::execute(const struct Params& p, CommandExecutor* c){
if(args==nullptr) return -1; if(p.argc<=0) return -1;
//filling longData // options a, b, c take integer arguments
Datas longData; // options f and g take no arguments
for(size_t i=0; i<longOpts.size(); i++){ poptContext pc;
longData.push_back(new Data(longOpts[i])); opts.push_back(POPT_TERMINATOR);
Datas datas;
for(int i=0; i<optionNum; i++){
Data* tmp = new Data(&opts[i]);
opts[i].arg=&(tmp->d);
datas.push_back(tmp);
} }
//filling string for getopt and shortData // pc is the context for all popt-related functions
string getoptarg; pc = poptGetContext(NULL, p.argc, const_cast<const char**>(p.argv), opts.data(), 0);
Datas shortData; poptSetOtherOptionHelp(pc, "[ARG...]");
for(size_t i=0; i<shortOpts.size(); i++){ if (p.argc < 2 && opts.size()==0) {
shortData.push_back(new Data(shortOpts[i])); poptPrintUsage(pc, stderr, 0);
getoptarg.append(1,shortOpts[i]->getOptionName()[0]); return 1;
}
getoptarg+=" -:";
//creating argv as char** for getopt compatibility
vector<char *> argv(args->size());
size_t i;
for (i = 0; i < args->size(); ++i)
{
argv[i] = const_cast<char*>(&(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; i<shortOpts.size(); i++){
if(c==shortOpts[i]->getOptionName()[0]){
shortData[i]->set(true);
break;
}
}
}
else if(c=='-'){
string l(optarg);
bool getout = false;
try{
for(size_t i=0; i<longOpts.size(); i++){
if(l.find(longOpts[i]->getOptionName()+"=")==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<string>("--") + 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) // process options and handle each val returned
/* int val;
for(size_t i=0; i<longOpts.size(); i++){ while ((val = poptGetNextOpt(pc)) >= 0);
cout << longOpts[i]->getOptionName() << ": ";
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<shortOpts.size(); i++){
cout << shortOptions[i] << ": " << sLongData[i] << "\n";
}*/
}
catch(OptionNotParsedCorrectlyException e){
cout << "Error parsing option " << e.getOptarg() << "\n";
return -1;
}
catch(NotRightArgException){
cout << "Error on options argument type\n";
return -1;
}
//making one big Data vector // poptGetNextOpt returns -1 when the final argument has been parsed
shortOpts.insert( // otherwise an error occured
shortOpts.end(), if (val != -1) {
std::make_move_iterator(longOpts.begin()), cerr << name << ": ";
std::make_move_iterator(longOpts.end()) switch(val) {
); case POPT_ERROR_NOARG:
cerr << "argument missing for an option\n";
//deleting options and command name from argv return 1;
argv.erase(argv.begin()); //argv[0] = command name case POPT_ERROR_BADOPT:
for(int i=0; i<argv.size(); i++){ cerr << "option not found\n";
if(argv[0][0]=='-'){ return 1;
argv.erase(argv.begin()+i); case POPT_ERROR_BADNUMBER:
i--; case POPT_ERROR_OVERFLOW:
cerr << "option could not be converted to number\n";
return 1;
default:
cerr << "unknown error in option processing\n";
return 1;
} }
} }
return (*funcCommand)(c,shortData, argv); vector<const char*> nonOptionArgs;
while (poptPeekArg(pc) != NULL)
nonOptionArgs.push_back(const_cast<const char*>(poptGetArg(pc)));
return (*funcCommand)(c,datas,nonOptionArgs);
} }
string Command::getName(){ const string& Command::getName(){
return this->name; 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};
} }

View file

@ -1,9 +1,12 @@
#ifndef COMMAND_H #ifndef COMMAND_H
#define COMMAND_H #define COMMAND_H
#pragma once
#include <string> #include <string>
#include <vector> #include <vector>
//#include "shell.h" #include <unistd.h>
#include "option.h" extern "C"{
#include <popt.h>
}
#include "commandexecutor.h" #include "commandexecutor.h"
using std::string; using std::string;
@ -12,71 +15,67 @@ using std::vector;
namespace mshconsole{ namespace mshconsole{
class Command class Command
{ {
class OptionNotParsedCorrectlyException {
string optarg;
public:
OptionNotParsedCorrectlyException(const string& s) : optarg(s) {}
string getOptarg(){
return optarg;
}
};
class CommandNameNotValidException {};
class NotRightArgException {};
const string name; const string name;
void checkObj(); void checkObj();
vector<Option*> longOpts; vector<poptOption> opts;
vector<Option*> shortOpts; static const struct poptOption POPT_TERMINATOR;
size_t optionNum;
public: public:
class Data{ class Data{
public: public:
enum States{ union Arg{
STRING=4, int i;
TRUE=2, char* s;
FALSE=1 long l;
float f;
double d;
};
enum Types{
STRING,
INT,
LONG,
FLOAT,
DOUBLE
}; };
class MultipleDefinitionException{};
private: private:
string sData; union Arg d;
const Option* of; poptOption* of;
enum States state; Data(poptOption* o) : of(o), d() {}
static const string EMPTY; friend class mshconsole::Command;
bool isSDataValorized;
Data(const Option* o) : sData(), state(Data::FALSE), isSDataValorized(false), of(o) {}
public: public:
void set(bool b); const union Arg& getArg() const;
void set(const string& s); enum Types getType() const;
enum States getState() const; int getInt() const;
const string& getData() const; char* getString() const;
bool getBoolState() const; long getLong() const;
friend class Command; float getFloat() const;
friend class Datas; double getDouble() const;
}; };
class Datas : public vector<Data*>{ class Datas : public vector<Data*>{
public: public:
Data* getOptData(const string& optionName) const; 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<char*> argv)); class DuplicatedOptionException{};
class CommandNameNotValidException{};
class InvalidOptionException{};
Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector<const char*> argv));
Command(const Command&); Command(const Command&);
~Command(); ~Command();
string getName(); const string& getName();
int execute(const vector<string>*, CommandExecutor*); int execute(const struct Params&, CommandExecutor*);
void addOption(Option* a); void addOption(const poptOption& option);
private: private:
int (*funcCommand)(CommandExecutor* whoExecuted,const Datas& data, const vector<char*> argv); int (*funcCommand)(CommandExecutor* whoExecuted,const Datas& data, const vector<const char*> argv);
}; };
} }
#endif // COMMAND_H #endif // COMMAND_H

View file

@ -1,5 +1,6 @@
#ifndef COMMANDEXECUTOR_H #ifndef COMMANDEXECUTOR_H
#define COMMANDEXECUTOR_H #define COMMANDEXECUTOR_H
#pragma once
#include <vector> #include <vector>
#include <string> #include <string>
@ -16,12 +17,16 @@ namespace mshconsole{
ExitException(int c=0) : code(c){} ExitException(int c=0) : code(c){}
}; };
public: public:
virtual int executeCmd(std::vector<std::string>* args) = 0; virtual int executeCmd(const struct Params& args) = 0;
virtual int executeCmd(const std::string& args) = 0; virtual int executeCmd(const std::string& args) = 0;
virtual size_t howManyCmds() const = 0; virtual size_t howManyCmds() const = 0;
void exit(int code=0); void exit(int code=0);
CommandExecutor(); CommandExecutor();
}; };
struct Params{
int argc;
char** argv;
};
} }
#endif // COMMANDEXECUTOR_H #endif // COMMANDEXECUTOR_H

View file

@ -14,10 +14,10 @@ namespace mshconsole {
return commands.size(); return commands.size();
} }
int Shell::Commands::launch(const vector<string>* 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++){ for(unsigned int i=0; i<(launchThread ? threadCommands.size() : commands.size()); i++){
if((launchThread ? threadCommands[i]->getName() : commands[i]->getName())==args->operator [](0)){ if((launchThread ? threadCommands[i]->getName() : commands[i]->getName())==p.argv[0]){
return (launchThread ? threadCommands[i]->execute(args, parent) : commands[i]->execute(args, parent)); return (launchThread ? threadCommands[i]->execute(p, parent) : commands[i]->execute(p, parent));
} }
} }
throw CommandNotFoundException(); throw CommandNotFoundException();

View file

@ -1,30 +1,40 @@
#include "command.h" #include "command.h"
namespace mshconsole{ namespace mshconsole{
void Command::Data::set(bool b){ inline const union Command::Data::Arg& Command::Data::getArg() const{
if(isSDataValorized) throw MultipleDefinitionException(); return d;
b ? state=Data::TRUE : state=Data::FALSE;
isSDataValorized=true;
} }
void Command::Data::set(const string& s){ enum Command::Data::Types Command::Data::getType() const{
if(isSDataValorized) throw MultipleDefinitionException(); if(of->argInfo & POPT_ARG_INT || of->argInfo & POPT_ARG_VAL || of->argInfo == POPT_ARG_NONE){
state=Data::STRING; return INT;
sData=s;
isSDataValorized=true;
} }
enum Command::Data::States Command::Data::getState() const{ else if(of->argInfo & POPT_ARG_STRING){
return state; return STRING;
} }
const string& Command::Data::getData() const{ else if(of->argInfo & POPT_ARG_LONG){
if(state!=Data::STRING) return EMPTY; return LONG;
else return sData;
} }
bool Command::Data::getBoolState() const{ else if(of->argInfo & POPT_ARG_FLOAT){
return state!=Data::FALSE; return FLOAT;
}
Command::Data* Command::Datas::getOptData(const string& opt) const{
for(size_t i=0; i<size(); i++){
if(operator[](i)->of->getOptionName()==opt) return operator[](i);
} }
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<char*>("");
}
long Command::Data::getLong() const{
return d.l;
}
float Command::Data::getFloat() const{
return d.f;
}
double Command::Data::getDouble() const{
return d.d;
} }
} }

View file

@ -0,0 +1,19 @@
#include "command.h"
namespace mshconsole {
Command::Data* Command::Datas::getOptData(const string& opt) const{
for(size_t i=0; i<this->size(); 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; i<this->size(); 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;
}
}

View file

@ -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;
}
}

View file

@ -1,20 +0,0 @@
#include <string>
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;
};
}

View file

@ -43,7 +43,7 @@ namespace mshconsole {
//launch loop //launch loop
string* line; string* line;
vector<string>* args; struct Params p;
int exitCode; int exitCode;
try{ try{
do { do {
@ -59,9 +59,8 @@ namespace mshconsole {
readSuccess = false; readSuccess = false;
} }
}while(!readSuccess); }while(!readSuccess);
args = split_line(line); p = split_line(line);
executeCmd(args); executeCmd(p);
delete args;
} while (1); } while (1);
} catch(CommandExecutor::ExitException c) { } catch(CommandExecutor::ExitException c) {
exitCode=c.getCode(); exitCode=c.getCode();
@ -74,7 +73,7 @@ namespace mshconsole {
return exitCode; return exitCode;
} }
int Shell::launchCmd(vector<string>* args) int Shell::launchCmd(const struct Params& p)
{ {
using std::exit; using std::exit;
int status; int status;
@ -86,19 +85,12 @@ namespace mshconsole {
//execute threadCommand //execute threadCommand
int a; int a;
try { try {
a=cmds.launch(args, true); a=cmds.launch(p, true);
} }
catch (CommandNotFoundException){ catch (CommandNotFoundException){
//execute bash command or program //execute bash command or program
vector<char *> argv(args->size() + 1); if((a=execvp(p.argv[0], p.argv)) == -1) {
size_t i; cerr << name <<": command " << p.argv[0] << " not found\n";
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";
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -118,18 +110,17 @@ namespace mshconsole {
return 1; return 1;
} }
int Shell::executeCmd(vector<string>* args) int Shell::executeCmd(const struct Params& p)
{ {
if (args->operator [](0) == "\0") { if (!p.argc) { //empty line
// An empty command was entered.
return 1; return 1;
} }
int ret; int ret;
try { try {
ret = cmds.launch(args, false); ret = cmds.launch(p, false);
} }
catch(CommandNotFoundException) { catch(CommandNotFoundException) {
ret = launchCmd(args); ret = launchCmd(p);
} }
return ret; return ret;
} }
@ -181,17 +172,10 @@ namespace mshconsole {
return buffer; return buffer;
} }
vector<string>* Shell::split_line(const string* line) struct Params Shell::split_line(const string* line){
{ struct Params p;
vector<string>* tokens = new vector<string>(); stringToArgcArgv(*line, &(p.argc), &(p.argv));
string ln = *line; return p;
istringstream is(ln);
int i;
for(i=0; getline(is, ln, ' '); i++){
tokens->push_back(ln);
}
tokens->push_back("\0");
return tokens;
} }
bool Shell::undoingLine = false; bool Shell::undoingLine = false;

View file

@ -1,18 +1,19 @@
#ifndef SHELL_H #ifndef SHELL_H
#define SHELL_H #define SHELL_H
#pragma once
#include <iostream> #include <iostream>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <cstdlib>
#include <sstream>
#include <string> #include <string>
#include <cstring>
#include <vector> #include <vector>
#include <sstream>
#include <cstddef> #include <cstddef>
#include <csignal> #include <csignal>
#include "command.h" #include "command.h"
//#include "commands.h" #include <wordexp.h>
#include "commandexecutor.h" #include "commandexecutor.h"
#include "stringtoargcargv.h"
using std::string; using std::string;
using std::cin; using std::cin;
using std::cout; using std::cout;
@ -35,7 +36,7 @@ namespace mshconsole {
Commands(Shell*); Commands(Shell*);
void add(Command*, bool isthread=false); void add(Command*, bool isthread=false);
size_t howMany() const; size_t howMany() const;
int launch(const vector<string>* args, bool launchThread=false); int launch(const struct Params& args, bool launchThread=false);
}; };
static bool undoingLine; static bool undoingLine;
@ -46,10 +47,10 @@ namespace mshconsole {
void (*shellPostSetup)(Shell *); void (*shellPostSetup)(Shell *);
bool notLoop; bool notLoop;
int launchCmd(vector<string>* args); int launchCmd(const struct Params& args);
static void EofHandler(int); static void EofHandler(int);
string* read_line(); string* read_line();
vector<string>* split_line(const string* line); struct Params split_line(const string* line);
class IsUndoingLineException {}; class IsUndoingLineException {};
class CommandNotFoundException {}; class CommandNotFoundException {};
@ -69,7 +70,7 @@ namespace mshconsole {
//for in-shell commands //for in-shell commands
void addCmd(Command *cmd, bool isThread=false); void addCmd(Command *cmd, bool isThread=false);
size_t howManyCmds() const; size_t howManyCmds() const;
int executeCmd(vector<string>* args); int executeCmd(const struct Params& args);
int executeCmd(const string& args); int executeCmd(const string& args);
}; };
} }

View file

@ -0,0 +1,192 @@
/* stringtoargcargv.cpp -- Parsing a string to std::vector<string>
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<std::string> args = parse(str);
*argv = (char**)std::malloc(args.size() * sizeof(char*));
int i=0;
for(std::vector<std::string>::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<std::string> 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<std::string> 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;
}

View file

@ -0,0 +1,45 @@
#ifndef STRINGTOARGCARGV_H
#define STRINGTOARGCARGV_H
#pragma once
/* stringtoargcargv.cpp -- Parsing a string to std::vector<string>
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 <iostream>
#include <sstream>
#include <stdexcept>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
bool _isQuote(char c);
bool _isEscape(char c);
bool _isEscape(char c);
bool _isWhitespace(char c);
std::vector<std::string> parse(const std::string& args);
void stringToArgcArgv(const std::string& str, int* argc, char*** argv);
#endif //STRINGTOARGCARGV_H