JShell

来源:互联网 发布:编程金字塔图案 编辑:程序博客网 时间:2024/05/21 01:48

main.cpp

#include <iostream>#include "JShell.h"int main() {    std::cout << "Hello, JShell!" << std::endl;    JShell jShell;    jShell.execute();    return 0;}

JShell.h

//// Created by JieWei on 8/22/16.//#ifndef UNIXAPI_JSHELL_H#define UNIXAPI_JSHELL_H#include <string>#include <map>#include <vector>#include "cmds.h"using namespace std;class JShell {    const char* _promot = "JShell > ";    int handleCommands(string line);    int handleCommand(string command);    int handleCommand(vector<string> segs, string input, string& output1, string& output2);    int single_exec(vector<string> segs, string input, string& output1, string& output2);    std::map<string, cmd_type> buildin_cmds;    void log(string str);public:    JShell();    void execute();};#endif //UNIXAPI_JSHELL_H

JShell.cpp

//// Created by JieWei on 8/22/16.//#include <iostream>#include <vector>#include <sstream>#include <unistd.h>#include <sys/wait.h>#include <cstdio>#include <algorithm>#include <memory>#include <fstream>#include <sstream>#include "JShell.h"#include "cmds.h"using namespace std;string& ltrim(string& s){    auto p = s.find_first_not_of(" ");    if (p > 0){        s.erase(0, p);    }    return s;}vector<string> split(string& str){    vector<string> ret;    stringstream ss(str);    string buf;    while(ss >> buf){        ret.push_back(buf);    }    return ret;}vector<string> split(const string &s, char delim) {    vector<string> ret;    stringstream ss(s);    string item;    while (getline(ss, item, delim)) {        ret.push_back(item);    }    return ret;}string join(vector<string>& segs, string glue = " "){    stringstream ss;    for(auto i = 0; i < segs.size(); ++i){        if(i != 0)            ss << glue;        ss << segs[i];    }    return ss.str();}vector<string> split_cmd(string& str){    vector<string> ret;    auto s1 = ltrim(str);    if(s1.length() == 0){        return ret;    }    auto sp = s1.find_first_of(' ');    if (sp == string::npos){        ret.push_back(str);        ret.push_back("");    }else{        ret.push_back(str.substr(0, sp));        ret.push_back(str.substr(sp+1));    }    return ret;}void write_file(string file, string content){    ofstream myfile;    myfile.open (file);    myfile << content;    myfile.close();}string read_file(string file){    std::ifstream t(file);    std::string str((std::istreambuf_iterator<char>(t)),                    std::istreambuf_iterator<char>());    return str;}void JShell::execute() {    int st = 0;    while(st != 100) {        cout << _promot;        string line;        getline(cin, line);        st = handleCommands(line);    }}int JShell::handleCommand(string command) {    // handle command with redirect 2    auto segs = split(command);    string input_file, output1_file, output2_file;    auto input_iter = find(segs.begin(), segs.end(), "<");    if (input_iter != segs.end()){        input_file = *(input_iter+1);        segs.erase(input_iter, input_iter+2);        log(  "redirect input from " + input_file );    }    auto output2_iter = find(segs.begin(), segs.end(), "2>");    if (output2_iter != segs.end()){        output2_file = *(output2_iter+1);        segs.erase(output2_iter, output2_iter+2);        log( "redirect output2 to " + output2_file );    }    auto output1_iter = find(segs.begin(), segs.end(), ">");    if (output1_iter != segs.end()) {        output1_file = *(output1_iter + 1);        segs.erase(output1_iter, output1_iter + 2);        log( "redirect output1 to " + output1_file );    }    string input = "";    string output1 = "";    string output2 = "";    if (!input_file.empty()){        input = read_file(input_file);    }    auto cmd_ret = handleCommand(segs, input, output1, output2);    if (!output1_file.empty()){        write_file(output1_file, output1);    }else{        if (!output1.empty())            cout << output1 << endl;    }    if (!output2_file.empty()){        write_file(output2_file, output2);    }else{        if (!output2.empty())            cout << output2 << endl;    }    return cmd_ret;}JShell::JShell() {    // initialize buildin commands    buildin_cmds["cd"] = &cd;    buildin_cmds["echo"] = &echo;    buildin_cmds["cmd1"] = &cmd1;}int JShell::handleCommand(vector<string> segs, string input, string& output1, string& output2) {    // handle commmand with build in cmds    string command = join(segs);    auto argv_segs = split_cmd(command);    int process_ret = 0;    if(segs.size() == 0){        log("Empty command");        return 0;    }else{        string cmd = segs[0];        if (cmd == "exit") {            return 100;        }        if (buildin_cmds.find(cmd) != buildin_cmds.end()){            log(cmd + " is a built in command!");            process_ret = buildin_cmds[cmd](argv_segs[1].c_str(), output1);        }else{            process_ret = single_exec(segs, input, output1, output2);        }        if (process_ret != 0) {            stringstream ss;            ss << process_ret;            log(cmd + " return non-zero: " + ss.str());        }    }    return 0;}int JShell::single_exec(vector<string> segs, string input, string& output1, string& output2) {    int pipe_in[2];    int pipe_out1[2];    int pipe_out2[2];    pipe(pipe_in);    pipe(pipe_out1);    pipe(pipe_out2);    auto pid = fork();    if (pid == 0){        // child        char** argv = new char*[segs.size()+1];        for(int i = 0; i < segs.size(); ++i){            argv[i] = const_cast<char*>(segs[i].c_str());        }        argv[segs.size()] = NULL;        if(!input.empty()){            dup2(pipe_in[0], STDIN_FILENO);            close(pipe_in[1]);        }        close(pipe_out1[0]);        dup2(pipe_out1[1], STDOUT_FILENO);        close(pipe_out2[0]);        dup2(pipe_out2[1], STDERR_FILENO);        int ret = execvp(segs[0].c_str(), argv);        delete [] argv;        exit(ret);    }else{  // parent        char buf[10240];        // input        if(!input.empty()){            close(pipe_in[0]);            write(pipe_in[1], input.c_str(), input.length());            close(pipe_in[1]);        }        close(pipe_out1[1]);        auto len = read(pipe_out1[0], buf, sizeof(buf));        buf[len] = 0; output1 = buf;        close(pipe_out2[1]);        len = read(pipe_out2[0], buf, sizeof(buf));        buf[len] = 0; output2 = buf;        int child_ret;        wait(&child_ret);        return child_ret;    }}void JShell::log(string str) {    // JShell's output format    cout << "*[" << str << "]*" << endl;}int JShell::handleCommands(string line) {    // handles command with pipe    int ret = 0;    auto cmds = split(line, '|');    switch(cmds.size()){        case 1: {            ret = handleCommand(line);            break;        }        case 2: {            log("pipe command");            string inp, output1, output2;            auto cmd1 = split(cmds[0]);            handleCommand(cmd1, inp, output1, output2);            string cmd2_output1, cmd2_output2;            auto cmd2 = split(cmds[1]);            ret = handleCommand(cmd2, output1 + output2, cmd2_output1, cmd2_output2);            if (!cmd2_output1.empty())                cout << cmd2_output1 << endl;            if (!cmd2_output2.empty())                cout << cmd2_output2 << endl;            break;        }        default: {            log("Unsupport multi pipe!");        }    }    return ret;}

cmds.h

//// Created by JieWei on 8/22/16.//#ifndef UNIXAPI_CMDS_H#define UNIXAPI_CMDS_H#include <iostream>using namespace std;typedef int (*cmd_type)(const char*, string&);int echo(const char* argv, string& output);int cd(const char *argv, string& output);int cmd1(const char *argv, string& output);#endif //UNIXAPI_CMDS_H

cmds.cpp
//// Created by JieWei on 8/22/16.//// cmds.cpp contains commmands like binary in /usr/bin#include <iostream>#include <unistd.h>#include "cmds.h"int cd(const char *argv, string& output) {    int ret = chdir(argv);    output = string("I'm cd, i'm going to ") + argv;    return ret;}int echo(const char* argv, string& output) {    output = string(argv) + "\n";    return 0;}int cmd1(const char* argv, string& output) {    output = "cmd1... do nothing.\n";    return 0;}// add more built in commands here...

0 0
原创粉丝点击