Started work on automated option (flags) handling. Current code is incomplete.

This commit is contained in:
Claudio Maggioni 2016-04-02 16:28:03 +02:00
parent 9e5ab340d9
commit 00d937f28c
8 changed files with 289 additions and 38 deletions

3
.gitignore vendored
View file

@ -1,6 +1,9 @@
# Build folders
build-*
#internal test
msh-console-library/main.cpp
# Autosaves
*.autosave

View file

@ -1,9 +1,25 @@
# msh-console dynamic library by praticamentetilde (Claudio Maggioni)
# licensed with "The Unlicense"
project(msh-console-library)
cmake_minimum_required(VERSION 2.8)
# Create a library which includes the source listed.
# The extension is already found. Any number of sources could be listed here.
SET(CMAKE_CXX_FLAGS "-std=c++11")
add_library (mshconsole SHARED command.cpp commandexecutor.cpp commandexecutor.h command.h commands.cpp shell.cpp shell.h)
set(compilable OFF)
if(${compilable})
SET(CMAKE_CXX_FLAGS "-std=c++11")
FILE(GLOB sources *.cpp)
FILE(GLOB headers *.h)
set(lib OFF)
if(${lib})
MESSAGE( STATUS "Building .so.1")
#compile the library
# Create a library which includes the source listed.
# The extension is already found. Any number of sources could be listed here.
list(REMOVE_ITEM SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
add_library (mshconsole SHARED ${SRC_LIST})
else(${lib})
MESSAGE( STATUS "Building exec (debug only)")
add_executable(${PROJECT_NAME} ${sources} ${headers})
endif(${lib})
endif(${compilable})

View file

@ -1,14 +1,106 @@
#include "shell.h"
namespace mshconsole {
Command::Command(const string& n, int (*funcptr)(const vector<string>* args, CommandExecutor*)) : name(n) , funcCommand(funcptr){
Command::Command(const string& n, int (*funcptr)(CommandExecutor*,const vector<LongData*>&,const vector<bool>&, const char** argv)) :
name(n), funcCommand(funcptr){
checkObj();
numCom++;
}
int Command::execute(const vector<string>* args, CommandExecutor* ciao){
int Command::execute(const vector<string>* args, CommandExecutor* c){
if(args==nullptr) return -1;
return (*funcCommand)(args, ciao);
vector<LongData*> data;
for(size_t i=0; i<longOptions.size(); i++){
data.push_back(new LongData());
}
vector<bool> sLongData;
for(size_t i=0; i<shortOptions.size(); i++){
sLongData.push_back(false);
}
string getoptarg;
for(size_t i=0; i<shortOptions.size(); i++){
getoptarg.append(1,shortOptions[i]);
}
getoptarg+=" -:";
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<shortOptions.size(); i++){
if(c==shortOptions[i]){
sLongData[i]=true;
}
}
}
else if(c=='-'){
string l(optarg);
bool getout = false;
try{
for(size_t i=0; i<longOptions.size(); i++){
if(l.find(longOptions[i]->getArgName()+"=")==0){
if(!(longOptions.at(i)->hasFlag(LongOption::STRING))){
throw NotRightArgException();
}
data[i]->set(l.substr(longOptions[i]->getArgName().size()+1,l.size()));
getout = true;
break;
}
if(l==longOptions[i]->getArgName()){
data[i]->set(true);
getout=true;
break;
}
}
}
catch(LongData::MultipleDefinitionException){
getout=false;
}
if(!getout) throw OptionNotParsedCorrectlyException(static_cast<string>("--") + optarg);
}
else if(c=='?'){
//if (optopt == 'c')
// fprintf (stderr, "Option -%c requires an argument.\n", optopt); else
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 for debug
/*
for(size_t i=0; i<longOptions.size(); i++){
cout << longOptions[i]->getArgName() << ": ";
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<shortOptions.size(); i++){
cout << shortOptions[i] << ": " << sLongData[i] << "\n";
}*/
}
catch(OptionNotParsedCorrectlyException e){
cout << "Error parsing option " << e.getOptarg() << "\n";
}
catch(NotRightArgException){
cout << "Error on options argument type\n";
}
return (*funcCommand)(c,data,sLongData, const_cast<const char**>(argv.data()));
}
string Command::getName(){
@ -17,7 +109,6 @@ namespace mshconsole {
Command::Command(const Command& old) : name(old.name) , funcCommand(old.funcCommand){
checkObj();
numCom++;
}
void Command::checkObj(){
@ -28,9 +119,52 @@ namespace mshconsole {
}
}
/*Command::Options *Command::getCmdOpts() const
{
return cmdOpts;
}
void Command::setCmdOpts(Command::Options *value)
{
cmdOpts = value;
}
Command::~Command(){
numCom--;
}
unsigned int Command::numCom = 0;
unsigned int Command::numCom = 0;
const Command::Options *(Command::defaultOpts) = new Command::Options();
string Command::Options::Option::getOShort() const
{
return oShort;
}
void Command::Options::Option::setOShort(const string &value)
{
oShort = value;
}
string Command::Options::Option::getOLong() const
{
return oLong;
}
void Command::Options::Option::setOLong(const string &value)
{
oLong = value;
}
void Command::Options::addOption(Command::Options::Option *a){
for(size_t i=0; i<this->howMany(); i++){
if(a->getOShort()==(this->operator [](i)->getOShort())||a->getOLong()==(this->operator [](i)->getOLong())){
throw OptionNameConflictException();
}
}
opts.push_back(a);
}*/
const string Command::LongData::EMPTY("");
}

View file

@ -11,19 +11,106 @@ 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 {};
vector<char> shortOptions;
const string name;
static unsigned int numCom;
int (*funcCommand)(const vector<string>*,CommandExecutor*);
void checkObj();
public:
Command(const string& n, int (*funcptr)(const vector<string>* args, CommandExecutor*));
class LongData{
public:
enum States{
STRING=4,
TRUE=2,
FALSE=1
};
class MultipleDefinitionException{};
private:
string sLongData;
enum States state;
static const string EMPTY;
bool isSLongDataValorized;
public:
LongData() : sLongData(), state(LongData::FALSE), isSLongDataValorized(false) {}
void set(bool b){
if(isSLongDataValorized) throw MultipleDefinitionException();
b ? state=LongData::TRUE : state=LongData::FALSE;
isSLongDataValorized=true;
}
void set(const string& s){
if(isSLongDataValorized) throw MultipleDefinitionException();
state=LongData::STRING;
sLongData=s;
isSLongDataValorized=true;
}
enum LongData::States getState() const{
return state;
}
const string& getLongData() const{
if(state!=LongData::STRING) return EMPTY;
else return sLongData;
}
bool getBoolState() const{
return state!=LongData::FALSE;
}
};
Command(const string& n, int (*funcptr)(CommandExecutor*, const vector<LongData*>&, const vector<bool>&, const char** argv));
Command(const Command&);
~Command();
string getName();
int execute(const vector<string>*, CommandExecutor* ciao);
int execute(const vector<string>*, CommandExecutor*);
class LongOption{
string argName;
public:
enum States{
STRING=2,
BOOL=1
};
private:
enum States want;
public:
LongOption(const string& s, enum States b) : argName(s), want(b) {}
enum States getWant() const{
return want;
}
const string& getArgName(){
return argName;
}
bool hasFlag(enum States s){
return want & s;
}
};
void addLongOption(LongOption* a){
longOptions.push_back(a);
}
void addShortOption(char a){
shortOptions.push_back(a);
}
private:
vector<LongOption*> longOptions;
int (*funcCommand)(CommandExecutor*,const vector<LongData*>&, const vector<bool>&, const char** argv);
};
inline Command::LongOption::States operator|(Command::LongOption::States a, Command::LongOption::States b){
return static_cast<Command::LongOption::States>(static_cast<int>(a) | static_cast<int>(b));
}
}
class CommandNameNotValidException{};
#endif // COMMAND_H

View file

@ -1,7 +1,7 @@
#include "commandexecutor.h"
namespace mshconsole {
CommandExecutor::CommandExecutor() {}
void CommandExecutor::exit(){
throw CommandExecutor::ExitException();
void CommandExecutor::exit(int code){
throw CommandExecutor::ExitException(code);
}
}

View file

@ -7,12 +7,19 @@ namespace mshconsole{
class CommandExecutor
{
protected:
class ExitException {};
class ExitException {
int code;
public:
int getCode(){
return code;
}
ExitException(int c=0) : code(c){}
};
public:
virtual int executeCmd(std::vector<std::string>* args) = 0;
virtual int executeCmd(const std::string& args) = 0;
virtual size_t howManyCmds() const = 0;
void exit();
void exit(int code=0);
CommandExecutor();
};
}

View file

@ -29,11 +29,11 @@ namespace mshconsole {
notLoop = false;
}
void Shell::launch(){
int Shell::launch(){
//launch setup
if(notLoop) {
return;
return -1;
}
if(shellSetup!=0) {
notLoop = true;
@ -44,7 +44,7 @@ namespace mshconsole {
//launch loop
string* line;
vector<string>* args;
int status;
int exitCode;
try{
do {
bool readSuccess;
@ -60,15 +60,18 @@ namespace mshconsole {
}
}while(!readSuccess);
args = split_line(line);
status = executeCmd(args);
executeCmd(args);
delete args;
} while (1);
} catch(CommandExecutor::ExitException) {}
} catch(CommandExecutor::ExitException c) {
exitCode=c.getCode();
}
//launch postSetup
if(shellPostSetup!=0) {
shellPostSetup(this);
}
return exitCode;
}
int Shell::launchCmd(vector<string>* args)

View file

@ -8,6 +8,7 @@
#include <string>
#include <cstring>
#include <vector>
#include <cstddef>
#include <csignal>
#include "command.h"
//#include "commands.h"
@ -19,7 +20,6 @@ using std::cerr;
using std::string;
using std::vector;
using std::istringstream;
using std::nullptr_t;
namespace mshconsole {
@ -37,6 +37,7 @@ namespace mshconsole {
size_t howMany() const;
int launch(const vector<string>* args, bool launchThread=false);
};
static bool undoingLine;
Commands cmds;
string ps;
@ -59,7 +60,7 @@ namespace mshconsole {
void setPs(const string &value);
string getName() const;
void setName(const string &value);
void launch();
int launch();
void setShellSetup(void (*)(Shell *));
void (*getShellSetup())(Shell*);
void setShellPostSetup(void (*)(Shell *));