我的期望:它将存储在终端中输入的最后十个命令。当你按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 */
}
}