msh-console/msh-console-library/command.cpp

150 lines
5.2 KiB
C++

#include "shell.h"
namespace mshconsole {
Command::Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector<char*> argv)) :
name(n), funcCommand(funcptr){
checkObj();
}
void Command::addOption(Option *a){
if(a->getOptionName().length()==1){
shortOpts.push_back(a);
}
else longOpts.push_back(a);
}
int Command::execute(const vector<string>* args, CommandExecutor* c){
if(args==nullptr) return -1;
//filling longData
Datas longData;
for(size_t i=0; i<longOpts.size(); i++){
longData.push_back(new Data(longOpts[i]));
}
//filling string for getopt and shortData
string getoptarg;
Datas shortData;
for(size_t i=0; i<shortOpts.size(); i++){
shortData.push_back(new Data(shortOpts[i]));
getoptarg.append(1,shortOpts[i]->getOptionName()[0]);
}
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)
/*
for(size_t i=0; i<longOpts.size(); i++){
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
shortOpts.insert(
shortOpts.end(),
std::make_move_iterator(longOpts.begin()),
std::make_move_iterator(longOpts.end())
);
//deleting options and command name from argv
argv.erase(argv.begin()); //argv[0] = command name
for(int i=0; i<argv.size(); i++){
if(argv[0][0]=='-'){
argv.erase(argv.begin()+i);
i--;
}
}
return (*funcCommand)(c,shortData, argv);
}
string Command::getName(){
return this->name;
}
Command::Command(const Command& old) : name(old.name) , funcCommand(old.funcCommand){
checkObj();
}
void Command::checkObj(){
for(unsigned int i=0; i<name.length(); i++){
if(!((name[i]>'a'&&name[i]<'z')||(name[i]>'A'&&name[i]<'Z'))){
throw CommandNameNotValidException();
}
}
}
const string Command::Data::EMPTY("");
}