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:
parent
e96a300f8e
commit
854b218cb4
14 changed files with 309 additions and 387 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
||||||
|
# autosaves
|
||||||
|
*.autosave
|
||||||
|
|
||||||
#kate directory files
|
#kate directory files
|
||||||
*.directory
|
*.directory
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -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})
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
const string name;
|
||||||
static unsigned int numCom;
|
static unsigned int numCom;
|
||||||
int (*funcCommand)(const vector<string>*,CommandExecutor*);
|
int (*funcCommand)(const vector<string>*,CommandExecutor*);
|
||||||
void checkObj();
|
void checkObj();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Command(const string& n, int (*funcptr)(const vector<string>* args, CommandExecutor*));
|
Command(const string& n, int (*funcptr)(const vector<string>* args, CommandExecutor*));
|
||||||
Command(const Command&);
|
Command(const Command&);
|
||||||
~Command();
|
~Command();
|
||||||
string getName();
|
string getName();
|
||||||
int execute(const vector<string>*, CommandExecutor* ciao);
|
int execute(const vector<string>*, CommandExecutor* ciao);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
class CommandNameNotValidException{};
|
class CommandNameNotValidException{};
|
||||||
|
|
||||||
#endif // COMMAND_H
|
#endif // COMMAND_H
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "commandexecutor.h"
|
#include "commandexecutor.h"
|
||||||
|
namespace mshconsole {
|
||||||
CommandExecutor::CommandExecutor()
|
CommandExecutor::CommandExecutor() {}
|
||||||
{
|
void CommandExecutor::exit(){
|
||||||
|
throw CommandExecutor::ExitException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,18 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class CommandExecutor
|
namespace mshconsole{
|
||||||
{
|
class CommandExecutor
|
||||||
public:
|
{
|
||||||
|
protected:
|
||||||
|
class ExitException {};
|
||||||
|
public:
|
||||||
virtual int executeCmd(std::vector<std::string>* args) = 0;
|
virtual int executeCmd(std::vector<std::string>* 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();
|
||||||
CommandExecutor();
|
CommandExecutor();
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif // COMMANDEXECUTOR_H
|
#endif // COMMANDEXECUTOR_H
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
namespace mshconsole {
|
||||||
string Shell::getPs() const
|
string Shell::getPs() const
|
||||||
{
|
{
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::setPs(const string &value)
|
void Shell::setPs(const string &value)
|
||||||
{
|
{
|
||||||
ps = value;
|
ps = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
string Shell::getName() const
|
string Shell::getName() const
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::setName(const string &value)
|
void Shell::setName(const string &value)
|
||||||
{
|
{
|
||||||
name = value;
|
name = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shell::Shell( string n, string ps,void (*s)(Shell*), void (*pss)(Shell*)) : cmds(this)
|
Shell::Shell( string n, string ps,void (*s)(Shell*), void (*pss)(Shell*)) : cmds(this)
|
||||||
{
|
{
|
||||||
shellSetup = s;
|
shellSetup = s;
|
||||||
name = n;
|
name = n;
|
||||||
this->ps = ps;
|
this->ps = ps;
|
||||||
shellPostSetup = pss;
|
shellPostSetup = pss;
|
||||||
notLoop = false;
|
notLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shell::launch(){
|
||||||
|
|
||||||
void Shell::launch(){
|
|
||||||
//launch setup
|
//launch setup
|
||||||
if(notLoop) {
|
if(notLoop) {
|
||||||
throw ShellLaunchInSetupException();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(shellSetup!=0) {
|
if(shellSetup!=0) {
|
||||||
|
@ -40,10 +40,12 @@ void Shell::launch(){
|
||||||
(*shellSetup)(this);
|
(*shellSetup)(this);
|
||||||
notLoop = false;
|
notLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//launch loop
|
//launch loop
|
||||||
string* line;
|
string* line;
|
||||||
vector<string>* args;
|
vector<string>* args;
|
||||||
int status;
|
int status;
|
||||||
|
try{
|
||||||
do {
|
do {
|
||||||
bool readSuccess;
|
bool readSuccess;
|
||||||
do{
|
do{
|
||||||
|
@ -60,14 +62,18 @@ void Shell::launch(){
|
||||||
args = split_line(line);
|
args = split_line(line);
|
||||||
status = executeCmd(args);
|
status = executeCmd(args);
|
||||||
delete args;
|
delete args;
|
||||||
} while (status);
|
} while (1);
|
||||||
|
} catch(CommandExecutor::ExitException) {}
|
||||||
|
|
||||||
|
//launch postSetup
|
||||||
if(shellPostSetup!=0) {
|
if(shellPostSetup!=0) {
|
||||||
shellPostSetup(this);
|
shellPostSetup(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Shell::launchCmd(vector<string>* args)
|
int Shell::launchCmd(vector<string>* args)
|
||||||
{
|
{
|
||||||
|
using std::exit;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
@ -107,10 +113,10 @@ int Shell::launchCmd(vector<string>* args)
|
||||||
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Shell::executeCmd(vector<string>* args)
|
int Shell::executeCmd(vector<string>* args)
|
||||||
{
|
{
|
||||||
if (args->operator [](0) == "\0") {
|
if (args->operator [](0) == "\0") {
|
||||||
// An empty command was entered.
|
// An empty command was entered.
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -123,43 +129,43 @@ int Shell::executeCmd(vector<string>* args)
|
||||||
ret = launchCmd(args);
|
ret = launchCmd(args);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int Shell::executeCmd(const std::string &args){
|
inline int Shell::executeCmd(const std::string &args){
|
||||||
return executeCmd(split_line(&args));
|
return executeCmd(split_line(&args));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::EofHandler(int){
|
void Shell::EofHandler(int){
|
||||||
undoingLine = true;
|
undoingLine = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::setShellSetup(void (*s)(Shell *)){
|
void Shell::setShellSetup(void (*s)(Shell *)){
|
||||||
shellSetup=s;
|
shellSetup=s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*Shell::getShellSetup())(Shell*) {
|
void (*Shell::getShellSetup())(Shell*) {
|
||||||
return shellSetup;
|
return shellSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shell::setShellPostSetup(void (*s)(Shell *)){
|
void Shell::setShellPostSetup(void (*s)(Shell *)){
|
||||||
shellPostSetup=s;
|
shellPostSetup=s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*Shell::getShellPostSetup())(Shell*) {
|
void (*Shell::getShellPostSetup())(Shell*) {
|
||||||
return shellPostSetup;
|
return shellPostSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setEofHandler(void (*funcptr)(int)){
|
void setEofHandler(void (*funcptr)(int)){
|
||||||
struct sigaction *sa = new struct sigaction();
|
struct sigaction *sa = new struct sigaction();
|
||||||
sa->sa_handler = funcptr;
|
sa->sa_handler = funcptr;
|
||||||
sa->sa_flags = 0; // not SA_RESTART!;
|
sa->sa_flags = 0; // not SA_RESTART!;
|
||||||
sigaction(SIGINT, sa, NULL);
|
sigaction(SIGINT, sa, NULL);
|
||||||
delete sa;
|
delete sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
string* Shell::read_line()
|
string* Shell::read_line()
|
||||||
{
|
{
|
||||||
string* buffer = new string();
|
string* buffer = new string();
|
||||||
setEofHandler(EofHandler);
|
setEofHandler(EofHandler);
|
||||||
getline(cin,*buffer); // get command
|
getline(cin,*buffer); // get command
|
||||||
|
@ -170,10 +176,10 @@ string* Shell::read_line()
|
||||||
throw IsUndoingLineException();
|
throw IsUndoingLineException();
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string>* Shell::split_line(const string* line)
|
vector<string>* Shell::split_line(const string* line)
|
||||||
{
|
{
|
||||||
vector<string>* tokens = new vector<string>();
|
vector<string>* tokens = new vector<string>();
|
||||||
string ln = *line;
|
string ln = *line;
|
||||||
istringstream is(ln);
|
istringstream is(ln);
|
||||||
|
@ -183,14 +189,15 @@ vector<string>* Shell::split_line(const string* line)
|
||||||
}
|
}
|
||||||
tokens->push_back("\0");
|
tokens->push_back("\0");
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shell::undoingLine = false;
|
bool Shell::undoingLine = false;
|
||||||
|
|
||||||
void Shell::addCmd(Command* cmd, bool isthread){
|
void Shell::addCmd(Command* cmd, bool isthread){
|
||||||
cmds.add(cmd, isthread);
|
cmds.add(cmd, isthread);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Shell::howManyCmds() const{
|
size_t Shell::howManyCmds() const{
|
||||||
return cmds.howMany();
|
return cmds.howMany();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,10 @@ using std::vector;
|
||||||
using std::istringstream;
|
using std::istringstream;
|
||||||
using std::nullptr_t;
|
using std::nullptr_t;
|
||||||
|
|
||||||
class Shell : public CommandExecutor
|
namespace mshconsole {
|
||||||
{
|
|
||||||
|
class Shell : public CommandExecutor
|
||||||
|
{
|
||||||
class Commands
|
class Commands
|
||||||
{
|
{
|
||||||
Shell* parent;
|
Shell* parent;
|
||||||
|
@ -49,8 +51,9 @@ class Shell : public CommandExecutor
|
||||||
vector<string>* split_line(const string* line);
|
vector<string>* split_line(const string* line);
|
||||||
|
|
||||||
class IsUndoingLineException {};
|
class IsUndoingLineException {};
|
||||||
|
class CommandNotFoundException {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Shell(string n="msh", string ps="MSH$", void (*s)(Shell*)=0, void (*pss)(Shell*)=0);
|
Shell(string n="msh", string ps="MSH$", void (*s)(Shell*)=0, void (*pss)(Shell*)=0);
|
||||||
string getPs() const;
|
string getPs() const;
|
||||||
void setPs(const string &value);
|
void setPs(const string &value);
|
||||||
|
@ -61,15 +64,13 @@ public:
|
||||||
void (*getShellSetup())(Shell*);
|
void (*getShellSetup())(Shell*);
|
||||||
void setShellPostSetup(void (*)(Shell *));
|
void setShellPostSetup(void (*)(Shell *));
|
||||||
void (*getShellPostSetup())(Shell*);
|
void (*getShellPostSetup())(Shell*);
|
||||||
|
|
||||||
//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(vector<string>* args);
|
||||||
int executeCmd(const string& args);
|
int executeCmd(const string& args);
|
||||||
|
};
|
||||||
//excepsetions
|
}
|
||||||
class CommandNotFoundException{};
|
|
||||||
class ShellLaunchInSetupException{};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SHELL_H
|
#endif // SHELL_H
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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");
|
|
||||||
}
|
|
Loading…
Reference in a new issue