2012-05-31 5 views
0

간단한 셸에 대한 내역 기능을 구현하려고합니다. 기록에는 실행 된 마지막 10 개의 명령이 있어야합니다. 아래에 코드를 배치했지만 몇 가지 문제가 있습니다.간단한 UNIX 셸에서 히스토리 구현 관련 문제

먼저 하나 또는 두 개의 명령을 입력하고 history에 입력하면 기록이 표시되지 않습니다. 그러나 몇 가지 명령을 추가하면 전체 기록이 표시되지만 (예 : 그래야 함) 각 기록 색인 옆에는 0의 문자열이 표시됩니다.

내가 뭘 잘못하고 있고, 어떻게 해결할 수 있습니까? 당신의 args 포인터의

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

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

char *history[10][MAX_LINE]; 
int placePointer; 


/** 
* 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 setup(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; 

    /* read what the user enters on the command line */ 
    length = read(STDIN_FILENO, inputBuffer, MAX_LINE); 

    start = -1; 
    if (length == 0) 
     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; 

     case '&': 
      *background = 1; 
      inputBuffer[i] = '\0'; 
      break; 

     default :    /* some other character */ 
      if (start == -1) 
       start = i; 
     } 
    }  
    args[ct] = NULL; /* just in case the input line was > 80 */ 
} 

void displayHistory(){ 
    printf("Display History:\n"); 
    int i = placePointer; 
    int j; 
    int counter; 
    while(counter < 10) { 
     printf("%d: ",counter); 
     for (j = 0; j < MAX_LINE; j++) { 
      printf("%d",history[i][j]); 
     } 
     printf("\n"); 
     i = (i + 1) % 10; 
     counter++; 
    } 
} 
/* 
void runHistoryAt(int index){ 
    printf("Run History At:\n"); 
    char *arg1 = &history[placePointer + index][0]; 
    char *argLine[MAX_LINE/2+1]; 
    int j; 
    for (j = 0; j < MAX_LINE/2+1; j++) { 
     *argLine[j] = history[placePointer + index][j]; 
    } 
    execvp(arg1,argLine); 
}*/ 

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


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

     /* the steps are: 
     (1) fork a child process using fork() 
     (2) the child process will invoke execvp() 
     (3) if background == 0, the parent will wait, 
      otherwise returns to the setup() function. */ 

     pid_t pid = fork(); 
     printf("Fork created.\n"); 


     if(pid < 0){ 
      printf("Fork failed.\n"); 
     }else if(pid == 0){ 
      if(strcmp(args[0],"history") == 0){ /* Print History */ 
       displayHistory(); 
      }else if(strcmp(args[0],"r") == 0){ /* r num */ 
       int index = (int) args[1]; 
       /*runHistoryAt(index - 1);*/ 
      }else if(strcmp(args[0],"rr") == 0){ /* Run recent */ 
       /*runHistoryAt(0);*/ 
      }else{ /* Execute normally */ 
       printf("executing..., adding to history buffer\n"); 
       /* Add args to history buffer */ 
       int j; 
       for (j = 0; j < sizeof(args); j++) { 
        history[placePointer][j] = args[j]; 
       } 
       placePointer = (placePointer + 1) % 10; 
       /* Execute! */ 
       execvp(args[0],args); 
      } 
     } 

     if(background == 0){ 
      wait(NULL); 
     }else{ 
      setup(inputBuffer, args, &background); 
     } 
    } 
} 
+0

진심으로, 당신은 자신을 디버그하는 것이 가장 좋습니다. 검사를 통해 코드의 오류를 찾아내는 낯선 사람에게 생산적이지는 않습니다. –

답변

1

모든 입력 입력의 최신 라인을 포함하여 inputBuffer,에 포인터입니다. 따라서 argshistory에 저장할 때 문자열을 가리키는 실제 포인터가 아니라 포인터를 저장하는 것입니다. 문자열은 여전히 ​​inputBuffer에만 있습니다. 다음 명령어를 읽을 때, inputBuffer은 저장된 모든 history 포인터를 무효로 만듭니다. 현재 포인터는 현재 명령의 일부분을 가리키고 이전 명령은 가리키지 않습니다.

+0

그래서 포인터를 사용하는 대신 기록의 값을 저장해야하므로이 문제를 해결할 수 있습니까? 그리고 어떻게 그럴 수 있을까요? – user906153

+0

@ user906153, 혹시 혹시이 작업 코드가 있거나 알아 내고 코드가 작동하지 않는 이유를 기억하십니까? – wolfclique