有人向我提供了此代码,作为如何制作“迷你外壳”的示例,但我不知道它在做什么-我了解主函数中的大多数内容,但是初始化它上面的函数确实让我很迷失上。

任何有关外壳如何工作的基础知识以及C中的一些较低级别的功能都将受到赞赏。

log_t Log;

void printLog(log_t *l){
  log_entry_t *tmp = l->tail;
  while(tmp != NULL){
    printf("%s\n", tmp->value);
    tmp = tmp->prev;
  }
}

int countArg(char *line){
  unsigned int i, count = 0;
  for(i = 0; i < strlen(line); i++){
    if(line[i] == ' ')
      count++;
  }
  return count + 1;
}

char **makeargv(char *line){
  char *buff;
  char **retv;
  unsigned int i, count, arg_num = 0;

  buff = malloc((strlen(line) + 1) * sizeof(char));
  strcpy(buff, line);

  arg_num = countArg(buff);

  retv = malloc((arg_num + 1) * sizeof(char*));

  retv[arg_num] = NULL;
  retv[0] = buff;

  for(i = 0, count = 1; buff[i]!='\0'; i++){
    if(buff[i] == ' '){
      buff[i]='\0';
      retv[count] = buff + i + 1;
      count++;
    }
  }
  return retv;
}


int main()
{
  log_init(&Log);
  char * line;

  while(1){
    size_t size;
    char * cwd = NULL;
    char * query = NULL;
    char * match = NULL;

    int f_exit = 0,
    f_nbi=0,
    f_match=0,
    f_sys = 0,
    f_path=0;

    // print out the requested prompt
    cwd = getcwd(NULL,0);
    printf("$(pid=%d)%s$ ", getpid(), cwd );
    free(cwd);

    line = NULL;
    fflush(stdout);
    getline(&line, &size, stdin);
    line[strlen(line)-1] = '\0';

    while(1){
      if(strcmp(line, "exit") == 0){
        if(f_match) printf("%s matches %s\n", query, line);
        f_exit = 1;
        printf("Command executed by pid=%d\n",getpid());
        log_destroy(&Log);
        break;
      }
      else if(strncmp(line, "cd ", 3) == 0){
        if(f_match) printf("%s matches %s\n", query, line);
        printf("Command executed by pid=%d\n",getpid());
        log_push(&Log, line);
        if(chdir(line + 3) != 0){
          printf("%s: No such file or directory\n",(line + 3));
        }
        break;
      }
      else if(strcmp(line, "!#") == 0){
        if(f_match) printf("%s matches %s\n", query, line);
        printf("Command executed by pid=%d\n",getpid());
        printLog(&Log);
        break;
      }
      else if(strstr(line,"!")==line){
        if(f_match) printf("%s matches %s\n", query, line);
        query = line+1;
        match = log_search(&Log, query);

        if(match==NULL){
          printf("Command executed by pid=%d\n",getpid());
          printf("No Match\n");
          break;
        }
        else{
          f_match = 1;
          printf("Command executed by pid=%d\n",getpid());
          line = malloc((strlen(match)+1)*sizeof(char));
          strcpy(line, match);
          continue;
        }
      }
      else{
        f_nbi = 1;
        log_push(&Log,line);
        if(strstr(line,"/"))
          f_path = 1;
        break;
      }
    }

    if(f_exit)
      break;

    if(f_nbi){
      pid_t pid = fork();
      if(pid == 0){ //child
        if(f_match){
          printf("%s matches %s\n", query, line);
          free(query-1);
        }

        printf("Command executed by pid=%d\n",getpid());
        char **argv = makeargv(line);
        f_sys = 0;

        if(f_path)
          f_sys = execv(argv[0],&argv[0]);
        else
          f_sys = execvp(argv[0],&argv[0]);

        if(f_sys == -1)
          printf("%s: not found\n",line);

        free(argv[0]);
        free(argv);
        log_destroy(&Log);
        exit(0);

    }
    else { //parent
      waitpid(pid, NULL, WUNTRACED);
      if(f_match)
        free(query-1);
      }
    }
    free(line);
    line = NULL;
  }
  if(line != NULL){
    free(line);
    line = NULL;
  }

  return 0;
}

最佳答案

printLog()函数只是以结构类型(由log_t命名为typedef)打印记录的链接列表中的所有数据。它从列表的末尾开始并向后工作。目前尚不清楚列表是单链表还是双链表,但是prev通常仅出现在双链表中。

countArgs()函数是确定命令行上存在多少个参数的粗略方法。这很粗糙,因为它不考虑引号或多个相邻的空格。但是,这些仅表示它高估了论点的数量,这并不严重。它不能将制表符识别为分隔符,这在Shell中是不常见的。

makeargv()函数将命令行分成一系列用空格分隔的单词,并将单词列表返回给调用函数。它有效地解析了命令行,确保命令行末尾有一个空指针。同样,它很简单,但是足够了。与其他两个函数相比,它的命名也不一致。

关于c - 这个 shell 在做什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22032928/

10-11 18:28