• 实现自己的shell--MIT xv6 shell


    参考代码

    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <string.h>
    #include <assert.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    // Simplifed xv6 shell.
    
    #define MAXARGS 10
    
    // All commands have at least a type. Have looked at the type, the code
    // typically casts the *cmd to some specific cmd type.
    struct cmd {        
      int type;          //  ' ' (exec), | (pipe), '<' or '>' for redirection
    };
    
    struct execcmd {//普通指令
      int type;              // ' '
      char *argv[MAXARGS];   // arguments to the command to be exec-ed
    };
    
    struct redircmd {//重定向
      int type;          // < or > 
      struct cmd *cmd;   // the command to be run (e.g., an execcmd)
      char *file;        // the input/output file
      int mode;          // the mode to open the file with
      int fd;            // the file descriptor number to use for the file
    };
    
    struct pipecmd {//pipe指令
      int type;          // |
      struct cmd *left;  // left side of pipe
      struct cmd *right; // right side of pipe
    };
    
    int fork1(void);  // Fork but exits on failure.
    struct cmd *parsecmd(char*);
    
    // Execute cmd.  Never returns.
    void
    runcmd(struct cmd *cmd)
    {
      int p[2], r;
      struct execcmd *ecmd;
      struct pipecmd *pcmd;
      struct redircmd *rcmd;
    
      if(cmd == 0)
        exit(0);
      
      switch(cmd->type){
      default:
        fprintf(stderr, "unknown runcmd
    ");
        exit(-1);
    
      case ' ':
        ecmd = (struct execcmd*)cmd;
        if(ecmd->argv[0] == 0){
            fprintf(stderr, "exec not implemented
    ");
            exit(0);
        }
        execvp(ecmd->argv[0], ecmd->argv);
        // Your code here ...
        break;
      case '>':
      case '<':
        rcmd = (struct redircmd*)cmd;
        // Your code here ...
        close(rcmd->fd);
        if(open(rcmd->file, rcmd->mode) < 0)
        {
            fprintf(stderr, "redir not implemented
    ");
            exit(0);
        }
        runcmd(rcmd->cmd);
        break;
    
      case '|':
        pcmd = (struct pipecmd*)cmd;
        //fprintf(stderr, "pipe not implemented
    ");
        // Your code here ...
        if(pipe(p) < 0)
        {
            fprintf(stderr, "pipe not implemented
    ");
            exit(0);
        }
    
        if(fork1() == 0)
        {
            close(1);
            dup2(p[1],1);
            close(p[0]);
            runcmd(pcmd->left);
        }
    
        if(fork1() == 0)
        {
            close(0);
            dup2(p[0],0);
            close(p[1]);
            runcmd(pcmd->right);
        }
    
        close(p[0]);
        close(p[1]);
        wait();
        wait();
        break;
    
      }
      exit(0);
    }
    
    int
    getcmd(char *buf, int nbuf)// 检测输入是否是标准输入流stdin,然后把用户输入存到buffer里
    {
      
      if (isatty(fileno(stdin)))//fileno()函数   功能:把文件流指针转换成文件描述符;
                                //isatty(判断文件描述词是否是为终端机)若为终端设备则返回1(真),否则返回0(假)
        fprintf(stdout, "$ ");//库函数 int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。
      memset(buf, 0, nbuf);
      fgets(buf, nbuf, stdin);//C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,
      //并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
      if(buf[0] == 0) // EOF
        return -1;
      return 0;
    } 
    
    int
    main(void)
    {
      static char buf[100];
      int fd, r;
    
      // Read and run input commands.
      while(getcmd(buf, sizeof(buf)) >= 0){
        if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
          // Clumsy but will have to do for now.
          // Chdir has no effect on the parent if run in the child.
          buf[strlen(buf)-1] = 0;  // chop 
    
          if(chdir(buf+3) < 0)
            fprintf(stderr, "cannot cd %s
    ", buf+3);
          continue;
        }
        if(fork1() == 0)
          runcmd(parsecmd(buf));
        wait(&r);
      }
      exit(0);
    }
    
    int
    fork1(void)
    {
      int pid;
      
      pid = fork();
      if(pid == -1)
        perror("fork");
      return pid;
    }
    
    struct cmd*
    execcmd(void)// 为一个cmd数据结构分配内存
    {
      struct execcmd *cmd;
    
      cmd = malloc(sizeof(*cmd));
      memset(cmd, 0, sizeof(*cmd));
      cmd->type = ' ';
      return (struct cmd*)cmd;
    }
    
    struct cmd*
    redircmd(struct cmd *subcmd, char *file, int type)
    {
      struct redircmd *cmd;
    
      cmd = malloc(sizeof(*cmd));
      memset(cmd, 0, sizeof(*cmd));
      cmd->type = type;
      cmd->cmd = subcmd;
      cmd->file = file;
      cmd->mode = (type == '<') ?  O_RDONLY : O_WRONLY|O_CREAT|O_TRUNC;
      cmd->fd = (type == '<') ? 0 : 1;
      return (struct cmd*)cmd;
    }
    
    struct cmd*
    pipecmd(struct cmd *left, struct cmd *right)
    {
      struct pipecmd *cmd;
    
      cmd = malloc(sizeof(*cmd));
      memset(cmd, 0, sizeof(*cmd));
      cmd->type = '|';
      cmd->left = left;
      cmd->right = right;
      return (struct cmd*)cmd;
    }
    
    // Parsing
    
    char whitespace[] = " 	
    v";
    char symbols[] = "<|>";
    
    int
    gettoken(char **ps, char *es, char **q, char **eq) // 把地址ps到es的字符串中的变量找到,并存到q到eq的地址去
    {
      char *s;
      int ret;
      
      s = *ps;
      while(s < es && strchr(whitespace, *s))
        s++;
      if(q)
        *q = s;
      ret = *s;
      switch(*s){
      case 0:
        break;
      case '|':
      case '<':
        s++;
        break;
      case '>':
        s++;
        break;
      default:
        ret = 'a';
        while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
          s++;
        break;
      }
      if(eq)
        *eq = s;
      
      while(s < es && strchr(whitespace, *s))
        s++;
      *ps = s;
      return ret;
    }
    
    int
    peek(char **ps, char *es, char *toks)//判断从地址ps到es的字符串是否含有toks里面的字符
    {
      char *s;
      
      s = *ps;
      while(s < es && strchr(whitespace, *s))
        s++;
      *ps = s;
      return *s && strchr(toks, *s);
    }
    
    struct cmd *parseline(char**, char*);
    struct cmd *parsepipe(char**, char*);
    struct cmd *parseexec(char**, char*);
    
    // make a copy of the characters in the input buffer, starting from s through es.
    // null-terminate the copy to make it a string.
    char 
    *mkcopy(char *s, char *es) // s指向需要拷贝的字符串头,es指向需要拷贝的字符串结尾. 这个函数拷贝从s到es的字符串,然后返回拷贝的地址。
    {
      int n = es - s;
      char *c = malloc(n+1);
      assert(c);
      strncpy(c, s, n);
      c[n] = 0;
      return c;
    }
    
    struct cmd*
    parsecmd(char *s)// 解析命令把buffer里的命令包装成可执行的数据结构struct cmd
    {
      char *es;
      struct cmd *cmd;
    
      es = s + strlen(s);
      cmd = parseline(&s, es);
      peek(&s, es, "");
      if(s != es){
        fprintf(stderr, "leftovers: %s
    ", s);
        exit(-1);
      }
      return cmd;
    }
    
    struct cmd*
    parseline(char **ps, char *es)
    {
      struct cmd *cmd;
      cmd = parsepipe(ps, es);
      return cmd;
    }
    
    struct cmd*
    parsepipe(char **ps, char *es)
    {
      struct cmd *cmd;
    
      cmd = parseexec(ps, es);
      if(peek(ps, es, "|")){
        gettoken(ps, es, 0, 0);
        cmd = pipecmd(cmd, parsepipe(ps, es));
      }
      return cmd;
    }
    
    struct cmd*
    parseredirs(struct cmd *cmd, char **ps, char *es)
    {
      int tok;
      char *q, *eq;
    
      while(peek(ps, es, "<>")){
        tok = gettoken(ps, es, 0, 0);
        if(gettoken(ps, es, &q, &eq) != 'a') {
          fprintf(stderr, "missing file for redirection
    ");
          exit(-1);
        }
        switch(tok){
        case '<':
          cmd = redircmd(cmd, mkcopy(q, eq), '<');
          break;
        case '>':
          cmd = redircmd(cmd, mkcopy(q, eq), '>');
          break;
        }
      }
      return cmd;
    }
    
    struct cmd*
    parseexec(char **ps, char *es)
    {
      char *q, *eq;
      int tok, argc;
      struct execcmd *cmd;
      struct cmd *ret;
      
      ret = execcmd();
      cmd = (struct execcmd*)ret;
    
      argc = 0;
      ret = parseredirs(ret, ps, es);
      while(!peek(ps, es, "|")){
        if((tok=gettoken(ps, es, &q, &eq)) == 0)
          break;
        if(tok != 'a') {
          fprintf(stderr, "syntax error
    ");
          exit(-1);
        }
        cmd->argv[argc] = mkcopy(q, eq);
        argc++;
        if(argc >= MAXARGS) {
          fprintf(stderr, "too many args
    ");
          exit(-1);
        }
        ret = parseredirs(ret, ps, es);
      }
      cmd->argv[argc] = 0;
      return ret;
    }
    View Code
  • 相关阅读:
    opencvcircle圆
    关于“100g文件全是数组,取最大的100个数”解决方法汇总
    软件测试的核心价值
    写给测试新手
    软件测试职业规划
    关于软件测试职业规划的讨论
    云计算将改变传统软件测试行业
    对MVC模式的理解
    软件测试专家于涌谈行业前景与测试人员成长
    MVC模式
  • 原文地址:https://www.cnblogs.com/solvit/p/9820662.html
Copyright © 2020-2023  润新知