JShell

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...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值