2

単純なcシェルのコードを書いています。最後の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() は、一度に 1 行ずつ与えられることを期待しているように見えるので、そもそも使用したいものではないでしょう。代わりに fgets() を使用してみてください。

于 2010-11-20T05:55:48.497 に答える