Renamed some functions and variables in SIGINT handling. README updated. Removed "using" directives in the headers. Input, output and error streams are now fields
of Shell. stringToArgcArgv has its own namespace.
This commit is contained in:
parent
f6c3135c27
commit
5d68248b18
15 changed files with 646 additions and 315 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,7 +2,7 @@
|
|||
build-*
|
||||
|
||||
#internal test
|
||||
msh-console-library/main.cpp
|
||||
#msh-console-library/main.cpp
|
||||
|
||||
# Autosaves
|
||||
*.autosave
|
||||
|
|
17
README.md
17
README.md
|
@ -1,8 +1,17 @@
|
|||
# msh-console
|
||||
Library that provides a bash-like interface for CLI C++ programs
|
||||
# Msh-console
|
||||
* included flag handling implemented with popt.h;
|
||||
Library that provides a bash-like command line for C++ programs. Features included:
|
||||
* creation of personalized commands in the same thread of the shell or in other threads;
|
||||
* basic shell functionalities, such as execution of other programs in the system. This is implemented with execvp().
|
||||
What is not actually included:
|
||||
* advanced shell features, like:
|
||||
* piping,
|
||||
* redirection,
|
||||
* scripting,
|
||||
* command history.
|
||||
### 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" tutorial by Stephen Brennan (http://brennan.io/2015/01/16/write-a-shell-in-c/).
|
||||
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
|
||||
### Compiling
|
||||
The library can be compiled as shared library with the CMakeLists.txt file already in msh-console-library/.
|
||||
|
|
|
@ -1,22 +1,38 @@
|
|||
# msh-console dynamic library by praticamentetilde (Claudio Maggioni)
|
||||
# licensed with "The Unlicense"
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016 Claudio Maggioni
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
project(msh-console-library)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lpopt")
|
||||
FILE(GLOB sources *.cpp)
|
||||
FILE(GLOB headers *.h)
|
||||
list(APPEND SRC_LIST "command.cpp" "commandexecutor.h" "commands.cpp" "datas.cpp" "shell.cpp" "stringtoargcargv.cpp"
|
||||
"commandexecutor.cpp" "command.h" "data.cpp" "main.cpp" "shell.h" "stringtoargcargv.h")
|
||||
|
||||
set(lib OFF)
|
||||
set(lib ON) #off=debug demo with main.cpp, on=library
|
||||
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)
|
||||
MESSAGE(STATUS "Building .so.1")
|
||||
list(REMOVE_ITEM SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) #remove demo file
|
||||
add_library (mshconsole SHARED ${SRC_LIST})
|
||||
else(${lib})
|
||||
MESSAGE( STATUS "Building exec (debug only)")
|
||||
add_executable(${PROJECT_NAME} ${sources} ${headers})
|
||||
MESSAGE(STATUS "Building exec (debug only)")
|
||||
add_executable(${PROJECT_NAME} ${SRC_LIST})
|
||||
endif(${lib})
|
||||
|
|
|
@ -1,7 +1,31 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shell.h"
|
||||
namespace mshconsole {
|
||||
|
||||
Command::Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector<const char*> argv)) :
|
||||
Command::Command(const std::string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const std::vector<const char*> argv)) :
|
||||
name(n), funcCommand(funcptr), optionNum(0){
|
||||
checkObj();
|
||||
}
|
||||
|
@ -16,7 +40,7 @@ namespace mshconsole {
|
|||
optionNum++;
|
||||
}
|
||||
|
||||
int Command::execute(const struct Params& p, CommandExecutor* c){
|
||||
int Command::execute(const struct Params& p, CommandExecutor* c, std::ostream& errorStream){
|
||||
if(p.argc<=0) return -1;
|
||||
|
||||
// options a, b, c take integer arguments
|
||||
|
@ -46,32 +70,32 @@ namespace mshconsole {
|
|||
// poptGetNextOpt returns -1 when the final argument has been parsed
|
||||
// otherwise an error occured
|
||||
if (val != -1) {
|
||||
cerr << name << ": ";
|
||||
errorStream << name << ": ";
|
||||
switch(val) {
|
||||
case POPT_ERROR_NOARG:
|
||||
cerr << "argument missing for an option\n";
|
||||
errorStream << "argument missing for an option\n";
|
||||
return 1;
|
||||
case POPT_ERROR_BADOPT:
|
||||
cerr << "option not found\n";
|
||||
errorStream << "option not found\n";
|
||||
return 1;
|
||||
case POPT_ERROR_BADNUMBER:
|
||||
case POPT_ERROR_OVERFLOW:
|
||||
cerr << "option could not be converted to number\n";
|
||||
errorStream << "option could not be converted to number\n";
|
||||
return 1;
|
||||
default:
|
||||
cerr << "unknown error in option processing\n";
|
||||
errorStream << "unknown error in option processing\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
vector<const char*> nonOptionArgs;
|
||||
std::vector<const char*> nonOptionArgs;
|
||||
while (poptPeekArg(pc) != NULL)
|
||||
nonOptionArgs.push_back(const_cast<const char*>(poptGetArg(pc)));
|
||||
|
||||
return (*funcCommand)(c,datas,nonOptionArgs);
|
||||
}
|
||||
|
||||
const string& Command::getName(){
|
||||
const std::string& Command::getName(){
|
||||
return this->name;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,32 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef COMMAND_H
|
||||
#define COMMAND_H
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
extern "C"{
|
||||
|
@ -9,15 +34,12 @@ extern "C"{
|
|||
}
|
||||
#include "commandexecutor.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace mshconsole{
|
||||
class Command
|
||||
{
|
||||
const string name;
|
||||
const std::string name;
|
||||
void checkObj();
|
||||
vector<poptOption> opts;
|
||||
std::vector<poptOption> opts;
|
||||
static const struct poptOption POPT_TERMINATOR;
|
||||
size_t optionNum;
|
||||
|
||||
|
@ -55,26 +77,26 @@ namespace mshconsole{
|
|||
double getDouble() const;
|
||||
};
|
||||
|
||||
class Datas : public vector<Data*>{
|
||||
class Datas : public std::vector<Data*>{
|
||||
public:
|
||||
Data* getOptData(const string& optionName) const;
|
||||
Data* getOptData(const std::string& optionName) const;
|
||||
Data* getOptData(char opt) const;
|
||||
Data* operator[](const string& opt) const;
|
||||
Data* operator[](const std::string& opt) const;
|
||||
};
|
||||
|
||||
class DuplicatedOptionException{};
|
||||
class CommandNameNotValidException{};
|
||||
class InvalidOptionException{};
|
||||
|
||||
Command(const string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const vector<const char*> argv));
|
||||
Command(const std::string& n, int (*funcptr)(CommandExecutor* whoExecuted,const Datas& data, const std::vector<const char*> argv));
|
||||
Command(const Command&);
|
||||
~Command();
|
||||
const string& getName();
|
||||
int execute(const struct Params&, CommandExecutor*);
|
||||
const std::string& getName();
|
||||
int execute(const struct Params&, CommandExecutor*,std::ostream& errorStream=std::cerr);
|
||||
void addOption(const poptOption& option);
|
||||
|
||||
private:
|
||||
int (*funcCommand)(CommandExecutor* whoExecuted,const Datas& data, const vector<const char*> argv);
|
||||
int (*funcCommand)(CommandExecutor* whoExecuted,const Datas& data, const std::vector<const char*> argv);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "commandexecutor.h"
|
||||
namespace mshconsole {
|
||||
CommandExecutor::CommandExecutor() {}
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef COMMANDEXECUTOR_H
|
||||
#define COMMANDEXECUTOR_H
|
||||
#pragma once
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shell.h"
|
||||
namespace mshconsole {
|
||||
Shell::Commands::Commands(Shell* s) : commands(), threadCommands()
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "command.h"
|
||||
|
||||
namespace mshconsole{
|
||||
|
|
|
@ -1,7 +1,31 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "command.h"
|
||||
|
||||
namespace mshconsole {
|
||||
Command::Data* Command::Datas::getOptData(const string& opt) const{
|
||||
Command::Data* Command::Datas::getOptData(const std::string& opt) const{
|
||||
for(size_t i=0; i<this->size(); i++){
|
||||
if(opt == this->at(i)->of->longName) return this->at(i);
|
||||
}
|
||||
|
@ -11,7 +35,7 @@ namespace mshconsole {
|
|||
if(opt == this->at(i)->of->shortName) return this->at(i);
|
||||
}
|
||||
}
|
||||
Command::Data* Command::Datas::operator [](const string& opt) const{
|
||||
Command::Data* Command::Datas::operator [](const std::string& opt) const{
|
||||
if(opt.length()>2) return getOptData(opt);
|
||||
if(opt.length()==1) return getOptData(opt[0]);
|
||||
else return nullptr;
|
||||
|
|
75
msh-console-library/main.cpp
Normal file
75
msh-console-library/main.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include "../msh-console-library/shell.h"
|
||||
#include "../msh-console-library/command.h"
|
||||
using namespace std;
|
||||
using namespace mshconsole;
|
||||
|
||||
static void setup(Shell *);
|
||||
|
||||
int cdExecute(CommandExecutor* whoExecuted,const Command::Datas& data, const vector<const char*> argv){
|
||||
if (argv.size() == 0) {
|
||||
cerr << "expected argument to \"cd\"\n";
|
||||
} else {
|
||||
int ret;
|
||||
if (strcmp("~",argv[0])==0) {
|
||||
ret = chdir(getenv("HOME"));
|
||||
}
|
||||
else {
|
||||
ret = chdir(argv[0]);
|
||||
}
|
||||
if (ret != 0) {
|
||||
cerr << "cd: error executing the command\n";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exitExecute(CommandExecutor* whoExecuted,const Command::Datas& data, const vector<const char*> argv){
|
||||
whoExecuted->exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int helpExecute(CommandExecutor* whoExecuted,const Command::Datas& data, const vector<const char*> argv){
|
||||
cout << data.getOptData('p')->getString() << "\n";
|
||||
if(data.getOptData('h')->getInt()){
|
||||
cout << "These are the further details." << endl;
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(data.getOptData('p')->getString(),"prova")==0){
|
||||
cout << "prova\n";
|
||||
return 0;
|
||||
}
|
||||
cout << "Snippet console generated with msh-console library.\nUse option -h for further details." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Little snippet for library use.
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
string c = "msh-console-test";
|
||||
string ps = "[msh-console-test]:";
|
||||
Shell mshConsoleTest(c, ps, cin,cout,cerr, &setup);
|
||||
Command* help = new Command("help", &helpExecute);
|
||||
struct poptOption h = {"help",'h',POPT_ARG_NONE,NULL,1000,"advance","advaced options"};
|
||||
struct poptOption p = {"prova",'p',POPT_ARG_STRING,NULL,1000,"cose","cosecose"};
|
||||
help->addOption(h);
|
||||
help->addOption(p);
|
||||
|
||||
//add builtin commands
|
||||
mshConsoleTest.addCmd(help);
|
||||
mshConsoleTest.addCmd(new Command("exit", &exitExecute));
|
||||
mshConsoleTest.addCmd(new Command("cd", &cdExecute));
|
||||
mshConsoleTest.launch();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void setup(Shell *s){
|
||||
cout << "Now entering in test shell...\n" << endl;
|
||||
//s->executeCmd("stty -ctlecho");
|
||||
}
|
|
@ -1,81 +1,109 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shell.h"
|
||||
namespace mshconsole {
|
||||
string Shell::getPs() const
|
||||
{
|
||||
const std::string& Shell::getPs() const{
|
||||
return ps;
|
||||
}
|
||||
|
||||
void Shell::setPs(const string &value)
|
||||
{
|
||||
void Shell::setPs(const std::string &value){
|
||||
ps = value;
|
||||
}
|
||||
|
||||
string Shell::getName() const
|
||||
{
|
||||
const std::string& Shell::getName() const{
|
||||
return name;
|
||||
}
|
||||
|
||||
void Shell::setName(const string &value)
|
||||
{
|
||||
void Shell::setName(const std::string &value){
|
||||
name = value;
|
||||
}
|
||||
|
||||
Shell::Shell( string n, string ps,void (*s)(Shell*), void (*pss)(Shell*)) : cmds(this)
|
||||
{
|
||||
Shell::Shell(std::string nam, std::string ps, std::istream &i, std::ostream &o, std::ostream &e,
|
||||
void (*s)(Shell*), void (*pss)(Shell*)) : cmds(this), inputStream(i),
|
||||
outputStream(o), errorStream(e){
|
||||
shellSetup = s;
|
||||
name = n;
|
||||
name = nam;
|
||||
this->ps = ps;
|
||||
shellPostSetup = pss;
|
||||
notLoop = false;
|
||||
}
|
||||
|
||||
int Shell::launch(){
|
||||
//Forbid launching shell if it is already launched in other threads.
|
||||
static bool notLoop=false;
|
||||
if(notLoop) return -1;
|
||||
notLoop = true;
|
||||
|
||||
//launch setup
|
||||
if(notLoop) {
|
||||
return -1;
|
||||
}
|
||||
if(shellSetup!=0) {
|
||||
notLoop = true;
|
||||
(*shellSetup)(this);
|
||||
notLoop = false;
|
||||
}
|
||||
//Launch the shell setup.
|
||||
if(shellSetup!=0) (*shellSetup)(this);
|
||||
|
||||
//launch loop
|
||||
string* line;
|
||||
struct Params p;
|
||||
//Run the shell loop.
|
||||
int exitCode;
|
||||
|
||||
try{
|
||||
do {
|
||||
bool readSuccess;
|
||||
do{
|
||||
cout << ps << " ";
|
||||
std::string* line=nullptr;
|
||||
struct Params p;
|
||||
|
||||
while(1){
|
||||
delete line;
|
||||
outputStream << ps << " "; //Print the prompt.
|
||||
|
||||
//Try reading the line. if SIGINT is caught, print another time the prompt and retry.
|
||||
try{
|
||||
line = read_line();
|
||||
readSuccess = true;
|
||||
line = readLine();
|
||||
}
|
||||
catch (IsUndoingLineException){
|
||||
cout << "\n";
|
||||
readSuccess = false;
|
||||
outputStream << "\n";
|
||||
continue;
|
||||
}
|
||||
}while(!readSuccess);
|
||||
p = split_line(line);
|
||||
executeCmd(p);
|
||||
} while (1);
|
||||
|
||||
//Try line conversion from string to argc and argv. stringToArgcArgv() throws a std::runtime_error
|
||||
//exception if the string has unproper quotes.
|
||||
try{
|
||||
p = splitLine(line);
|
||||
}
|
||||
catch(std::runtime_error e){
|
||||
errorStream << name << ": error in line parsing\n";
|
||||
errorStream << e.what() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
//Execute the command.
|
||||
executeCmd(p);
|
||||
};
|
||||
} catch(CommandExecutor::ExitException c) {
|
||||
exitCode=c.getCode();
|
||||
exitCode=c.getCode();
|
||||
}
|
||||
|
||||
//launch postSetup
|
||||
if(shellPostSetup!=0) {
|
||||
shellPostSetup(this);
|
||||
}
|
||||
//Launch postSetup().
|
||||
if(shellPostSetup!=0) shellPostSetup(this);
|
||||
|
||||
notLoop = false;
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
int Shell::launchCmd(const struct Params& p)
|
||||
{
|
||||
using std::exit;
|
||||
int Shell::launchCmd(const struct Params& p){
|
||||
int status;
|
||||
|
||||
pid_t pid = fork();
|
||||
|
@ -84,21 +112,23 @@ namespace mshconsole {
|
|||
|
||||
//execute threadCommand
|
||||
int a;
|
||||
|
||||
try {
|
||||
a=cmds.launch(p, true);
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
catch (CommandNotFoundException){
|
||||
//execute bash command or program
|
||||
if((a=execvp(p.argv[0], p.argv)) == -1) {
|
||||
cerr << name <<": command " << p.argv[0] << " not found\n";
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
catch (CommandNotFoundException){}
|
||||
|
||||
//execute bash command or program
|
||||
if((a=execvp(p.argv[0], p.argv)) == -1) {
|
||||
outputStream << name << ": execution failed. Errno is set to: "<<strerror(errno)<<"\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
else std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (pid < 0) {
|
||||
// Error forking
|
||||
cerr << name <<": error forking the process\n";
|
||||
errorStream << name <<": error in process forking.\n";
|
||||
}
|
||||
else {
|
||||
// Parent process
|
||||
|
@ -110,34 +140,32 @@ namespace mshconsole {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int Shell::executeCmd(const struct Params& p)
|
||||
{
|
||||
if (!p.argc) { //empty line
|
||||
return 1;
|
||||
}
|
||||
int ret;
|
||||
int Shell::executeCmd(const struct Params& p){
|
||||
if (!p.argc) return 1; //Return if the line is empty.
|
||||
|
||||
try {
|
||||
ret = cmds.launch(p, false);
|
||||
//Search in non-thread commands.
|
||||
return cmds.launch(p, false);
|
||||
}
|
||||
catch(CommandNotFoundException) {
|
||||
ret = launchCmd(p);
|
||||
}
|
||||
return ret;
|
||||
catch(CommandNotFoundException) {}
|
||||
|
||||
//Execute the threadCommand or the executable.
|
||||
return launchCmd(p);
|
||||
}
|
||||
|
||||
inline int Shell::executeCmd(const std::string &args){
|
||||
return executeCmd(split_line(&args));
|
||||
return executeCmd(splitLine(&args));
|
||||
}
|
||||
|
||||
void Shell::EofHandler(int){
|
||||
undoingLine = true;
|
||||
void Shell::SIGINTHandler(int,siginfo_t*, void *){
|
||||
SIGINTRaised = true;
|
||||
}
|
||||
|
||||
void Shell::setShellSetup(void (*s)(Shell *)){
|
||||
shellSetup=s;
|
||||
}
|
||||
|
||||
void (*Shell::getShellSetup())(Shell*) {
|
||||
void (*Shell::getShellSetup())(Shell*) const{
|
||||
return shellSetup;
|
||||
}
|
||||
|
||||
|
@ -145,40 +173,46 @@ namespace mshconsole {
|
|||
shellPostSetup=s;
|
||||
}
|
||||
|
||||
void (*Shell::getShellPostSetup())(Shell*) {
|
||||
void (*Shell::getShellPostSetup())(Shell*) const{
|
||||
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;
|
||||
struct sigaction* setHandler(unsigned signal, void (*funcptr)(int, siginfo_t*, void*)){
|
||||
struct sigaction* before = new struct sigaction();
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = funcptr;
|
||||
sa.sa_flags = 0;
|
||||
sigaction(signal, &sa, before);
|
||||
}
|
||||
|
||||
string* Shell::read_line()
|
||||
{
|
||||
string* buffer = new string();
|
||||
setEofHandler(EofHandler);
|
||||
getline(cin,*buffer); // get command
|
||||
cin.clear(); // clear flags
|
||||
void restoreHandler(unsigned signal, struct sigaction* before){
|
||||
sigaction(signal, before, NULL);
|
||||
delete before;
|
||||
}
|
||||
|
||||
if(undoingLine){
|
||||
undoingLine=false;
|
||||
std::string* Shell::readLine(){
|
||||
std::string* buffer = new std::string();
|
||||
struct sigaction* beforeSIGINT = setHandler(SIGINT,SIGINTHandler);
|
||||
getline(inputStream,*buffer); //Get line of input TODO: handle directional keys
|
||||
inputStream.clear(); //Clear flags. This is needed for the detection of SIGINT
|
||||
|
||||
if(SIGINTRaised){
|
||||
SIGINTRaised=false;
|
||||
throw IsUndoingLineException();
|
||||
}
|
||||
|
||||
restoreHandler(SIGINT, beforeSIGINT);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct Params Shell::split_line(const string* line){
|
||||
struct Params Shell::splitLine(const std::string* line){
|
||||
struct Params p;
|
||||
stringToArgcArgv(*line, &(p.argc), &(p.argv));
|
||||
return p;
|
||||
}
|
||||
|
||||
bool Shell::undoingLine = false;
|
||||
bool Shell::SIGINTRaised = false;
|
||||
|
||||
void Shell::addCmd(Command* cmd, bool isthread){
|
||||
cmds.add(cmd, isthread);
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
/**
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Claudio Maggioni
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SHELL_H
|
||||
#define SHELL_H
|
||||
#pragma once
|
||||
|
@ -7,20 +31,14 @@
|
|||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <cstddef>
|
||||
#include <csignal>
|
||||
#include <cerrno>
|
||||
#include "command.h"
|
||||
#include <wordexp.h>
|
||||
#include "commandexecutor.h"
|
||||
#include "stringtoargcargv.h"
|
||||
using std::string;
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::istringstream;
|
||||
using namespace StringToArgcArgv;
|
||||
|
||||
namespace mshconsole {
|
||||
|
||||
|
@ -29,8 +47,8 @@ namespace mshconsole {
|
|||
class Commands
|
||||
{
|
||||
Shell* parent;
|
||||
vector<Command*> commands; //commands that work the same thread of the shell
|
||||
vector<Command*> threadCommands; //commands that work on a different thread
|
||||
std::vector<Command*> commands; //commands that work the same thread of the shell
|
||||
std::vector<Command*> threadCommands; //commands that work on a different thread
|
||||
|
||||
public:
|
||||
Commands(Shell*);
|
||||
|
@ -39,40 +57,47 @@ namespace mshconsole {
|
|||
int launch(const struct Params& args, bool launchThread=false);
|
||||
};
|
||||
|
||||
static bool undoingLine;
|
||||
static bool SIGINTRaised;
|
||||
Commands cmds;
|
||||
string ps;
|
||||
string name;
|
||||
std::string ps;
|
||||
std::string name;
|
||||
std::ostream& errorStream;
|
||||
std::ostream& outputStream;
|
||||
std::istream& inputStream;
|
||||
void (*shellSetup)(Shell *);
|
||||
void (*shellPostSetup)(Shell *);
|
||||
bool notLoop;
|
||||
|
||||
int launchCmd(const struct Params& args);
|
||||
static void EofHandler(int);
|
||||
string* read_line();
|
||||
struct Params split_line(const string* line);
|
||||
static void SIGINTHandler(int,siginfo_t *info, void *);
|
||||
std::string* readLine();
|
||||
struct Params splitLine(const std::string* line);
|
||||
|
||||
class IsUndoingLineException {};
|
||||
class CommandNotFoundException {};
|
||||
|
||||
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);
|
||||
Shell(std::string n, std::string ps, std::istream& inputStream, std::ostream& outputStream,
|
||||
std::ostream& errorStream, void (*s)(Shell*)=0, void (*pss)(Shell*)=0);
|
||||
const std::string& getPs() const;
|
||||
void setPs(const std::string &value);
|
||||
const std::string& getName() const;
|
||||
void setName(const std::string &value);
|
||||
int launch();
|
||||
void setShellSetup(void (*)(Shell *));
|
||||
void (*getShellSetup())(Shell*);
|
||||
void (*getShellSetup())(Shell*) const;
|
||||
void setShellPostSetup(void (*)(Shell *));
|
||||
void (*getShellPostSetup())(Shell*);
|
||||
void (*getShellPostSetup())(Shell*) const;
|
||||
|
||||
//for in-shell commands
|
||||
void addCmd(Command *cmd, bool isThread=false);
|
||||
size_t howManyCmds() const;
|
||||
|
||||
int executeCmd(const struct Params& args);
|
||||
int executeCmd(const string& args);
|
||||
int executeCmd(const std::string& args);
|
||||
size_t howManyCmds() const;
|
||||
};
|
||||
|
||||
extern struct sigaction* setHandler(unsigned signal, void (*funcptr)(int, siginfo_t*, void*));
|
||||
extern void restoreHandler(unsigned signal, struct sigaction* before);
|
||||
}
|
||||
|
||||
#endif // SHELL_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* stringtoargcargv.cpp -- Parsing a string to std::vector<string>
|
||||
/** stringtoargcargv.cpp -- Parsing a string to std::vector<string>
|
||||
|
||||
Copyright (C) 2011 Bernhard Eder
|
||||
|
||||
|
@ -22,171 +22,176 @@
|
|||
|
||||
*/
|
||||
|
||||
///The code is modified for the null-termination of argv
|
||||
|
||||
#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);
|
||||
namespace StringToArgcArgv{
|
||||
/*
|
||||
* 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*));
|
||||
*argv = (char**)std::malloc((args.size()+1) * 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;
|
||||
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());
|
||||
}
|
||||
(*argv)[i]=NULL;
|
||||
|
||||
*argc = args.size();
|
||||
}
|
||||
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
|
||||
|
||||
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
|
||||
{
|
||||
#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
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
switch(currentState) {
|
||||
case InArg:
|
||||
case InArgQuote:
|
||||
currentArg << c;
|
||||
break;
|
||||
|
||||
case OutOfArg:
|
||||
currentArg.str(std::string());
|
||||
currentArg << c;
|
||||
currentState = InArg;
|
||||
break;
|
||||
}
|
||||
bool _isQuote(char c)
|
||||
{
|
||||
if(c == '\"')
|
||||
return true;
|
||||
else if(c == '\'')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentState == InArg)
|
||||
oargs.push_back(currentArg.str());
|
||||
else if(currentState == InArgQuote)
|
||||
throw(std::runtime_error("Starting quote has no ending quote."));
|
||||
bool _isEscape(char c)
|
||||
{
|
||||
if(c == '\\')
|
||||
return true;
|
||||
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _isWhitespace(char c)
|
||||
{
|
||||
if(c == ' ')
|
||||
return true;
|
||||
else if(c == '\t')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
#ifndef STRINGTOARGCARGV_H
|
||||
#define STRINGTOARGCARGV_H
|
||||
#pragma once
|
||||
|
||||
/* stringtoargcargv.cpp -- Parsing a string to std::vector<string>
|
||||
/** stringtoargcargv.cpp -- Parsing a string to std::vector<string>
|
||||
|
||||
Copyright (C) 2011 Bernhard Eder
|
||||
|
||||
|
@ -26,6 +22,10 @@
|
|||
|
||||
*/
|
||||
|
||||
#ifndef STRINGTOARGCARGV_H
|
||||
#define STRINGTOARGCARGV_H
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
@ -35,11 +35,12 @@
|
|||
#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);
|
||||
|
||||
namespace StringToArgcArgv{
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue