发新话题
打印

[转载]Sixth Edition Unix Shell

[转载]Sixth Edition Unix Shell

  信息来源:mhss.nease.net

UNIX V6 的 sh 代码没有什么稀罕.稀罕的是这是一个改写版,并且有很详细的中文注释.对学习很有好处:)

/*
* 这个 shell 是 UNIX v6 的 sh 在 POSIX 环境下的重新实现。
* UNIX v6 是受 BSD 许可证保护的自由软件,其中 sh 的原作者是 Ken Thompson。
* 余对这个 shell 的语法做了细微修改,对代码做了注释和重写。
* 余对这个程序和相关文档不做任何担保,放弃一切权利,不承担任何责任和义务。
*
* 最近的修订∶ 2004-09-06   寒蝉退士(http://mhss.nease.net)
* 做的工作主要有: K&R C -> ANSI C,unix v6/v7 -> POSIX,去掉了进程记帐和 ^,
* 增加了 $?、umask 和 exec,去除了 goto 语句,增加了中文注释。
*/

下载地址:
http://mhss.nease.net/shell/v6sh/v6sh.tar.gz

或(MS VC6 实验版本):
http://mhss.nease.net/shell/v6sh/v6sh.vc.zip

对应手册(man page):
http://mhss.nease.net/shell/v6sh/sh.html

代码有四个文件,依次是shell.c glob.c if.c goto.c

Shell.c
复制内容到剪贴板
代码:
/*
* 这个 shell 是 UNIX v6 的 sh 在 POSIX 环境下的重新实现。
* UNIX v6 是受 BSD 许可证保护的自由软件,其中 sh 的原作者是 Ken Thompson。
* 余对这个 shell 的语法做了细微修改,对代码做了注释和重写。
* 余对这个程序和相关文档不做任何担保,放弃一切权利,不承担任何责任和义务。
*
* 最近的修订∶ 2004-09-06   寒蝉退士([url]http://mhss.nease.net[/url])
* 做的工作主要有: K&R C -> ANSI C,unix v6/v7 -> POSIX,去掉了进程记帐和 ^,
* 增加了 $?、umask 和 exec,去除了 goto 语句,增加了中文注释。
*/

/*
* Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
*    Redistributions of source code and documentation must retain the above
*    copyright notice, this list of conditions and the following disclaimer.
*    Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*    All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*
*    This product includes software developed or owned by Caldera International, Inc.
*
*    Neither the name of Caldera International, Inc. nor the names of other
*    contributors may be used to endorse or promote products derived from this
*    software without specific prior written permission.
*
* USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA INTERNATIONAL, INC.
* AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR
* ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <limits.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#define     QUOTE 0x80 /* 引用标志位,限制了字符集为 7 位 ASCII */

/* 语法树节点字段定义 */
#define     DTYP 0 /* type: 节点类型 */
#define     DLEF 1 /* left: 左子节点或输入重定向文件描述符 */
#define     DRIT 2 /* right: 右子节点或输出重定向文件描述符 */
#define     DFLG 3 /* flag: 标志位,属性文法意义上的属性 */
#define     DSPR 4 /* space: 在简单命令的时候是一个空位,
           * parentheses: 在复合命令时指向子语法树 */
#define     DCOM 5 /* command: 命令和参数的字列表 */

/* 类型定义,用于 DTYP */
#define     TCOM 1 /* command: 简单命令 */
#define     TPAR 2 /* parentheses: 复合命令 */
#define     TFIL 3 /* filter: 过滤器 */
#define     TLST 4 /* list: 命令列表 */

/* 标志定义,用于 DFLG */
#define     FAND 0x01 /* and: & 后台执行 */
#define     FCAT 0x02 /* catenate: >> 添加方式的输出重定向 */
#define     FPIN 0x04 /* pipe in: 命令从管道获得输入 */
#define     FPOU 0x08 /* pipe out: 命令向管道发送输出 */
#define     FPAR 0x10 /* parentheses: 复合命令中最后一个命令 */
#define     FINT 0x20 /* interrupt: 忽略中断信号 */
#define     FPRS 0x40 /* print string: 打印子进程 pid */

char     *dolp = NULL; /* dollar p: 指向命令行参数的指针 */
char     **dolv; /* dollar v: 命令行参数列表 */
int      dolc; /* dollar c: 命令行参数个数 */
char     pidp[11]; /* 保存 sh 自身进程 pid 的字符串 */
char     *promp; /* 提示符 */
char     *linep; /* 操纵行缓冲区的指针 */
char     *elinep;
char     **argp; /* 操纵字列表存储空间的指针 */
char     **eargp;
int      *treep; /* 操纵语法树节点存储空间的指针 */
int      *treeend;
int      peekc = 0; /* 预读字符 */
int      gflg = 0; /* 全局标志,两种用途:缓冲区溢出,或包含通配符 */
int      error; /* 语法分析发现错误标志 */
int      setintr = 0; /* 设置中断信号忽略的标志 */
char     *arginp = NULL; /* 指针指向包含要执行的命令的参数,执行之后退出 */
int      onelflg = 0; /* one line flag: 读取一行命令执行并退出标志 */
uid_t     uid; /* sh 进程的真实 uid */
jmp_buf     jmpbuf; /* 跨函数跳转用来保存当前状态的缓冲区 */
#define     SIGFLG 0x80 /* 异常终止标志位 */
int      exitstat = 0; /* 执行命令的终止状态 */
char     exitp[4]; /* 保存终止状态的字符串 */
char     *arg0; /* 本 shell 的绝对路径名 */

#define     LINSIZ 1000
#define     ARGSIZ 50
#define     TRESIZ ARGSIZ*2
char     line[LINSIZ]; /* 行缓冲区 */
char     *args[ARGSIZ]; /* 字列表存储空间 */
int      trebuf[TRESIZ]; /* 语法树节点的存储空间 */


/* 诊断消息 */
char *mesg[] = {
     NULL,
     "Hangup", /* SIGHUP 1 */
     NULL, /* SIGINT 2 */
     "Quit", /* SIGQUIT 3 */
     "Illegal instruction", /* SIGILL 4 */
     "Trace trap", /* SIGTRAP 5 */
     "Abort", /* SIGABRT 6 */
     "Signal 7", /* SIGEMT 7 */
     "Floating point exception", /* SIGFPE 8 */
     "Killed", /* SIGKILL 9 */
     "Signal 10", /* SIGBUS 10 */     
     "Segmentation violation", /* SIGSEGV 11 */
     "Bad argument to system call", /* SIGSYS 12 */
     NULL, /* SIGPIPE 13 */
     "Alarm clock", /* SIGALRM 14 */
     "Software termination signal from kill", /* SIGTERM 15 */
     "Signal 16", /* 16 */
     "Child process terminated or stopped", /* SIGSTOP 17 */
};

void lexscan(void);
int  *parse(void);
int  *command_list(char **p1, char **p2);
int  *pipeline(char **p1, char **p2);
int  *command(char **p1, char **p2);
void execute(int *t, int *pf1, int *pf2);
int  redirect(int *t);
int  execcmd(int *t);
int  builtin(int *t);
int  texec(char *f, int *at);
void word(void);
int  *tree(int n);
void scan(int *at, int (*f)());
int  tglob(int c);
int  trim(int c);
int  getC(void);
int  readc(void);
void err(char *s);
void prs(char *as);
void putC(int c);
void prn(int n);
void sprn(int n, char *s);
int  any(int c, char *as);
int  equal(char *as1, char *as2);
int  pwait(pid_t i);
char *shpath(char* s);

int main(int argc, char **argv)
{
     register int f;     /* 文件描述符 */
     int *t; /* 语法树 */

     /* 关闭所有打开的文件 */
     for(f=STDERR_FILENO; f<sysconf(_SC_OPEN_MAX); f++)
          close(f);
     /* 复制标准输出到标准错误输出 */
     if((f=dup(STDOUT_FILENO)) != STDERR_FILENO)
          close(f);
     /* 获得进程标识(32位整数),并转换成字符串,临时借用 dolc 变量 */
     dolc = (int)getpid();
     sprn(dolc, pidp);

     /* 判断当前时候是否根用户,设置正确的提示符 */
     if((uid = getuid()) == 0) /* 根用户 */
          promp = "# ";
     else
          promp = "% ";
     setuid(uid);
     setgid(getgid());

     /* 取得 shell 的绝对路径名 */
     if (argv[0][0] == &#39;/&#39;)
          arg0 = argv[0];
     else
          arg0 = shpath(argv[0]);

     if(argc > 1) {     /* 有参数或选项 */
          promp = 0;     /* 设置为非交互模式 */
          if (*argv[1]==&#39;-&#39;) { /* 有选项 */
              setintr++; /* 需要设置信号处理程序 */
              if (argv[1][1]==&#39;c&#39; && argc>2) /* -c 把下一个参数作为命令执行 */
                   arginp = argv[2];
              else if (argv[1][1]==&#39;t&#39;) /* -t: 从标准输入读入一行执行并退出 */
                   onelflg = 2;
          } else { /* 有命令文件 */
              /* 在标准输入上打开包含要执行的命令的文件 */
              close(STDIN_FILENO);
              f = open(argv[1], O_RDONLY);
              if(f < 0) { /* 打不开指定文件 */
                   prs(argv[1]);
                   err(": cannot open");
              }
          }
     }
     if(setintr) {
          /* 设置中断信号处理程序为忽略信号 */
          signal(SIGQUIT, SIG_IGN);
          signal(SIGINT, SIG_IGN);
     }
     dolv = argv+1; /* 参数列表指针右移 */
     dolc = argc-1; /* 参数数目减少 */

     /* 主循环: 扫描、分析和执行命令行 */
     for(;;) {
          error = 0;
          gflg = 0;
          if(promp != 0)     /* 交互模式运行 */
              prs(promp);     
          lexscan();
          if(gflg != 0) {/* 发生命令行字符溢出 */
              err("Command line overflow");
              continue;
          }
          t = parse();
          if(error != 0) {/* 语法分析发现错误 */
              err("syntax error");
              continue;
          }
          execute(t,NULL,NULL);
     }
     return 0;
}

/* 词法扫描 */
void lexscan(void)
{
     register char *cp;
     register int c;
     /* 初始化行缓冲区、字列表空间和相关指针 */
     argp = args;
     eargp = args+ARGSIZ-5;
     linep = line;
     elinep = line+LINSIZ-5;

     /* 过滤掉注释行 */
     do c = getC();
     while (c == &#39; &#39; || c == &#39;\t&#39;);
     if (c == &#39;#&#39;)
          while ((c = getC()) != &#39;\n&#39;);
     peekc = (char) c; /* 送回最后的换行符 */
     
     /* 把命令行扫描到字列表中 */
     do {
          cp = linep; /* cp 指向当前要读入的字在行缓冲区中的位置 */
          word(); /* 读入一个字到行缓冲区中 */
     } while(*cp != &#39;\n&#39;); /* 循环直到读到换行符 */
}

/* 语法分析 */
int * parse(void)
{
     /* 初始化语法树节点空间和相关指针 */
     treep = trebuf;
     treeend = &trebuf[TRESIZ];

     setjmp(jmpbuf);
     if (error) /* 分析出语法错误或没有空间分配语法树节点的了 */
          return NULL;
     /* args 指向是字列表的第一个元素,
      * argp 指向是字列表的最后一个元素后面的一个元素 */
     return  command_list(args, argp);
}

/*
* 从输入中读出一个字到行缓冲区中,并增加一个字列表元素
*/
void word(void)
{
     register int c, c1;
     
     /* 字列表的当前元素指针指向当前要读入的字在行缓冲区中的位置 */
     *argp++ = linep;

     /* 忽略字前空白 */
     do c = getC();
     while (c == &#39; &#39; || c == &#39;\t&#39;);
     /* 处理 shell 的元字符和换行符 */
     if(any(c, ";&<>()|\n")) {      
          *linep++ = (char) c; /* 把这个元字符或换行符写到行缓冲区中 */
          *linep++ = &#39;\0&#39;; /* 终结这个字符串 */
          return;     
     }
     /* 读到普通字符 */
     peekc = c; /* 送回这个普通字符 */
     for(;;) {
          c = getC();
          if(any(c, " \t;&<>()|\n")) { /* 读到空白、元字符或换行符 */
              peekc = (char) c; /* 送回这个字符 */
              *linep++ = &#39;\0&#39;; /* 终结这个字符串 */
              return;
          }
          if(c == &#39;\&#39;&#39; || c == &#39;"&#39;) {/* 读到单双引号 */
              c1 = c;
              while((c=readc()) != c1) {
                   if(c == &#39;\n&#39;) {
                        error++;     /* 引用没有在本行完结 */
                        peekc = (char) c; /* 送回这个字符 */
                        return;
                   }
                   /* 对引号包围的字符设置引用标志位,并写到行缓冲区中 */
                   *linep++ = (char) c|QUOTE;
              }
              continue;
          }
          *linep++ = (char) c; /* 把这个普通字符写入行缓冲区 */
     }
}

/* 分配指定大小的树结点 */
int * tree(int n)
{
     int *t;

     t = treep;
     treep += n;
     if (treep>treeend) { /* 语法树节点空间不够 */
          prs("Command line overflow\n");
          error++;
          longjmp(jmpbuf,1);
     }
     return t;
}
/* 从输入中读出一个字符 */
int getC(void)
{
     int c;

     if(peekc) { /* 已经预读了一个字符 */
          c = peekc;
          peekc = 0;
          return c;
     }
     if(argp > eargp) { /* 字列表空间溢出 */
          argp -= 10;
          while((c=getC()) != &#39;\n&#39;); /* 忽略多出来的所有字符 */
          argp += 10;
          err("Too many args");
          gflg++;
          return c;
     }
     if(linep > elinep) {  /* 行缓冲区空间溢出 */
          linep -= 10;
          while((c=getC()) != &#39;\n&#39;); /* 忽略多出来的所有字符 */
          linep += 10;
          err("Too many characters");
          gflg++;
          return c;
     }
     if(dolp == NULL) { /* 当前未处理 $ */
          c = readc();
          if(c == &#39;\\&#39;) { /* 转义符 */
              c = readc();
              if(c == &#39;\n&#39;) /* 行接续 */
                   return &#39; &#39;;
              return(c|QUOTE); /* 引用这个字符 */
          }
          if(c == &#39;$&#39;) { /* 变量替换 */
              c = readc();
              if(c>=&#39;0&#39; && c<=&#39;9&#39;) { /* 位置参数 */
                   if(c-&#39;0&#39; < dolc)
                        dolp = dolv[c-&#39;0&#39;];
              }
              if(c == &#39;$&#39;) { /* 进程标识 */
                   dolp = pidp;
              }
              if(c == &#39;?&#39;) { /* 退出状态 */
                   sprn(exitstat, exitp);
                   dolp = exitp;
              }
          }
     }
     if (dolp != NULL) { /* 当前处理 $ */
          c = *dolp++;
          if(c != &#39;\0&#39;)
              return c;
          dolp = NULL;
     }
     return c&~QUOTE; /* 清除引用位 */
}

int readc(void)
{
     char cc;
     int c;

     if (arginp) { /* 有 -c 选项,onelflg == 0 */
          /* 从 arginp 中读取字符 */
          if ((c = (int)*arginp++) == 0) { /* 没有要作为命令的参数 */
              arginp = NULL;
              onelflg++; /* 设置下次执行本函数的时候退出 */
              c = &#39;\n&#39;;
          }
          return c;
     }
     if (onelflg==1)
          exit(0);
     if(read(STDIN_FILENO, &cc, 1) != 1) /* 读一个字符 */
          exit(0);
     /* 有 -t 选项,onelflg == 2,从标准输入读入了换行符 */
     if (cc==&#39;\n&#39; && onelflg)
          onelflg--; /* 设置下次执行本函数的时候退出 */
     return (int)cc;
}

/*
*     command_list:
*          empty
*          pipeline
*          pipeline & command_list
*          pipeline ; command_list
*/
int * command_list(char **p1, char **p2)
{
     register char **p;
     int *t, *t1;
     int l;

     /* 忽略前导的列表分隔符 */
     while(p1 != p2 && any(**p1, ";&\n"))
          p1++;

     if (p1 == p2)
          return NULL; /* 空命令 */

     l = 0; /* 嵌套层数 */
     for(p=p1; p!=p2; p++)
          switch(**p) {

          case &#39;(&#39;:
              l++;
              break;

          case &#39;)&#39;:
              l--;
              if(l < 0)
                   error++;
              break;

          /* 找到第一个列表分隔符 */
          case &#39;&&#39;:
          case &#39;;&#39;:
          case &#39;\n&#39;:
              if(l == 0) {
                   l = **p;
                   t = tree(4);
                   t[DTYP] = TLST; /* 类型是命令列表 */
                   t[DLEF] = (int)pipeline(p1, p);
                   t[DFLG] = 0;  /* 命令列表节点不设置任何标志位 */
                   if(l == &#39;&&#39;) { /* 需要后台处理 */
                        t1 = (int *)t[DLEF];
                        /* 设置左子节点标志 */
                        t1[DFLG] |= FAND|FPRS|FINT;     
                        /*
                        * 后台运行的这些标志位只设置到在管道线节点上,
                        * 所以在执行的时候需要通过继承来下传到各个命令节点上。
                        */
                   }
                   t[DRIT] = (int)command_list(p+1, p2);
                   return t;
              }
          }
     /* 没有找到列表分隔符,发生在命令来自参数的时候 */
     if(l == 0)
          return pipeline(p1, p2);
     error++;
     return NULL;
}

/*
*     pipeline:
*          command
*          command | pipeline
*/
int * pipeline(char **p1, char **p2)
{
     register char **p;
     int l, *t;

     l = 0; /* 嵌套层数 */
     for(p=p1; p!=p2; p++)
          switch(**p) {

          case &#39;(&#39;:
              l++;
              break;

          case &#39;)&#39;:
              l--;
              break;

          /* 找到第一个管道符号 */
          case &#39;|&#39;:
              if(l == 0) {
                   t = tree(4);
                   t[DTYP] = TFIL;     /* 类型是管道线 */
                   t[DLEF] = (int)command(p1, p);
                   t[DRIT] = (int)pipeline(p+1, p2);
                   t[DFLG] = 0; /* 标志位由上级的 command_list 设置 */
                   return t;
              }
          }
     /* 没有找到管道符号,是管道线末端或简单命令 */
     return command(p1, p2);
}

/*
*     command:
*          ( command_list ) [ < in  ] [ > out ]
*          word word* [ < in ] [ > out ]
*/
int * command(char **p1, char **p2)
{
     register char **p;
     char **lp = NULL, **rp = NULL;
     int *t;
     int n = 0, l = 0, i = 0, o = 0, c, flg = 0;

     if(**p2 == &#39;)&#39;)     /* 这个命令是在圆括号包围中的命令列表的最后一个命令 */
          flg |= FPAR;

     for(p=p1; p!=p2; p++)
          switch(c = **p) {

          case &#39;(&#39;:
              if(l == 0) {
                   if(lp != NULL)
                        error++;
                   lp = p+1; /* 最外层圆括号内列表的第一个字 */
              }
              l++;
              break;

          case &#39;)&#39;:
              l--;
              if(l == 0)
                   rp = p; /* 最外层圆括号内的最后一个字后面的&#39;)&#39; */
              break;

          case &#39;>&#39;:
              p++;
              if(p!=p2 && **p==&#39;>&#39;) /*  >> 重定向 */
                   flg |= FCAT;
              else
                   p--;
          case &#39;<&#39;:
              if(l == 0) {
                   p++; /* 重定向的文件描述符 */
                   if(p == p2) { /* 重定向之后没有字符了 */
                        error++;
                        p--;
                   }
                   if(any(**p, "<>("))  /* 重定向之后的字符不是合法字符 */
                        error++;
                   if(c == &#39;<&#39;) {
                        if(i != 0)
                            error++;
                        i = (int)*p; /* 输入重定向文件的全路径名 */
                   } else { /* > 或 >> */
                        if(o != 0)
                            error++;
                        o = (int)*p; /* 输出重定向文件的全路径名 */
                   }
                   break;
              }

          default:
              if(l == 0) /* 有不在圆括号中的普通的字 */
                   p1[n++] = *p;
              /* 形成简单命令的字列表,去掉了重定向符号和相应的文件描述符 */
          }

     if(lp != 0) { /* 有圆括号 */
          if(n != 0)  /* 有不在圆括号中的普通的字 */
              error++;
          t = tree(5); /* 有 DSPR 字段 */
          t[DTYP] = TPAR; /* 类型是复合命令 */
          t[DSPR] = (int)command_list(lp, rp);
     } else { /* 简单命令 */
          if(n == 0)     /* 没有命令名字 */
              error++;
          p1[n++] = 0; /* 结束字列表 */
          t = tree(n+5);
          /* 在语法树节点中有 DSPR,DCOM 字段,并增加了字列表的空间 */
          t[DTYP] = TCOM; /* 类型是简单命令 */
          for(l=0; l<n; l++) /* 复制字列表到语法树节点 */
              t[l+DCOM] = (int)p1[l];
     }
     t[DFLG] = flg; /* 根据情况设置的 FPAR 或 FCAT 标志 */
     t[DLEF] = i; /* 输入重定向文件的全路径名 */
     t[DRIT] = o; /* 输出重定向文件的全路径名 */
     return t;
}
/* 扫描字列表 */
void scan(int *at, int (*f)())
{
     register char *p, c;
     int *t;

     t = at+DCOM;
     while((p = (char *)*t++) != NULL)
          while((c = *p) != 0)
              *p++ = (*f)(c);
}
/* 检测是否包含通配符 */
int tglob(int c)
{
     if(any(c, "[?*"))
          gflg = 1;
     return c;
}
/* 清除引用标志位 */
int trim(int c)
{
     return c&~QUOTE;
}
/*
* 管道线语法树的执行,pf1 流入管道,pf2 流出管道
* a | b | c 管道线的语法树:
*   TFIL1
*   /  \
*  TCOM1 TFIL2
*   |  /  \
*   a TCOM2 TCOM3
*      |    |
*      b    c
* 执行序列:
* execute(TFIL1, NULL, NULL);
* execute(TOCM1, NULL, pv1);     TOCM1.TFLG: FPOU;     父进程打开着 pv1
* execute(TFIL2, pv1, NULL);     TFIL2.TFLG: FPIN;
* execute(TCOM2, pv1, pv2);     TCOM2.TFLG: FPIN, FPOU;     父进程关闭了 pv1, 打开着 pv2
* execute(TCOM3, pv2, NULL);     TCOM3.TFLG: FPIN;     父进程关闭了 pv2
*/
void execute(int *t, int *pf1, int *pf2)
{
     int i, f, pv[2];
     register int *t1;

     if(t == 0)
          return;
     switch(t[DTYP]) {
     case TLST:     /* 命令列表类型 */
          f = t[DFLG];     
          if((t1 = (int *)t[DLEF]) != NULL)
              /* 向子节点下传 FINT 标志的当前状态 */
              t1[DFLG] |= f&FINT;     
          execute(t1,NULL,NULL);
          if((t1 = (int *)t[DRIT]) != NULL)
              t1[DFLG] |= f&FINT;
          execute(t1,NULL,NULL);
          /*
          * 命令列表位于复合命令中当中的时候,TLST 节点
          * 只从上层 TPAR 节点继承 FINT 标志。
          */
          return;

     case TFIL:     /* 管道线类型 */
          f = t[DFLG];
          pipe(pv); /* 建立管道 */
          t1 = (int *)t[DLEF];
          /* 向左子节点下传 FPIN FINT FPRS 标志的当前状态,
          * 并设置它的 FPOU 标志  */
          t1[DFLG] |= FPOU | (f&(FPIN|FINT|FPRS));
          execute(t1, pf1, pv); /* 命令输出流入新建的管道 */
          t1 = (int *)t[DRIT];
          /* 向右子节点下传 FPOU FINT FAND FPRS 标志的当前状态,
          * 并设置它的 FPIN 标志  */
          t1[DFLG] |= FPIN | (f&(FPOU|FINT|FAND|FPRS));
          execute(t1, pv, pf2); /* 命令输入来自新建的管道 */
          /*
          * 只有管道线末端的命令能从上层节点继承到 FAND 标志
          */
          return;

     case TCOM: /* 简单命令类型入口 */
          /* 筛选出内置命令 */
          if (builtin(t))
              return;

     case TPAR: /* 复合命令类型切入点 */
          f = t[DFLG];
          i = 0;
          /*
          * 为简单命令、复合命令整体和复合命令除最后一个命令之外的所有命令
          * 建立子进程,复合命令最后一个命令使用为复合命令整体建立的子进程
          */
          if((f&FPAR) == 0)
              i = fork();
          if(i == -1) { /* 进程复制失败 */
              err("try again");
              return;
          }
          /*
          * 父进程执行部分
          */
          if(i != 0) {
              if((f&FPIN) != 0) { /* 子进程有流入管道 */
                   /* 在读管道的子进程没有建立之前,父进程保持打开这个管道
                    * 当读管道的子进程已经建立之后,父进程关闭管道读出写入端 */
                   close(pf1[0]);
                   close(pf1[1]);
              }
              if((f&FPRS) != 0) { /* 需要打印子进程 pid */
                   prn(i);
                   prs("\n");
              }
              if((f&FAND) != 0) { /* 后台命令不需要等待子进程 */
                   exitstat = 0;
                   return;
              }
              if((f&FPOU) == 0) /* 子进程是前台的简单命令、或管道线末端的命令 */
                   exitstat = pwait(i); /*  等待子进程终止 */
              return;
          }
          /*
          * 子进程执行部分
          */
          if (redirect(t)) /* 重定向标准输入输出 */
              exit(1);
          if((f&FPIN) != 0) { /* 有流入管道 */
              close(STDIN_FILENO);
              /* 接入管道读出端 */
              dup(pf1[0]);
              close(pf1[0]);
              /* 关闭管道写入端 */
              close(pf1[1]);
          }
          if((f&FPOU) != 0) {     /* 有流出管道 */
              /* 接入管道写入端 */
              close(STDOUT_FILENO);
              dup(pf2[1]);
              close(pf2[0]);
              /* 关闭管道读出端 */
              close(pf2[1]);
          }
          /* 后台进程没有做重定向其标准输入 */
          if((f&FINT)!=0 && t[DLEF]==0 && (f&FPIN)==0) {
              close(STDIN_FILENO);
              open("/dev/null", O_RDONLY);
          }
          /* 是未设置中断信号忽略标志的前台命令,
          * 并在非交互模式下已经设置中断信号处理程序为忽略信号 */
          if((f&FINT) == 0 && setintr) {
              /* 恢复中断信号处理程序为缺省 */
              signal(SIGINT, SIG_DFL);
              signal(SIGQUIT, SIG_DFL);
          }
          /*
          * 复合命令在子 shell 中执行,父 shell 节点中的 FAND, FPRS 标志位作用于
          * 子 shell 本身的进程,子 shell 中的节点不继承 FAND, FPRS 标志位。
          */
          if(t[DTYP] == TPAR) {
              if((t1 = (int *)t[DSPR]) != NULL)
                   /* 向子节点下传 FINT 标志的当前状态 */
                   t1[DFLG] |= f&FINT;
              execute(t1,NULL,NULL);
              exit(1);
          }
          i=execcmd(t); /* 执行命令 */
          exit(i);
     }
}
/*
* 重定向标准输入输出
*/
int redirect(int *t)
{
     int i;
     int f = t[DFLG];
     
     if(t[DLEF] != 0) { /* 有输入重定向 */
          /* 重定向标准输入 */
          close(STDIN_FILENO);
          i = open((char *)t[DLEF], O_RDONLY);
          if(i < 0) {
              prs((char *)t[DLEF]);
              err(": cannot open");
              return 1;
          }
     }
     if(t[DRIT] != 0) { /* 有输出重定向 */
          if((f&FCAT) != 0) { /* >> 重定向 */
              i = open((char *)t[DRIT], O_WRONLY);
              if(i >= 0)
                   lseek(i, 0, SEEK_END);
          } else {
              i = creat((char *)t[DRIT], 0666);
              if(i < 0) {
                   prs((char *)t[DRIT]);
                   err(": cannot create");
                   return 1;
              }
          }
          /* 重定向标准输出 */
          close(STDOUT_FILENO);
          dup(i);
          close(i);
     }
     return 0;
}
/*
* 执行语法树节点中的命令
*/
int execcmd(int *t)
{     
     register char *cp1, *cp2;
     int i;

     gflg = 0;
     scan(t, tglob);     /* 测试是否有通配符 */
     if(gflg) {
          extern int glob(int argc, char *argv[]);
          char **cp;
          t[DSPR] = (int)"/etc/glob";
          for(i = 0, cp = (char **)(t+DSPR); *cp != NULL; i++, cp++);
          i = glob(i, (char **)(t+DSPR));
          return i;
     }
     /* 参数没有通配符的命令 */
     scan(t, trim); /* 清除引用标志位 */
     *linep = &#39;\0&#39;;
     i=texec((char *)t[DCOM], t);
     if (i!=127)
          return i;
     /* 连接 /usr/bin/ 和 t[DCOM] 为一个字符串 */
     cp1 = linep;
     cp2 = "/usr/bin/";
     while((*cp1 = *cp2++) != 0)
          cp1++;
     cp2 = (char *)t[DCOM];
     while((*cp1++ = *cp2++) != 0);
     i=texec(linep+4, t); /* 添加 /bin 前缀执行命令 */
     if (i!=127)
          return i;
     i=texec(linep, t); /* 添加 /usr/bin 前缀执行命令 */
     prs((char *)t[DCOM]);
     err(": not found");
     return i;
}
/*
* 内置命令处理
*/
int builtin(int *t)
{
     char *cp1;

     cp1 = (char *)t[DCOM];
     if(equal(cp1, "cd") || equal(cp1, "chdir")) {
          if((char *)t[DCOM+1] != NULL) {
              if(chdir((char *)t[DCOM+1]) < 0)
                   err("chdir: bad directory");
          } else
              err("chdir: arg count");
          return 1;
     }
     if(equal(cp1, "shift")) {
          if(dolc < 1) {
              prs("shift: no args\n");
              return 1;
          }
          dolv[1] = dolv[0]; /* 命令文件名右移替代了第一个位置参数 */
          dolv++;
          dolc--;
          return 1;
     }
     if(equal(cp1, "login")) {
          if(promp != 0)
              execv("/bin/login", (char **)(t+DCOM));
          prs("login: cannot execute\n");
          return 1;
     }
     if(equal(cp1, "newgrp")) {
          if(promp != 0)
              execv("/bin/newgrp", (char **)(t+DCOM));
          prs("newgrp: cannot execute\n");
          return 1;
     }
     if(equal(cp1, "wait")) {
          pwait(-1);     /* 等待所有子进程 */
          return 1;
     }
     if(equal(cp1, ":"))
          return 1;
     if(equal(cp1, "exit")) {
          char* cp2 = (char *)t[DCOM+1];
          int c, i = 0;
          if (cp2 != NULL) { /* 有参数 */
              while ((c = *cp2++) >= &#39;0&#39; && c <= &#39;9&#39;)
                   i = (i*10)+c-&#39;0&#39;;
          }
          exit(i);
     }
     if(equal(cp1,"exec")) {
          int i;
          if (redirect(t)) {     /* 重定向标准输入输出 */
              exitstat = 1;
              return 1;
          }
          if ((char *)t[DCOM+1] != NULL) {
              i=execcmd(t+1);
              exitstat = i;
              return 1;
          }
          exitstat = 0;
          return 1;
     }
     if(equal(cp1, "umask"))     {
          char* cp2 = (char *)t[DCOM+1];
          if (cp2 != NULL) { /* 有参数 */
              int c, i = 0;
              while ((c = *cp2++) >= &#39;0&#39; && c <= &#39;7&#39;)
                   i = (i<<3)+c-&#39;0&#39;;
              umask(i);
          } else {
              int i, j;
              umask(i = umask(0));
              putC(&#39;0&#39;);
              for (j = 6; j >= 0; j-=3)
                   putC(((i>>j)&07)+&#39;0&#39;);
              putC(&#39;\n&#39;);
          }
          return 1;
     }
     return 0;
}

/* exec 和进行错误消息打印 */
int texec(char* f, int *at)
{
     extern int errno;
     register int *t;

     t = at;
     execv(f, (char **)(t+DCOM));
     if (errno==EACCES) { /* 没有访问权限 */
          prs("Permission denied\n");
          return 126;
     }
     if (errno==ENOEXEC) { /* 不是二进制可执行文件 */
          t[DCOM] = (int)f;
          t[DSPR] = (int)arg0;
          execv((char *)t[DSPR], (char **)(t+DSPR));
          prs("No shell!\n");
          return 126;
     }
     if (errno==ENOMEM) { /* 不能分配内存 */
          prs((char *)t[DCOM]);
          err(": too large");
          return ENOMEM;
     }
     return 127;
}
/* 打印错误输出,在非交互模式下退出 */
void err(char *s)
{

     prs(s);
     prs("\n");
     if(promp == 0) {
          lseek(STDIN_FILENO, 0, SEEK_END);
          exit(1);
     }
}
/* 写一个字符串 */
void prs(char *as)
{
     register char *s;

     s = as;
     while(*s)
          putC(*s++);
}
/* 写一个字符 */
void putC(int c)
{
     write(STDERR_FILENO, &c, 1);
}
/* 写一个数 */
void prn(int n)
{
     register int a;

     if((a=n/10) != 0)
          prn(a);
     putC((n%10)+&#39;0&#39;);
}
/* 写一个数到字符串 */
void sprn(int n, char *s)
{
     int i,j;
     for (i=1000000000; n<i && i>1; i/=10); /* 32 位字长 */
     for (j=0; i>0; j++,n%=i,i/=10)
          s[j] =(char)(n/i + &#39;0&#39;);
     s[j] = &#39;\0&#39;;
}

/* 判断一个字符是否在一个字符串中 */
int any(int c, char *as)
{
     register char *s;

     s = as;
     while(*s)
          if(*s++ == c)
              return 1;
     return 0;
}
/* 判断两个字符串是否相等 */
int equal(char *as1, char *as2)
{
     register char *s1, *s2;

     s1 = as1;
     s2 = as2;
     while(*s1++ == *s2)
          if(*s2++ == &#39;\0&#39;)
              return 1;
     return 0;
}
/* i>0 等待指定 pid 的进程终止,i<0 等待所有子进程终止,
* 如果异常终止,则打印诊断信息 */
int pwait(pid_t i)
{
     pid_t p;
     int e = 0, s;
     if(i == 0)
          return 0;
     for(;;) {
          p = wait(&s);
          if(p == -1) /* 没有子进程需要等待了 */
              break;
          e = WTERMSIG(s); /* 取子进程终止状态 */
          if(e > 0 && mesg[e] != NULL) {
              if(p != i) {
                   prn(p);
                   prs(": ");
              }
              if (e <= 17)
                   prs(mesg[e]);
              else
                   prs("Terminated abnormally");
          /*     if(WCOREDUMP(s))
          *          prs(" -- Core dumped"); */
              err("");
          }
          if(i == p) /* 终止的子进程是要等待的子进程 */
              break;
     }
     if (WIFEXITED(s))
          return WEXITSTATUS(s);
     else
          return e | SIGFLG;
}
/*
* 把调用 shell 的相对路径名和当前工作路径合并成绝对路径名
*/
char *shpath(char* s)
{
     #define SHPATH_MAX 80
     static char shpathbuf[SHPATH_MAX+1]; /* 保存 sh 绝对路径名 */
     register char *p1, *p2;
     register char c;

     if (getcwd(shpathbuf, SHPATH_MAX)==NULL) { /* 得到当前工作路径 */
          err("shell path error");
          exit(1);
     }
     p1 = shpathbuf;
     while (*p1 != &#39;\0&#39;)
          p1++;
     *p1++ = &#39;/&#39;;
     p2 = s;
     c = *p2;
     while (c != &#39;\0&#39;) {
          if (p2[0]== &#39;.&#39; && p2[1] == &#39;/&#39;)
              p2+=2;
          else if (p2[0]== &#39;.&#39; && p2[1] == &#39;.&#39; && p2[2] == &#39;/&#39;) {
              p2+=3;
              while(*(--p1) != &#39;/&#39;);
          }
          else
              do {
                   if (p1 > shpathbuf+SHPATH_MAX) {
                        err("shell path error");
                        exit(1);
                   }
                   *p1++ = c = *p2++;
              } while (c != &#39;/&#39; && c != &#39;\0&#39;);
     }
     return shpathbuf;
}
Very Idiotic Person

TOP

glob.c:
复制内容到剪贴板
代码:
/* glob 命令 --

  glob params

  在 params 中的 "*" 匹配正则表达式 ".*"
  在 params 中的 "?" 匹配正则表达式 "."
  在 params 中的 "[...]" 匹配字符类
  在 params 中的 "[!...]" 匹配字符类的补集。
  在 params 中的 "[...a-z...]" 匹配 a 到 z。

  执行命令并带有按如下规则构造的参数列表:
     如果 param 不包含 "*","[",或 "?",则按原样使用它
     如果包含,则在当前目录中找到匹配这个 param 的所有文件,
      排序并使用它们。

  按需要为命令名字添加 "/bin" 或 "/usr/bin" 前缀。
*/
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>

#define    QUOTE 0x80    /* 引用标志位 */

#define    STRSIZ _POSIX_ARG_MAX
extern char *arg0;    /* 调用 sh 的全路径 */
static char ab[STRSIZ];    /* 生成的字符串的存储空间 */
static char *string;   
static char *ava[STRSIZ/2];    /* 生成的参数列表 */
static char **av;
static int  ncoll;

int glob(int argc, char *argv[]);
static int gexec(char *afile, char **aarg);
static void expand(char *as);
static void sort(char **oav);
static void toolong(void);
static int match(char *s, char *p);
static int amatch(char *as, char *ap);
static int umatch(char *s, char *p);
static int compare(char *as1, char *as2);
static char* cat(char *as1, char *as2);

int glob(int argc, char *argv[])
{
    char *cp;
    int r;

    string = ab;
    av = &ava[1]; /* 有意留出一个空位 */

    if (argc < 2) {
        write(STDERR_FILENO, "Arg count\n", 10);
        exit (1);
    }
    argv++;
    *av++ = *argv; /* 指向第一个参数,它是要执行的文件的名字 */
    while (--argc >= 2)
        expand(*++argv);  /* 展开余下的所有的参数 */

    if ((r = gexec(ava[1], &ava[1])))
        return r;
    cp = cat("/usr/bin/", ava[1]);
    if ((r = gexec(cp+4, &ava[1])))
        return r;
    if ((r = gexec(cp, &ava[1])))
        return r;
    write(STDERR_FILENO, "Command not found.\n", 19);
    return 127;
}

void expand(char *as)
{
    register char *s, *cs;
    struct dirent * dirp;
    DIR    *dp;
    char **oav;

    ncoll = 0;
    s = cs = as;
    /* 把 cs 定位到第一个通配符 */
    while (*cs!=&#39;*&#39; && *cs!=&#39;?&#39; && *cs!=&#39;[&#39;) {
        if (*cs++ == 0) { /* 没有找到通配符 */
            *av++ = cat(s, "");
            return;
        }
    }
    for (;;) {
        if (cs==s) { /* 在通配符之前没有&#39;/&#39; */
            dp = opendir(".");
            s = "";
            break;
        }
        if (*--cs == &#39;/&#39;) {
            *cs = 0; /* 把参数分开为目录和文件名两个字符串 */
            dp = opendir((s==cs)? "/": s);
            *cs++ = QUOTE;    /* 做标记,在后面的 cat 操作中恢复成斜杠 */
            break;
        }
    }
    if (dp == NULL) {
        write(STDERR_FILENO, "No directory\n", 13);
        exit (1);
    }
    oav = av;
    while ((dirp = readdir(dp)) != NULL) {
        if (match(dirp->d_name, cs)) {
            *av++ = cat(s, dirp->d_name);
            ncoll++;
        }
    }
    if (!ncoll) /* 没有匹配 */
        *av++ = cat(s, cs); /* 保持参数为原状 */
    else /* 排序匹配的文件名字 */
        sort(oav);
    closedir(dp);

}
/* 排序 */
void sort(char **oav)
{
    register char **p1, **p2, *c;

    p1 = oav;
    while (++p1 < av) {
        c = *p1;
        p2 = p1;
        while (--p2 >= oav && compare(*p2, c) > 0)
            *(p2+1) = *p2;
        *(p2+1) = c;
    }
}
/* 执行一个命令 */
int gexec(char *afile, char **aarg)
{
    register char *file, **arg;

    arg = aarg;
    file = afile;
    execv(file, arg);

    if (errno == EACCES) {
        write(STDERR_FILENO, "Permission denied\n", 18);
        return 126;
    }
    if (errno==ENOEXEC) { /* 不是二进制可执行文件 */
        arg[0] = file;
        *--arg = arg0;
        execv(*arg, arg); /* 作为命令文件执行 */
    }
    if (errno==E2BIG) {/* 在参数列表太长的时候退出 */
        toolong();
        return E2BIG;
    }
    return 0;
}
/* 打印错误消息并退出 */
void toolong(void)
{
    write(2, "Arg list too long\n", 18);
}
/*匹配判断例程 */
int match(char *s, char *p)
{
    if (*s==&#39;.&#39; && *p!=&#39;.&#39;) /* 对 . 开头的文件的处理 */
        return 0;
    return amatch(s, p);
}
/* 对字符的匹配 */
int amatch(char *as, char *ap)
{
    register char *s, *p;
    register int scc;
    int c, cc, ok, lc;
    int neg = 0;

    s = as;
    p = ap;
    if ((scc = *s++) != 0) /* 文件名未终结 */
        /* 传递给 glob 的参数中的字符可能设置了引用位,
        这些字符在 shell 命令行中位于" "或&#39; &#39; 中 */
        if ((scc &= ~QUOTE) == 0) /* 如果 scc 清除了引用位之后是 0 */
            scc = QUOTE; /* 重新把它设置为 QUOTE */
    switch (c = *p++) {

    case &#39;[&#39;:    /* 处理字符类 */
        if (*p==&#39;!&#39;) { /* 下个字符是 ! */
            neg = 1;
            p++;
        }
        ok = 0;
        lc = INT_MAX;
        while ((cc = *p++) != 0) {
            if (cc==&#39;]&#39;) {
                if ((ok && !neg) || (!ok && neg))
                    return amatch(s, p); /* 如果匹配,继续比较后面的字符 */
                else
                    return 0;
            } else if (cc==&#39;-&#39;) {
                if (lc<=scc && scc<=(c = *p++)) /* 在范围内 */
                    ok++;
            } else
                if (scc == (lc=cc))
                    ok++;
        }
        return 0;

    default:
        if (c!=scc)
            return 0;

    case &#39;?&#39;:
        if (scc)
            return amatch(s, p);
        return 0;

    case &#39;*&#39;:
        return umatch(--s, p);

    case &#39;\0&#39;:
        return !scc;
    }
}
/* 对闭包的匹配 */
int umatch(char *s, char *p)
{
    if(*p==0) /* 模式以 * 结束 */
        return 1;
    while(*s) /* 文件名中有字符匹配模式中 * 后面的字符 */
        if (amatch(s++,p))
            return 1;
    return 0;
}
/* 比较两个字符串 */
int compare(char *as1, char *as2)
{
    register char *s1, *s2;

    s1 = as1;
    s2 = as2;
    while (*s1++ ==  *s2)
        if (*s2++ == 0)
            return 0;
    return (*--s1 - *s2);
}
/* 联接两个字符串到 string 指向的数组中并返回它,
* 副作用是 string 指针右移,指向的数组空间减小 */
char* cat(char *as1, char *as2)
{
    register char *s1, *s2;
    register int c;

    s2 = string;
    s1 = as1;
    while ((c = *s1++) != 0) {
        if (s2 > &ab[STRSIZ])
            toolong();
        c &= ~QUOTE; /* 清除引用位 */
        if (c==0) { /* 原先是路径分隔符 */
            *s2++ = &#39;/&#39;;
            break;
        }
        *s2++ = c;
    }

    s1 = as2;
    do {
        if (s2 > &ab[STRSIZ])
            toolong();
        *s2++ = c = *s1++;
    } while (c);

    s1 = string;
    string = s2;
    return s1;
}
if.c
复制内容到剪贴板
代码:
/*
* if exprression cmd [arg]....
* if 是 test 命令的前身。在测试完表达式之后,如果为真则执行后面的命令。
* 这里的 if 命令建立在 v7 test 命令基础上。
*/

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

#define EQ(a,b)    ((tmp=a)==0?0:(strcmp(tmp,b)==0))

int     ac;
char    **av;
int     ap;
char    *tmp;

#define DIR 1
#define FIL 2
char *nxtarg(int mt);
int expr(void);
int e1(void);
int e2(void);
int e3(void);
int tio(char *a, int  f);
int ftype(char *f);
int fsizep(char *f);
void synbad(char *s1, char *s2);
int length(char *s);
int doex(char *earg);

int main(int argc, char**argv)
{
    ac = argc;
    av = argv;
    ap = 1;
    argv[ac] = 0;

    if (ac<=1)
        return 1;
    if (expr())
        return doex(0);
    else   
        return 1;
}
/*
* 获得下一个参数。mt 指示在读到列表尾部的时候是否为语法错误,
* 1 返回空指针,0 提示错误并退出。
*/
char *nxtarg(int mt)
{
    if (ap>=ac) {
        if(mt) {
            ap++;
            return(0);
        }
        synbad("argument exprected","");
    }
    return(av[ap++]);
}
/*
* expr ::= * e1 -o expr | expr
*/
int expr(void)
{
    int p1;

    p1 = e1();
    if (EQ(nxtarg(1), "-o"))
        return(p1 | expr());
    ap--;
    return(p1);
}
/*
* e1 ::= e2 -a e1 | e1
*/
int e1(void)
{
    int p1;

    p1 = e2();
    if (EQ(nxtarg(1), "-a"))
        return (p1 & e1());
    ap--;
    return(p1);
}
/*
* e2 ::= e3 | ! e3
*/
int e2(void)
{
    if (EQ(nxtarg(0), "!"))
        return(!e3());
    ap--;
    return(e3());
}
/*
* e3 ::= ( expr ) | { command ... } | -op file | string -op string
*/
int e3(void)
{
    int p1,r;
    register char *a;
    char *p2;
    int int1, int2;
    int ccode;

    a=nxtarg(0);
    if(EQ(a, "(")) {
        p1 = expr();
        if(!EQ(nxtarg(0), ")"))
            synbad(") exprected","");
        return(p1);
    }
    if(EQ(a, "{")) { /* 执行一个命令并等待退出状态 */
        if(fork()) /* 父进程执行部分 */
            wait(&ccode);
        else { /* 子进程执行部分 */
            if ((r=doex("}")) != 0)
                if (r == 1)
                    synbad("} exprected","");
                else
                    exit(r);
            else
                exit(0);
        }
        while((a=nxtarg(0)) && (!EQ(a,"}")));
        return(ccode? 0 : 1);
    }
    if(EQ(a, "-r"))
        return(tio(nxtarg(0), 0));

    if(EQ(a, "-w"))
        return(tio(nxtarg(0), 1));

    if(EQ(a, "-d"))
        return(ftype(nxtarg(0))==DIR);

    if(EQ(a, "-f"))
        return(ftype(nxtarg(0))==FIL);

    if(EQ(a, "-s"))
        return(fsizep(nxtarg(0)));

    if(EQ(a, "-t")) {
        if(ap>=ac)
            return(isatty(1));
        else
            return(isatty(atoi(nxtarg(0))));
    }
    if(EQ(a, "-n"))
        return(!EQ(nxtarg(0), ""));
    if(EQ(a, "-z"))
        return(EQ(nxtarg(0), ""));

    p2 = nxtarg(1);
    if (p2==0)
        return(!EQ(a,""));
    if(EQ(p2, "="))
        return(EQ(nxtarg(0), a));

    if(EQ(p2, "!="))
        return(!EQ(nxtarg(0), a));

    if(EQ(a, "-l")) {
        int1=length(p2);
        p2=nxtarg(0);
    } else{    int1=atoi(a);
    }
    int2 = atoi(nxtarg(0));
    if(EQ(p2, "-eq"))
        return(int1==int2);
    if(EQ(p2, "-ne"))
        return(int1!=int2);
    if(EQ(p2, "-gt"))
        return(int1>int2);
    if(EQ(p2, "-lt"))
        return(int1<int2);
    if(EQ(p2, "-ge"))
        return(int1>=int2);
    if(EQ(p2, "-le"))
        return(int1<=int2);
    synbad("unknown operator ",p2);
    return 0;
}
/*
* 文件访问测试
*/
int tio(char *a, int  f)
{

    f = open(a, f);
    if (f>=0) {
        close(f);
        return(1);
    }
    return(0);
}
/*
* 文件类型测试
*/
int ftype(char *f)
{
    struct stat statb;

    if(stat(f,&statb)<0)
        return(0);
    if((statb.st_mode&S_IFMT)==S_IFDIR)
        return(DIR);
    return(FIL);
}
/*
* 文件大小测试
*/
int fsizep(char *f)
{
    struct stat statb;
    if(stat(f,&statb)<0)
        return(0);
    return(statb.st_size>0);
}
/*
* 打印错误信息并退出
*/
void synbad(char *s1, char *s2)
{
    write(2, "if: ", 6);
    write(2, s1, strlen(s1));
    write(2, s2, strlen(s2));
    write(2, "\n", 1);
    exit(1);
}
/*
* 字符串长度测试
*/
int length(char *s)
{
    char *es=s;
    while(*es++);
    return((int)(es-s-1));
}
/*
* 执行命令
* earg 是终止参数
*/
int doex(char *earg)
{
    static char ncom[]="/usr/bin/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    char *p=av[ap];
    char **v=av+ap;
    int i=0;
    char c;

    if (p == 0)
        return 0;

    if (earg != 0) {
        while (*v != 0 && !EQ(*v,earg))
            v++;
        if (*v == 0)
            return 1;
        else
            *v=0;
    }

    execv(p, av+ap);
    while((c=p[i])) {
        ncom[9+i++] = c;
    }
    ncom[9+i] = &#39;\0&#39;;
    execv(ncom+4, av+ap);
    execv(ncom, av+ap);
    return 127;
}
goto.c
复制内容到剪贴板
代码:
#include <unistd.h>

int    offset=0;
int getlin(char *s);
int compar(char *s1, char *s2);
int getC(void);

int main(int argc, char **argv)
{
    char line[64];

    if (argc<2 || isatty(0)) {
        write(1, "goto error\n", 11);
        lseek(0, 0, 2);
        return 1;
    }
    lseek(0, 0, 0);
    do {
        if (getlin(line)) {
            write(1, "label not found\n", 16);
            return 1;
        }
    } while (compar(line, argv[1]));
    lseek(0, offset, 0);
    return 0;
}

int getlin(char *s)
{
    int ch, i;
    i = 0;

    while ((ch=getC())!=&#39;\0&#39; && ch!=&#39;:&#39;) {
        while(ch!=&#39;\n&#39; && ch!=&#39;\0&#39;)
            ch = getC();
    }
    if (ch==&#39;\0&#39;)
        return(1);
    while ((ch=getC())==&#39; &#39;);
    while (ch!=&#39; &#39; && ch!=&#39;\n&#39; && ch!=&#39;\0&#39;) {
        s[i++] = ch;
        ch = getC();
    }
    while(ch != &#39;\n&#39;)
        ch = getC();
    s[i] = &#39;\0&#39;;
    return(0);
}

int compar(char *s1, char *s2)
{
    int i;
    i = 0;

    while(1) {
        if(s1[i] != s2[i])
            return(1);
        if (s1[i++] == &#39;\0&#39;)
            return(0);
    }
}

int getC(void)
{
    char cc;
    offset++;

    if(read(0, &cc, 1))
        return cc;
    else
        return 0;
}
Very Idiotic Person

TOP

发新话题