Moved snippet in msh-console-snippet repository. All the code in the library is in the namespace mshconsole. Added CommandExecutor::exit() for exiting from the

shell.
This commit is contained in:
Claudio Maggioni 2016-03-18 18:48:16 +01:00
parent e96a300f8e
commit 854b218cb4
14 changed files with 309 additions and 387 deletions

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
# autosaves
*.autosave
#kate directory files #kate directory files
*.directory *.directory

View file

@ -1,9 +0,0 @@
project(msh-console-test)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
# Recurse into the subdirectories. This does not actually
# cause another cmake executable to run. The same process will walk through
# the project's entire directory structure.
add_subdirectory (msh-console-library)
add_subdirectory (snippet)

View file

@ -6,8 +6,4 @@ cmake_minimum_required(VERSION 2.8)
# Create a library which includes the source listed. # Create a library which includes the source listed.
# The extension is already found. Any number of sources could be listed here. # The extension is already found. Any number of sources could be listed here.
SET(CMAKE_CXX_FLAGS "-std=c++11") SET(CMAKE_CXX_FLAGS "-std=c++11")
add_library (msh-console command.cpp commandexecutor.cpp commandexecutor.h command.h commands.cpp shell.cpp shell.h) add_library (mshconsole SHARED command.cpp commandexecutor.cpp commandexecutor.h command.h commands.cpp shell.cpp shell.h)
# Make sure the compiler can find include files for the library
# when other libraries or executables link to this library
target_include_directories (msh-console PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -1,34 +1,36 @@
#include "shell.h" #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)(const vector<string>* args, CommandExecutor*)) : name(n) , funcCommand(funcptr){
checkObj(); checkObj();
numCom++; numCom++;
} }
int Command::execute(const vector<string>* args, CommandExecutor* ciao){ int Command::execute(const vector<string>* args, CommandExecutor* ciao){
if(args==nullptr) return -1; if(args==nullptr) return -1;
return (*funcCommand)(args, ciao); return (*funcCommand)(args, ciao);
} }
string Command::getName(){ string Command::getName(){
return this->name; return this->name;
} }
Command::Command(const Command& old) : name(old.name) , funcCommand(old.funcCommand){ Command::Command(const Command& old) : name(old.name) , funcCommand(old.funcCommand){
checkObj(); checkObj();
numCom++; numCom++;
} }
void Command::checkObj(){ void Command::checkObj(){
for(unsigned int i=0; i<name.length(); i++){ for(unsigned int i=0; i<name.length(); i++){
if(!((name[i]>'a'&&name[i]<'z')||(name[i]>'A'&&name[i]<'Z'))){ if(!((name[i]>'a'&&name[i]<'z')||(name[i]>'A'&&name[i]<'Z'))){
throw CommandNameNotValidException(); throw CommandNameNotValidException();
}
} }
} }
}
Command::~Command(){ Command::~Command(){
numCom--; numCom--;
} }
unsigned int Command::numCom = 0; unsigned int Command::numCom = 0;
}

View file

@ -8,21 +8,22 @@
using std::string; using std::string;
using std::vector; using std::vector;
class Command namespace mshconsole{
{ class Command
const string name; {
static unsigned int numCom; const string name;
int (*funcCommand)(const vector<string>*,CommandExecutor*); static unsigned int numCom;
void checkObj(); int (*funcCommand)(const vector<string>*,CommandExecutor*);
void checkObj();
public:
Command(const string& n, int (*funcptr)(const vector<string>* args, CommandExecutor*));
Command(const Command&);
~Command();
string getName();
int execute(const vector<string>*, CommandExecutor* ciao);
};
public:
Command(const string& n, int (*funcptr)(const vector<string>* args, CommandExecutor*));
Command(const Command&);
~Command();
string getName();
int execute(const vector<string>*, CommandExecutor* ciao);
};
}
class CommandNameNotValidException{}; class CommandNameNotValidException{};
#endif // COMMAND_H #endif // COMMAND_H

View file

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

View file

@ -3,13 +3,18 @@
#include <vector> #include <vector>
#include <string> #include <string>
class CommandExecutor namespace mshconsole{
{ class CommandExecutor
public: {
virtual int executeCmd(std::vector<std::string>* args) = 0; protected:
virtual int executeCmd(const std::string& args) = 0; class ExitException {};
virtual size_t howManyCmds() const = 0; public:
CommandExecutor(); 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();
CommandExecutor();
};
}
#endif // COMMANDEXECUTOR_H #endif // COMMANDEXECUTOR_H

View file

@ -1,26 +1,27 @@
#include "shell.h" #include "shell.h"
namespace mshconsole {
Shell::Commands::Commands(Shell* s) : commands(), threadCommands() Shell::Commands::Commands(Shell* s) : commands(), threadCommands()
{ {
parent = s; parent = s;
} }
void Shell::Commands::add(Command* cmd, bool isthread){ void Shell::Commands::add(Command* cmd, bool isthread){
if(!isthread) commands.push_back(cmd); if(!isthread) commands.push_back(cmd);
else threadCommands.push_back(cmd); else threadCommands.push_back(cmd);
} }
size_t Shell::Commands::howMany() const{ size_t Shell::Commands::howMany() const{
return commands.size(); return commands.size();
} }
int Shell::Commands::launch(const vector<string>* args, bool launchThread){ int Shell::Commands::launch(const vector<string>* args, 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())==args->operator [](0)){
return (launchThread ? threadCommands[i]->execute(args, parent) : commands[i]->execute(args, parent)); return (launchThread ? threadCommands[i]->execute(args, parent) : commands[i]->execute(args, parent));
} }
}
throw CommandNotFoundException();
} }
throw CommandNotFoundException();
} }

View file

@ -1,196 +1,203 @@
#include "shell.h" #include "shell.h"
namespace mshconsole {
string Shell::getPs() const
{
return ps;
}
string Shell::getPs() const void Shell::setPs(const string &value)
{ {
return ps; ps = value;
} }
void Shell::setPs(const string &value) string Shell::getName() const
{ {
ps = value; return name;
} }
string Shell::getName() const void Shell::setName(const string &value)
{ {
return name; name = value;
} }
void Shell::setName(const string &value) Shell::Shell( string n, string ps,void (*s)(Shell*), void (*pss)(Shell*)) : cmds(this)
{ {
name = value; shellSetup = s;
} name = n;
this->ps = ps;
shellPostSetup = pss;
notLoop = false;
}
Shell::Shell( string n, string ps,void (*s)(Shell*), void (*pss)(Shell*)) : cmds(this) void Shell::launch(){
{
shellSetup = s;
name = n;
this->ps = ps;
shellPostSetup = pss;
notLoop = false;
}
void Shell::launch(){ //launch setup
//launch setup if(notLoop) {
if(notLoop) { return;
throw ShellLaunchInSetupException(); }
return; if(shellSetup!=0) {
} notLoop = true;
if(shellSetup!=0) { (*shellSetup)(this);
notLoop = true; notLoop = false;
(*shellSetup)(this); }
notLoop = false;
}
//launch loop
string* line;
vector<string>* args;
int status;
do {
bool readSuccess;
do{
cout << ps << " ";
try{
line = read_line();
readSuccess = true;
}
catch (IsUndoingLineException){
cout << "\n";
readSuccess = false;
}
}while(!readSuccess);
args = split_line(line);
status = executeCmd(args);
delete args;
} while (status);
if(shellPostSetup!=0) {
shellPostSetup(this);
}
}
int Shell::launchCmd(vector<string>* args) //launch loop
{ string* line;
int status; vector<string>* args;
int status;
try{
do {
bool readSuccess;
do{
cout << ps << " ";
try{
line = read_line();
readSuccess = true;
}
catch (IsUndoingLineException){
cout << "\n";
readSuccess = false;
}
}while(!readSuccess);
args = split_line(line);
status = executeCmd(args);
delete args;
} while (1);
} catch(CommandExecutor::ExitException) {}
pid_t pid = fork(); //launch postSetup
if (pid == 0) { if(shellPostSetup!=0) {
//child process shellPostSetup(this);
}
}
//execute threadCommand int Shell::launchCmd(vector<string>* args)
int a; {
try { using std::exit;
a=cmds.launch(args, true); int status;
}
catch (CommandNotFoundException){ pid_t pid = fork();
//execute bash command or program if (pid == 0) {
vector<char *> argv(args->size() + 1); //child process
size_t i;
for (i = 0; i != args->size()-1; ++i) //execute threadCommand
{ int a;
argv[i] = &(args->operator[](i)[0]); try {
a=cmds.launch(args, true);
} }
argv[i] = NULL; catch (CommandNotFoundException){
if((a=execvp(argv[0], argv.data())) == -1) { //execute bash command or program
cerr << name <<": command " << args->operator [](0) << " not found\n"; vector<char *> 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";
}
exit(EXIT_FAILURE);
} }
exit(EXIT_FAILURE); exit(EXIT_SUCCESS);
}
else if (pid < 0) {
// Error forking
cerr << name <<": error forking the process\n";
}
else {
// Parent process
do {
//wait until child finished
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
} }
exit(EXIT_SUCCESS);
}
else if (pid < 0) {
// Error forking
cerr << name <<": error forking the process\n";
}
else {
// Parent process
do {
//wait until child finished
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
int Shell::executeCmd(vector<string>* args)
{
if (args->operator [](0) == "\0") {
// An empty command was entered.
return 1; return 1;
} }
int ret;
try { int Shell::executeCmd(vector<string>* args)
ret = cmds.launch(args, false); {
if (args->operator [](0) == "\0") {
// An empty command was entered.
return 1;
}
int ret;
try {
ret = cmds.launch(args, false);
}
catch(CommandNotFoundException) {
ret = launchCmd(args);
}
return ret;
} }
catch(CommandNotFoundException) {
ret = launchCmd(args); inline int Shell::executeCmd(const std::string &args){
return executeCmd(split_line(&args));
} }
return ret;
}
inline int Shell::executeCmd(const std::string &args){ void Shell::EofHandler(int){
return executeCmd(split_line(&args)); undoingLine = true;
}
void Shell::EofHandler(int){
undoingLine = true;
}
void Shell::setShellSetup(void (*s)(Shell *)){
shellSetup=s;
}
void (*Shell::getShellSetup())(Shell*) {
return shellSetup;
}
void Shell::setShellPostSetup(void (*s)(Shell *)){
shellPostSetup=s;
}
void (*Shell::getShellPostSetup())(Shell*) {
return shellPostSetup;
}
void setEofHandler(void (*funcptr)(int)){
struct sigaction *sa = new struct sigaction();
sa->sa_handler = funcptr;
sa->sa_flags = 0; // not SA_RESTART!;
sigaction(SIGINT, sa, NULL);
delete sa;
}
string* Shell::read_line()
{
string* buffer = new string();
setEofHandler(EofHandler);
getline(cin,*buffer); // get command
cin.clear(); // clear flags
if(undoingLine){
undoingLine=false;
throw IsUndoingLineException();
} }
return buffer;
}
vector<string>* Shell::split_line(const string* line) void Shell::setShellSetup(void (*s)(Shell *)){
{ shellSetup=s;
vector<string>* tokens = new vector<string>();
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;
}
bool Shell::undoingLine = false; void (*Shell::getShellSetup())(Shell*) {
return shellSetup;
}
void Shell::addCmd(Command* cmd, bool isthread){ void Shell::setShellPostSetup(void (*s)(Shell *)){
cmds.add(cmd, isthread); shellPostSetup=s;
} }
size_t Shell::howManyCmds() const{ void (*Shell::getShellPostSetup())(Shell*) {
return cmds.howMany(); return shellPostSetup;
}
void setEofHandler(void (*funcptr)(int)){
struct sigaction *sa = new struct sigaction();
sa->sa_handler = funcptr;
sa->sa_flags = 0; // not SA_RESTART!;
sigaction(SIGINT, sa, NULL);
delete sa;
}
string* Shell::read_line()
{
string* buffer = new string();
setEofHandler(EofHandler);
getline(cin,*buffer); // get command
cin.clear(); // clear flags
if(undoingLine){
undoingLine=false;
throw IsUndoingLineException();
}
return buffer;
}
vector<string>* Shell::split_line(const string* line)
{
vector<string>* tokens = new vector<string>();
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;
}
bool Shell::undoingLine = false;
void Shell::addCmd(Command* cmd, bool isthread){
cmds.add(cmd, isthread);
}
size_t Shell::howManyCmds() const{
return cmds.howMany();
}
} }

View file

@ -21,55 +21,56 @@ using std::vector;
using std::istringstream; using std::istringstream;
using std::nullptr_t; using std::nullptr_t;
class Shell : public CommandExecutor namespace mshconsole {
{
class Commands class Shell : public CommandExecutor
{ {
Shell* parent; class Commands
vector<Command*> commands; //commands that work the same thread of the shell {
vector<Command*> threadCommands; //commands that work on a different thread Shell* parent;
vector<Command*> commands; //commands that work the same thread of the shell
vector<Command*> threadCommands; //commands that work on a different thread
public:
Commands(Shell*);
void add(Command*, bool isthread=false);
size_t howMany() const;
int launch(const vector<string>* args, bool launchThread=false);
};
static bool undoingLine;
Commands cmds;
string ps;
string name;
void (*shellSetup)(Shell *);
void (*shellPostSetup)(Shell *);
bool notLoop;
int launchCmd(vector<string>* args);
static void EofHandler(int);
string* read_line();
vector<string>* split_line(const string* line);
class IsUndoingLineException {};
class CommandNotFoundException {};
public: public:
Commands(Shell*); Shell(string n="msh", string ps="MSH$", void (*s)(Shell*)=0, void (*pss)(Shell*)=0);
void add(Command*, bool isthread=false); string getPs() const;
size_t howMany() const; void setPs(const string &value);
int launch(const vector<string>* args, bool launchThread=false); string getName() const;
void setName(const string &value);
void launch();
void setShellSetup(void (*)(Shell *));
void (*getShellSetup())(Shell*);
void setShellPostSetup(void (*)(Shell *));
void (*getShellPostSetup())(Shell*);
//for in-shell commands
void addCmd(Command *cmd, bool isThread=false);
size_t howManyCmds() const;
int executeCmd(vector<string>* args);
int executeCmd(const string& args);
}; };
static bool undoingLine; }
Commands cmds;
string ps;
string name;
void (*shellSetup)(Shell *);
void (*shellPostSetup)(Shell *);
bool notLoop;
int launchCmd(vector<string>* args);
static void EofHandler(int);
string* read_line();
vector<string>* split_line(const string* line);
class IsUndoingLineException {};
public:
Shell(string n="msh", string ps="MSH$", void (*s)(Shell*)=0, void (*pss)(Shell*)=0);
string getPs() const;
void setPs(const string &value);
string getName() const;
void setName(const string &value);
void launch();
void setShellSetup(void (*)(Shell *));
void (*getShellSetup())(Shell*);
void setShellPostSetup(void (*)(Shell *));
void (*getShellPostSetup())(Shell*);
//for in-shell commands
void addCmd(Command *cmd, bool isThread=false);
size_t howManyCmds() const;
int executeCmd(vector<string>* args);
int executeCmd(const string& args);
//excepsetions
class CommandNotFoundException{};
class ShellLaunchInSetupException{};
};
#endif // SHELL_H #endif // SHELL_H

View file

@ -1,9 +0,0 @@
# snippet for showing how the library works
project(msh-console-library-snippet)
cmake_minimum_required(VERSION 2.8)
SET(CMAKE_CXX_FLAGS "-std=c++11")
add_executable (../../build-msh-console/msh-console-test main.cpp cmds.cpp)
target_link_libraries (../../build-msh-console/msh-console-test LINK_PUBLIC msh-console)

View file

@ -1,28 +0,0 @@
/**
builtin commands
*/
#include "cmds.h"
using namespace std;
int Cmds::cdExecute(const vector<string>* args, CommandExecutor*){
if (args->operator[](1) == "\0") {
cerr << "expected argument to \"cd\"\n";
} else {
if (chdir(args->operator[](1).c_str()) != 0) {
cerr << "error";
}
}
return 1;
}
int Cmds::exitExecute(const vector<string>*, CommandExecutor*){
std::exit(EXIT_SUCCESS);
}
int Cmds::helpExecute(const vector<string>*, CommandExecutor*){
cout << " info" << endl;
return 1;
}

View file

@ -1,17 +0,0 @@
#ifndef CMDS_H
#define CMDS_H
#include "../msh-console-library/commandexecutor.h"
#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
using std::string;
using std::vector;
namespace Cmds {
int cdExecute(const vector<string>* args, CommandExecutor*);
int exitExecute(const vector<string>*, CommandExecutor*);
int helpExecute(const vector<string>*, CommandExecutor*);
}
#endif // CMDS_H

View file

@ -1,32 +0,0 @@
/**
Little snippet for library use.
*/
#include <cstdlib>
#include <iostream>
#include "../msh-console-library/shell.h"
#include "../msh-console-library/command.h"
#include "cmds.h"
using namespace std;
using namespace Cmds;
static void setup(Shell *);
int main(int argc, char **argv)
{
string c = "msh-console-test";
string ps = "[msh-console-test]:";
Shell mshConsoleTest(c, ps, &setup);
//add builtin commands
mshConsoleTest.addCmd(new Command("cd", &cdExecute));
mshConsoleTest.addCmd(new Command("exit", &exitExecute));
mshConsoleTest.addCmd(new Command("help", &helpExecute));
mshConsoleTest.launch();
return EXIT_SUCCESS;
}
void setup(Shell *s){
cout << "Now entering in test shell...\n" << endl;
s->executeCmd("stty -ctlecho");
}