2

我正在为一个简单的 c shell 编写代码。它存储最后 10 个命令的历史记录。如果“r”作为命令输入,那么它应该运行历史记录中最近的命令。此外,如果输入了“r x”,其中“x”是历史记录中要执行的命令的第一个字母,那么它将运行以该字母开头的最新命令。

我遇到了从历史复制到 inputBuffer 的问题;当我尝试这样做时,它会出现分段错误。

这是代码(这很乱,我一直在尝试很多不同的东西,希望能修复它)。任何建议将不胜感激!

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>


#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
#define BUFFER_SIZE 50

#define buffer "Command History:\n"

char history[10][MAX_LINE];
int count = 0;
int caught = 0;
int ct =0;
int rFlag =0;

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

void shell(void);

void printHistory()
{
      int i;
  int j = 0;
  int hcount = count;

      for (i = 0; i<10;i++)
    {
      printf("%d. ", hcount);
      while (history[i][j] != '\n' && history[i][j] != '\0'){
      printf("%c", history[i][j]);
      j++;
    }
   printf("\n");
   j = 0;   

   hcount--;
   if (hcount ==  0)
    break;
   }


}   

/* the signal handler function */
void handle_SIGINT() 
{
  write(STDOUT_FILENO,buffer,sizeof(buffer));
  printHistory();
  printf("\nCOMMAND->");
  caught = 1;
}


void setup(char inputBuffer[], char *args[],int *background)
{
  int k;
  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;

  printf("Setup");

  /* read what the user enters on the command line */
  if (rFlag!=1)
    {
  length = read(STDIN_FILENO, inputBuffer, MAX_LINE); 
  rFlag = 0;
    }
   printf("buff=%i", strlen(inputBuffer));
  if (caught == 1)
{
  length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
  caught = 0;
}

  if ((strcmp(inputBuffer,"r\n\0")!=0) && (strncmp(inputBuffer, "r x", 2)!=0))
    {
      for (i = 9;i>0; i--)
    {
      strcpy(history[i], history[i-1]);
    }
      strcpy(history[0],inputBuffer); //this works
      count++;
    }


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


  /* examine every character in the inputBuffer */

       printf("beforeCase");
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 */

}

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/+1];/* command line (of 80) has max of 40 arguments */
  pid_t pid;
  char iBuffer2[MAX_LINE];
  int i;

  /* set up the signal handler */
  struct sigaction handler;
  handler.sa_handler = handle_SIGINT; 
  sigaction(SIGINT, &handler, NULL);
  while (1){            /* Program terminates normally inside setup */
   background = 0;
    printf("COMMAND->");
   fflush(0);
   setup(inputBuffer, args, &background);/* get next command */

   if ((strcmp(args[0],"r")==0) && (ct==1))
   {
    fflush(0);
  rFlag = 1;
  background = 0;
  printf("strlen=%i", strlen(history[0]));
  setup(history[0], args, &background);
  printf("AFTER");

}

if (strcmp(args[0],"exit")==0)break; //exits if args[0]=="exit"
pid_t pid = fork();
if (pid < 0) { //Error Occured
  fprintf(stderr, "Fork Failed");
  exit(-1);
}
else if (pid == 0) {//Child Process
  execvp(args[0], args); // Execute command in args
  printf("%s: Command not found.\n", args[0]); //If invalid command
  exit(0);
}
  else { // Parent Process
if (background == 0) { // case with No '&'
  wait(NULL);
}
  }
printf("\nFinish\n");
}
}
4

2 回答 2

2

catchsegv当程序因分段错误而终止时,可用于创建堆栈跟踪。http://www.linuxfromscratch.org/lfs/view/stable/chapter06/glibc.html

于 2010-11-20T01:26:22.280 回答
2

如果您要使用低级 i/o,那么在对读取的数据执行任何字符串操作之前,您有责任在执行 read() 之后 NUL 终止数据。

length = read(STDIN_FILENO, inputBuffer, MAX_LINE-1);
if (length > 0)
   inputBuffer[length] = '\0';
else
   inputBuffer[0] = '\0';

但是 read() 可能不是您一开始就想使用的,因为您似乎希望一次得到一行。尝试使用 fgets() 代替。

于 2010-11-20T05:55:48.497 回答