编写shell时会出现一些错误(可能是指针)

时间:2016-10-31 14:16:55

标签: c++ linux shell unix

我的期望:它将存储在终端中输入的最后十个命令。当你按ctrl + c时,你可以看到它们。如果要退出,只需按ctrl + d。

所以我用queue来实现存储命令。但是在长度=读取(STDIN_FILENO,inputBuffer,MAX_LINE);'之后,队列中的所有元素都是最新的命令。(例如,COMMAND-> date queue:date; COMMAND-> cal queue: cal cal)

在阅读之前是正常的。但是当我用“fgets”(inputBuffer,MAX_LINE,stdin)替换它时,它并没有帮助;'。这样,我就不知道如何捕获' CTRL + d'因为没有对应的信号(如SIGINT和ctrl + c)所以我必须检查长度是否等于0。

如何解决这个问题?

#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <sys/wait.h>
#include <queue>
using namespace std;
#define BUFFER_SIZE 50
#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */


struct mes{
    char* _args[MAX_LINE/2+1];
    int len;
    int bg;
    int erno;

    mes(){
        len = 0;
        bg = false;
        memset(_args,0,sizeof(_args));
    }

    mes(char* new_args[],int _len,int _bg){
        len = _len;
        bg = _bg;

        for(int i = 0; i < len; ++i){
            _args[i] = new_args[i];
        }
        _args[len] = NULL;

    }

    void show(){
        if(erno==-1) cout<<"ERROR:";
        for(int i=0;i<len;i++) 
            cout<<_args[i]<<" ";
        if(bg) cout<<"&"<<endl;
        else cout<<endl;
    }

    ~mes(){
        memset(_args,0,sizeof(_args));
        // for(int i=0; i<len && args[i]; i++){
        //     delete args[i];
        //     args[i]=NULL;
        // }
        // delete[] args;
        // args=NULL;
    }
};

queue <mes*> rec, quetmp;
static int reclen = 0;
static int totlen = 0;

void readSplit(char inputBuffer[], char *args[], int * background){
    int length, /* # of characters in the command line */
        i,      /* loop index for accessing inputBuffer array */
        start,  /* index where beginning of next command parameter is */
        ct;     /* index of where to place the next parameter into args[] */
    ct = 0;

    if(!rec.empty()){
        cout<<"before read"<<endl;
        cout<<rec.front()->_args[0]<<endl;
        cout<<"size:"<<sizeof(rec.front()->_args[0])<<'\n';
        for(int k = 0; k < sizeof(rec.front()->_args[0]); ++k)
            cout<<'*'<<rec.front()->_args[0][k]<<endl;
        cout<<"end"<<endl;
    }

    /* read what the user enters on the command line */
    // char *tmp = fgets(inputBuffer,MAX_LINE,stdin);
    length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
    if(!rec.empty()){
        cout<<"after read"<<endl;
        cout<<rec.front()->_args[0]<<'\n';
        cout<<"size:"<<sizeof(rec.front()->_args[0])<<'\n';
        for(int k = 0; k < sizeof(rec.front()->_args[0]); ++k)
            cout<<'*'<<rec.front()->_args[0][k]<<endl;
        cout<<"end"<<endl;
    }

    start = -1;
    if (length == 0){
        write(STDOUT_FILENO,inputBuffer,strlen(inputBuffer));//write the last instruction
        exit(0);            /* ^d was entered, end of user command stream */
    }
    if (length < 0){
        perror("error reading the command");
        exit(-1);           /* terminate with error code of -1 */
    }

    /* examine every character in the inputBuffer */
    for (i=0;i<length;i++) { 
        switch (inputBuffer[i]){
        case ' ':
        case '\t' :               /* argument separators */
            if(start != -1){
                args[ct] = &inputBuffer[start];    /* set up pointer */
                ct++;
            }
            inputBuffer[i] = '\0'; /* add a null char; make a C string */
            start = -1;
            break;

        case '\n':                 /* should be the final char examined */
            if (start != -1){
                args[ct] = &inputBuffer[start];     
                ct++;
            }
                    inputBuffer[i] = '\0';
                    args[ct] = NULL; /* no more arguments to this command */
            break;

        default :             /* some other character */
            if (start == -1)
                start = i;
                if (inputBuffer[i] == '&'){
                    *background  = 1;
                    inputBuffer[i] = '\0';
                }
        } 
    }

    args[ct] = NULL; /* just in case the input line was > 80 */
    // mes* pmes = new mes(args, ct, *background);
}



/**
 * setup() reads in the next command line, separating it into distinct tokens
 * using whitespace as delimiters. setup() sets the args parameter as a 
 * null-terminated string.
 */
//args end with NULL
//only deal with splitted command
void setup(char inputBuffer[], char *args[],int *background)
{

    readSplit(inputBuffer, args, background);

    int len = 0;
    while(args[len]) ++len;
    mes* pmes = new mes(args, len, *background);

    int * p_errno=(int*)mmap(NULL,sizeof(int)*2,PROT_READ|PROT_WRITE,\
        MAP_SHARED|MAP_ANONYMOUS,-1,0);
    int * p_errno;
    int pid = fork();
    if(pid == 0){

        int erno = execvp(args[0], args);
        *p_errno = erno;

        _exit(0);
    }
    else{
        if(!(*background)){
            waitpid(pid, NULL, 0);
        }
    // }
    pmes->erno = 1;
    pmes->erno = *p_errno;
    if(reclen < 10){
        rec.push(pmes);
        ++reclen;
    }
    else{
        rec.pop();
        rec.push(pmes);
    }
    ++totlen;
} 


void handle_SIGINT(int sig){// ctrl+c
    int num = totlen - reclen, index = 0;
    mes* ls[10];
    cout<<endl;
    while(!rec.empty()){
        cout<<++num<<": ";
        rec.front()->show();
        quetmp.push(rec.front());
        ls[index++] = rec.front();
        rec.pop();
    }
    while(!quetmp.empty()){
        rec.push(quetmp.front());
        quetmp.pop();
    }
    cout<<"Exit record input \"q\", repeat command,\
input \"r\" or \"r x\"(x is the prefix of command)"<<endl;

    char buffer[MAX_LINE];
    char *arguments[MAX_LINE/2+1];
    int flag;

    int exeNum = index - 1;
    while(true){
        readSplit(buffer, arguments, &flag);
        int num_arg = 0;
        while(arguments[num_arg]) ++num_arg;
        if(num_arg == 0) continue;
        if(strcmp(arguments[0], "p") == 0) break;
        if(strcmp(arguments[0], "r") != 0){
            cout<<"No such command"<<endl;
            continue;
        }

        if(num_arg == 1){
        }
        else if(num_arg != 2 || strlen(arguments[1]) != 1){
            cout<<"invalid input"<<endl;
            continue;
        }
        else{
            for(; exeNum >= 0; --exeNum){
                if(ls[exeNum]->args[0][0] == arguments[1][0]){
                    break;
                }
            }
        }
        if(exeNum >= 0){
            ls[exeNum]->show();
            if(ls[exeNum]->erno == -1){
                cout<<"It is an error command"<<endl;
            }
            else{
                setup(buffer, ls[exeNum]->args, & (ls[exeNum]->bg));
            }
        }

    }

    cout<<"record has quitted"<<endl;

}

int main(void)
{
    char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
    int background;             /* equals 1 if a command is followed by '&' */
    char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */

    // signal(SIGINT,handle_SIGINT);
    while (1){            /* Program terminates normally inside setup */
        background = 0;
        printf("COMMAND->");
        fflush(stdout);
        // readSplit(inputBuffer, args, &background);
        setup(inputBuffer,args,&background);       /* get next command */
    }
}

0 个答案:

没有答案