13 smsh——编写自己的shell

1、什么是shell脚本语言

Unix的引导程序和很多管理程序都使用shell脚本,shell是一个变成语言解释器,这个解释器解释从键盘输入的命令,也解释存储在脚本中的命令序列。shell脚本是一个包含一系列命令的文件。运行一个脚本就是运行这个文件中的每个命令。可以用一个shell脚本在一次请求中来执行多个命令。

shell脚本中元素:命令、变量、用户输入、控制、环境。

2、smsh1.c

对自编shell的第一个改进是添加命令行解析的功能。比如:find /home -name core -mtime +3 -print,然后由解析器将命令行拆成字符串数组传给execvp执行。

  • next_cmd:从输入流读取下一条命令,调用malloc来分配内存以接受任意参数个数的命令行。
  • splitline:将一个字符串分解为字符串数组,并返回这个数组,调用malloc来分配内存以接受任意参数个数的命令行。
  • execute:使用fork、execvp、wait来运行一个命令

相比于psh2,smsh1好用很多,改进的方面包含:

  • 一行多个命令
  • 后台进程
  • 退出命令

3、smsh2.c

在shell脚本中增加对if then...else...fi的解析。if语句的工作流程:

  • shell运行if之后的命令
  • shell检查命令的exit状态
  • exit的状态为0为成功,非0为失败
  • 如果成功,shell执行then部分的代码
  • 如果失败,shell执行else部分的代码
  • 关键字fi标识if块结束

使用if_state表示进入if块之后的代码状态,总共有三种状态:NEUTRAL,WANT_THEN,THEN_BLOCK,if语句及其之前的状态都是NEUTRAL中立区,如果if命令执行返回0,状态变为WANT_THEN,执行then后面的命令,否则变为THEN_BLOCK,之后遇到fi,状态回到NEUTRAL中立区。

  • is_control_command:返回一个boolean变量告诉process这条命令是if控制语句还是一条可执行命令
  • do_control_command:处理关键字if、then、fi,每个关键字都是区域的界标,更新状态变量if_state并执行必要的操作
  • ok_to_execute:根据当前的状态和条件命令的结果返回一个boolean值,说明能否执行当前命令

4、smsh3.c

shell包含两类变量:局部变量和环境变量。shell对变量的操作如下:

  • 赋值操作:var=value
  • 引用:$var
  • 删除:unset var
  • 输入:read var
  • 列出变量:set
  • 全局化:export var

增加变量命令buit-in,将变量存入结构体var,VLstore用来增加或更新变量var=val,VLookup取得var的值,VList输出列表到stdout。

struct var {
        char *str;        /* name=val string    */
        int  global;        /* a boolean        */
    };

static struct var tab[MAXVARS];    

5、smsh4.c

在smsh中增加环境处理,进行环境个性化设置。环境是每个程序都可以存取的一个字符串数组,每个数组中的字符串都以var=value这样的形式出现,数组的地址被存放在一个名为environ的全局变量里。环境就是environ指向的字符串数组,读环境就是读这个字符串数组,改变环境就是改变字符串、改变这个数组中的指针或者将这个全局指针指向其他数组。

在smsh中增加环境处理具体实现:

  • 存取环境变量:已经知道环境的结构,而且还有一组函数向变量列表添加变量。当shell开始运行的时候,使用函数VLenviron2table环境中的变量environ将被复制到自己的变量列表里tab,一旦这些值被复制到变量列表里,就能用set命令和赋值命令来查看和修改这些变量了。
  • 改变环境:修改环境最简单的方法是构建一个全新的列表,使用VLtable2environ将tab中的环境变量全部复制到envtab中,所以envtab这个列表包含了shell中的所有变量,然后将全局指针environ指向这个列表,调用exec,内核将这些设置复制到新的程序中。

6、具体实现程序

smsh1.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<sys/wait.h>
#define DFL_PROMPT ">"
#define YES 1
#define NO 0
#define is_delim(x) ((x)==' '||(x)=='\t')
void setup()
{
    signal(SIGINT,SIG_IGN);
    signal(SIGQUIT,SIG_IGN);
}
void fatal(char *s1,char *s2,int n)
{
    fprintf(stderr,"Error:%s,%s\n",s1,s2);
    exit(n);
}
int execute(char *argv[])
{
    int pid;
    int child_info=-1;
    if(argv[0]==NULL)
        return 0;
    if((pid=fork())==-1)
        perror("fork");
    else if(pid==0)
    {
        signal(SIGINT,SIG_DFL);
        signal(SIGQUIT,SIG_DFL);
        execvp(argv[0],argv);
        perror("cannot execute command");
        exit(1);
    }
    else
    {
        if(wait(&child_info)==-1)
            perror("wait");
    }
    return child_info;
}
void *emalloc(size_t n)
{
    void *rv;
    if((rv=malloc(n))==NULL)
        fatal("out of memory","",1);
    return rv;
}
void *erealloc(void *p,size_t n)
{
    void *rv;
    if((rv=realloc(p,n))==NULL)
        fatal("realloc() failed","",1);
    return rv;
}
void freelist(char **list)
{
    char **cp=list;
    while(*cp)
        free(*cp++);
    free(list);
}
char *next_cmd(char *prompt,FILE *fp)
{
    char *buf;
    int bufspace=0;
    int pos=0;
    char c;
    printf("%s",prompt);
    while((c=getc(fp))!=EOF)
    {
        //需要空间时申请空间
        if(pos+1>=bufspace)
        {
            if(bufspace==0)  //第一次申请空间
                buf=emalloc(BUFSIZ);
            else  //扩展空间
                buf=erealloc(buf,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
        }
        if(c=='\n')
            break;
        buf[pos++]=c;
    }
    if(c==EOF&&pos==0)
        return NULL;
    buf[pos]='\0';
    return buf;
}
char *newstr(char *s,int l)
{
    char *rv=emalloc(l+1);
    rv[l]='\0';
    strncpy(rv,s,l);
    return rv;
}
char **splitline(char *line)
{
    char **args;
    int spots=0;
    int bufspace=0;
    int argnum=0;
    char *cp=line;
    char *start;
    int len;
    if(line==NULL)
        return NULL;
    args=emalloc(BUFSIZ);
    bufspace=BUFSIZ;
    spots=BUFSIZ/sizeof(char *);
    while(*cp!='\0')
    {
        while(is_delim(*cp))
            cp++;
        if(*cp=='\0')
            break;
        //make sure the array has room (+1 for NULL)
        if(argnum+1>=spots)
        {
            args=erealloc(args,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
            spots+=(BUFSIZ/sizeof(char *));
        }
        start=cp;
        len=1;
        while(*++cp!='\0'&&!(is_delim(*cp)))
            len++;
        args[argnum++]=newstr(start,len);
    }
    args[argnum]=NULL;
    return args;
}
int main()
{
    char *cmdline,*prompt,**arglist;
    int result;
    prompt=DFL_PROMPT;
    setup();
    while((cmdline=next_cmd(prompt,stdin))!=NULL)
    {
        if((arglist=splitline(cmdline))!=NULL)
        {
            result=execute(arglist);
            freelist(arglist);
        }
        free(cmdline);
    }
    return 0;
}

smsh2.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<sys/wait.h>
#define DFL_PROMPT ">"
#define YES 1
#define NO 0
#define is_delim(x) ((x)==' '||(x)=='\t')
enum states {NEUTRAL,WANT_THEN,THEN_BLOCK};
enum results {SUCCESS,FAIL};
static int if_state=NEUTRAL;
static int if_result=SUCCESS;
static int last_state=0;
void setup()
{
    signal(SIGINT,SIG_IGN);
    signal(SIGQUIT,SIG_IGN);
}
void fatal(char *s1,char *s2,int n)
{
    fprintf(stderr,"Error:%s,%s\n",s1,s2);
    exit(n);
}
int execute(char *argv[])
{
    int pid;
    int child_info=-1;
    if(argv[0]==NULL)
        return 0;
    if((pid=fork())==-1)
        perror("fork");
    else if(pid==0)
    {
        signal(SIGINT,SIG_DFL);
        signal(SIGQUIT,SIG_DFL);
        execvp(argv[0],argv);
        perror("cannot execute command");
        exit(1);
    }
    else
    {
        if(wait(&child_info)==-1)
            perror("wait");
    }
    return child_info;
}
void *emalloc(size_t n)
{
    void *rv;
    if((rv=malloc(n))==NULL)
        fatal("out of memory","",1);
    return rv;
}
void *erealloc(void *p,size_t n)
{
    void *rv;
    if((rv=realloc(p,n))==NULL)
        fatal("realloc() failed","",1);
    return rv;
}
void freelist(char **list)
{
    char **cp=list;
    while(*cp)
        free(*cp++);
    free(list);
}
char *next_cmd(char *prompt,FILE *fp)
{
    char *buf;
    int bufspace=0;
    int pos=0;
    char c;
    printf("%s",prompt);
    while((c=getc(fp))!=EOF)
    {
        //需要空间时申请空间
        if(pos+1>=bufspace)
        {
            if(bufspace==0)  //第一次申请空间
                buf=emalloc(BUFSIZ);
            else  //扩展空间
                buf=erealloc(buf,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
        }
        if(c=='\n')
            break;
        buf[pos++]=c;
    }
    if(c==EOF&&pos==0)
        return NULL;
    buf[pos]='\0';
    return buf;
}
char *newstr(char *s,int l)
{
    char *rv=emalloc(l+1);
    rv[l]='\0';
    strncpy(rv,s,l);
    return rv;
}
char **splitline(char *line)
{
    char **args;
    int spots=0;
    int bufspace=0;
    int argnum=0;
    char *cp=line;
    char *start;
    int len;
    if(line==NULL)
        return NULL;
    args=emalloc(BUFSIZ);
    bufspace=BUFSIZ;
    spots=BUFSIZ/sizeof(char *);
    while(*cp!='\0')
    {
        while(is_delim(*cp))
            cp++;
        if(*cp=='\0')
            break;
        //make sure the array has room (+1 for NULL)
        if(argnum+1>=spots)
        {
            args=erealloc(args,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
            spots+=(BUFSIZ/sizeof(char *));
        }
        start=cp;
        len=1;
        while(*++cp!='\0'&&!(is_delim(*cp)))
            len++;
        args[argnum++]=newstr(start,len);
    }
    args[argnum]=NULL;
    return args;
}
int syn_err(char *msg)
{
    if_state=NEUTRAL;
    fprintf(stderr,"syntax error:%s\n",msg);
    return -1;
}
int is_control_command(char *s)
{
    return (strcmp(s,"if")==0||strcmp(s,"then")==0||strcmp(s,"fi")==0);
}
int do_control_command(char **args)
{
    char *cmd=args[0];
    int rv=-1;
    if(strcmp(cmd,"if")==0)
    {
        if(if_state!=NEUTRAL)
            rv=syn_err("if unexpected");
        else
        {
            last_state=process(args+1);
            if_result=(last_state==0?SUCCESS:FAIL);
            if_state=WANT_THEN;
            rv=0;
        }
    }
    else if(strcmp(cmd,"then")==0)
    {
        if(if_state!=WANT_THEN)
            rv=syn_err("then unexpected");
        else
        {
            if_state=THEN_BLOCK;
            rv=0;
        }
    }
    else if(strcmp(cmd,"fi")==0)
    {
        if(if_state!=THEN_BLOCK)
            rv=syn_err("fi unexpected");
        else
        {
            if_state=NEUTRAL;
            rv=0;
        }
    }
    else
        fatal("internal error processing:",cmd,2);
    return rv;
}
int ok_to_execute()
{
    int rv=1;
    if(if_state==WANT_THEN)
    {
        syn_err("then expected");
        rv=0;
    }
    else if(if_state==THEN_BLOCK&&if_result==SUCCESS)
        rv=1;
    else if(if_state==THEN_BLOCK&&if_result==FAIL)
        rv=0;
    return rv;
}
int process(char **args)
{
    int rv=0;
    if(args[0]==NULL)
        rv=0;
    else if(is_control_command(args[0]))
        rv=do_control_command(args);
    else if(ok_to_execute())
        rv=execute(args);
    return rv;
}
int main()
{
    char *cmdline,*prompt,**arglist;
    int result;
    prompt=DFL_PROMPT;
    setup();
    while((cmdline=next_cmd(prompt,stdin))!=NULL)
    {
        if((arglist=splitline(cmdline))!=NULL)
        {
            result=process(arglist);
            freelist(arglist);
        }
        free(cmdline);
    }
    return 0;
}

smsh3.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<sys/wait.h>
#include<ctype.h>
#define DFL_PROMPT ">"
#define YES 1
#define NO 0
#define is_delim(x) ((x)==' '||(x)=='\t')
#define	MAXVARS	200
struct var {
		char *str;		/* name=val string	*/
		int  global;		/* a boolean		*/
	};

static struct var tab[MAXVARS];			/* the table	*/
enum states {NEUTRAL,WANT_THEN,THEN_BLOCK};
enum results {SUCCESS,FAIL};
static int if_state=NEUTRAL;
static int if_result=SUCCESS;
static int last_state=0;
void setup()
{
    signal(SIGINT,SIG_IGN);
    signal(SIGQUIT,SIG_IGN);
}
void fatal(char *s1,char *s2,int n)
{
    fprintf(stderr,"Error:%s,%s\n",s1,s2);
    exit(n);
}
int execute(char *argv[])
{
    int pid;
    int child_info=-1;
    if(argv[0]==NULL)
        return 0;
    if((pid=fork())==-1)
        perror("fork");
    else if(pid==0)
    {
        signal(SIGINT,SIG_DFL);
        signal(SIGQUIT,SIG_DFL);
        execvp(argv[0],argv);
        perror("cannot execute command");
        exit(1);
    }
    else
    {
        if(wait(&child_info)==-1)
            perror("wait");
    }
    return child_info;
}
void *emalloc(size_t n)
{
    void *rv;
    if((rv=malloc(n))==NULL)
        fatal("out of memory","",1);
    return rv;
}
void *erealloc(void *p,size_t n)
{
    void *rv;
    if((rv=realloc(p,n))==NULL)
        fatal("realloc() failed","",1);
    return rv;
}
void freelist(char **list)
{
    char **cp=list;
    while(*cp)
        free(*cp++);
    free(list);
}
char *next_cmd(char *prompt,FILE *fp)
{
    char *buf;
    int bufspace=0;
    int pos=0;
    char c;
    printf("%s",prompt);
    while((c=getc(fp))!=EOF)
    {
        //需要空间时申请空间
        if(pos+1>=bufspace)
        {
            if(bufspace==0)  //第一次申请空间
                buf=emalloc(BUFSIZ);
            else  //扩展空间
                buf=erealloc(buf,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
        }
        if(c=='\n')
            break;
        buf[pos++]=c;
    }
    if(c==EOF&&pos==0)
        return NULL;
    buf[pos]='\0';
    return buf;
}
char *newstr(char *s,int l)
{
    char *rv=emalloc(l+1);
    rv[l]='\0';
    strncpy(rv,s,l);
    return rv;
}
char **splitline(char *line)
{
    char **args;
    int spots=0;
    int bufspace=0;
    int argnum=0;
    char *cp=line;
    char *start;
    int len;
    if(line==NULL)
        return NULL;
    args=emalloc(BUFSIZ);
    bufspace=BUFSIZ;
    spots=BUFSIZ/sizeof(char *);
    while(*cp!='\0')
    {
        while(is_delim(*cp))
            cp++;
        if(*cp=='\0')
            break;
        //make sure the array has room (+1 for NULL)
        if(argnum+1>=spots)
        {
            args=erealloc(args,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
            spots+=(BUFSIZ/sizeof(char *));
        }
        start=cp;
        len=1;
        while(*++cp!='\0'&&!(is_delim(*cp)))
            len++;
        args[argnum++]=newstr(start,len);
    }
    args[argnum]=NULL;
    return args;
}
int syn_err(char *msg)
{
    if_state=NEUTRAL;
    fprintf(stderr,"syntax error:%s\n",msg);
    return -1;
}
int is_control_command(char *s)
{
    return (strcmp(s,"if")==0||strcmp(s,"then")==0||strcmp(s,"fi")==0);
}
int do_control_command(char **args)
{
    char *cmd=args[0];
    int rv=-1;
    if(strcmp(cmd,"if")==0)
    {
        if(if_state!=NEUTRAL)
            rv=syn_err("if unexpected");
        else
        {
            last_state=process(args+1);
            if_result=(last_state==0?SUCCESS:FAIL);
            if_state=WANT_THEN;
            rv=0;
        }
    }
    else if(strcmp(cmd,"then")==0)
    {
        if(if_state!=WANT_THEN)
            rv=syn_err("then unexpected");
        else
        {
            if_state=THEN_BLOCK;
            rv=0;
        }
    }
    else if(strcmp(cmd,"fi")==0)
    {
        if(if_state!=THEN_BLOCK)
            rv=syn_err("fi unexpected");
        else
        {
            if_state=NEUTRAL;
            rv=0;
        }
    }
    else
        fatal("internal error processing:",cmd,2);
    return rv;
}
int ok_to_execute()
{
    int rv=1;
    if(if_state==WANT_THEN)
    {
        syn_err("then expected");
        rv=0;
    }
    else if(if_state==THEN_BLOCK&&if_result==SUCCESS)
        rv=1;
    else if(if_state==THEN_BLOCK&&if_result==FAIL)
        rv=0;
    return rv;
}

char * new_string( char *name, char *val )
{
	char	*retval;

	retval = malloc( strlen(name) + strlen(val) + 2 );
	if ( retval != NULL )
		sprintf(retval, "%s=%s", name, val );
	return retval;
}
static struct var * find_item( char *name , int first_blank )
{
	int	i;
	int	len = strlen(name);
	char	*s;

	for( i = 0 ; i<MAXVARS && tab[i].str != NULL ; i++ )
	{
		s = tab[i].str;
		if ( strncmp(s,name,len) == 0 && s[len] == '=' ){
			return &tab[i];
		}
	}
	if ( i < MAXVARS && first_blank )
		return &tab[i];
	return NULL;
}
void VLlist()
{
	int	i;
	for(i = 0 ; i<MAXVARS && tab[i].str != NULL ; i++ )
	{
		if ( tab[i].global )
			printf("  * %s\n", tab[i].str);
		else
			printf("    %s\n", tab[i].str);
	}
}
int VLstore( char *name, char *val )
{
	struct var *itemp;
	char	*s;
	int	rv = 1;
	/* find spot to put it              and make new string */
	if ((itemp=find_item(name,1))!=NULL && (s=new_string(name,val))!=NULL)
	{
		if ( itemp->str )		/* has a val?	*/
			free(itemp->str);	/* y: remove it	*/
		itemp->str = s;
		rv = 0;				/* ok! */
	}
	return rv;
}
int VLexport( char *name )
{
	struct var *itemp;
	int	rv = 1;

	if ( (itemp = find_item(name,0)) != NULL ){
		itemp->global = 1;
		rv = 0;
	}
	else if ( VLstore(name, "") == 1 )
		rv = VLexport(name);
	return rv;
}
int okname(char *str)
{
    char *cp;
    for(cp=str;*cp;cp++)
    {
        if((isdigit(*cp)&&cp==str)||!(isalnum(*cp)||*cp=='_'))
            return 0;
    }
    return (cp!=str);
}
int assign(char *str)
{
    char *cp;
    int rv;
    cp=strchr(str,'=');
    *cp='\0';
    rv=(okname(str)?VLstore(str,cp+1):-1);
    *cp='=';
    return rv;
}
int builtin_command(char **args,int *resultp)
{
    int rv=0;
    if(strcmp(args[0],"set")==0)
    {
        VLlist();
        *resultp=0;
        rv=1;
    }
    else if(strchr(args[0],'=')!=NULL)
    {
        *resultp=assign(args[0]);
        if(*resultp!=-1)
            rv=1;
    }
    else if(strcmp(args[0],"export")==0)
    {
        if(args[1]!=NULL&&okname(args[1]))
            *resultp=VLexport(args[1]);
        else
            *resultp=1;
        rv=1;
    }
    return rv;
}
int process(char **args)
{
    int rv=0;
    if(args[0]==NULL)
        rv=0;
    else if(is_control_command(args[0]))
        rv=do_control_command(args);
    else if(ok_to_execute())
    {
        if(!builtin_command(args,&rv))
            rv=execute(args);
    }
    return rv;
}
int main()
{
    char *cmdline,*prompt,**arglist;
    int result;
    prompt=DFL_PROMPT;
    setup();
    while((cmdline=next_cmd(prompt,stdin))!=NULL)
    {
        if((arglist=splitline(cmdline))!=NULL)
        {
            result=process(arglist);
            freelist(arglist);
        }
        free(cmdline);
    }
    return 0;
}

smsh4.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<sys/wait.h>
#include<ctype.h>
#define DFL_PROMPT ">"
#define YES 1
#define NO 0
#define is_delim(x) ((x)==' '||(x)=='\t')
#define	MAXVARS	200
struct var {
		char *str;		/* name=val string	*/
		int  global;		/* a boolean		*/
	};
static struct var tab[MAXVARS];			/* the table	*/
enum states {NEUTRAL,WANT_THEN,THEN_BLOCK};
enum results {SUCCESS,FAIL};
static int if_state=NEUTRAL;
static int if_result=SUCCESS;
static int last_state=0;
extern char **environ;
char * new_string( char *name, char *val )
{
	char	*retval;

	retval = malloc( strlen(name) + strlen(val) + 2 );
	if ( retval != NULL )
		sprintf(retval, "%s=%s", name, val );
	return retval;
}
static struct var * find_item( char *name , int first_blank )
{
	int	i;
	int	len = strlen(name);
	char	*s;

	for( i = 0 ; i<MAXVARS && tab[i].str != NULL ; i++ )
	{
		s = tab[i].str;
		if ( strncmp(s,name,len) == 0 && s[len] == '=' ){
			return &tab[i];
		}
	}
	if ( i < MAXVARS && first_blank )
		return &tab[i];
	return NULL;
}
void VLlist()
{
	int	i;
	for(i = 0 ; i<MAXVARS && tab[i].str != NULL ; i++ )
	{
		if ( tab[i].global )
			printf("  * %s\n", tab[i].str);
		else
			printf("    %s\n", tab[i].str);
	}
}
int VLstore( char *name, char *val )
{
	struct var *itemp;
	char	*s;
	int	rv = 1;
	/* find spot to put it              and make new string */
	if ((itemp=find_item(name,1))!=NULL && (s=new_string(name,val))!=NULL)
	{
		if ( itemp->str )		/* has a val?	*/
			free(itemp->str);	/* y: remove it	*/
		itemp->str = s;
		rv = 0;				/* ok! */
	}
	return rv;
}
int VLexport( char *name )
{
	struct var *itemp;
	int	rv = 1;

	if ( (itemp = find_item(name,0)) != NULL ){
		itemp->global = 1;
		rv = 0;
	}
	else if ( VLstore(name, "") == 1 )
		rv = VLexport(name);
	return rv;
}
int VLenviron2table(char *env[])
{
    int i;
    char *newstring;
    for(i=0;env[i]!=NULL;i++)
    {
        if(i==MAXVARS)
            return 0;
        newstring=malloc(1+strlen(env[i]));
        if(newstring==NULL)
            return 0;
        strcpy(newstring,env[i]);
        tab[i].str=newstring;
        tab[i].global=1;
    }
    while(i<MAXVARS)
    {
        tab[i].str=NULL;
        tab[i++].global=0;
    }
    return 1;
}
char **VLtable2environ()
{
    int i,j,n=0;
    char **envtab;
    for(i=0;i<MAXVARS&&tab[i].str!=NULL;i++)
        if(tab[i].global==1)
            n++;
    envtab=(char **)malloc((n+1)*sizeof(char *));
    if(envtab==NULL)
        return NULL;
    for(i=0,j=0;i<MAXVARS&&tab[i].str!=NULL;i++)
        if(tab[i].global==1)
            envtab[j++]=tab[i].str;
    envtab[j]=NULL;
    return envtab;
}
void setup()
{
    VLenviron2table(environ);
    signal(SIGINT,SIG_IGN);
    signal(SIGQUIT,SIG_IGN);
}
void fatal(char *s1,char *s2,int n)
{
    fprintf(stderr,"Error:%s,%s\n",s1,s2);
    exit(n);
}
int execute(char *argv[])
{
    int pid;
    int child_info=-1;
    if(argv[0]==NULL)
        return 0;
    if((pid=fork())==-1)
        perror("fork");
    else if(pid==0)
    {
        environ=VLtable2environ();
        signal(SIGINT,SIG_DFL);
        signal(SIGQUIT,SIG_DFL);
        execvp(argv[0],argv);
        perror("cannot execute command");
        exit(1);
    }
    else
    {
        if(wait(&child_info)==-1)
            perror("wait");
    }
    return child_info;
}
void *emalloc(size_t n)
{
    void *rv;
    if((rv=malloc(n))==NULL)
        fatal("out of memory","",1);
    return rv;
}
void *erealloc(void *p,size_t n)
{
    void *rv;
    if((rv=realloc(p,n))==NULL)
        fatal("realloc() failed","",1);
    return rv;
}
void freelist(char **list)
{
    char **cp=list;
    while(*cp)
        free(*cp++);
    free(list);
}
char *next_cmd(char *prompt,FILE *fp)
{
    char *buf;
    int bufspace=0;
    int pos=0;
    char c;
    printf("%s",prompt);
    while((c=getc(fp))!=EOF)
    {
        //需要空间时申请空间
        if(pos+1>=bufspace)
        {
            if(bufspace==0)  //第一次申请空间
                buf=emalloc(BUFSIZ);
            else  //扩展空间
                buf=erealloc(buf,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
        }
        if(c=='\n')
            break;
        buf[pos++]=c;
    }
    if(c==EOF&&pos==0)
        return NULL;
    buf[pos]='\0';
    return buf;
}
char *newstr(char *s,int l)
{
    char *rv=emalloc(l+1);
    rv[l]='\0';
    strncpy(rv,s,l);
    return rv;
}
char **splitline(char *line)
{
    char **args;
    int spots=0;
    int bufspace=0;
    int argnum=0;
    char *cp=line;
    char *start;
    int len;
    if(line==NULL)
        return NULL;
    args=emalloc(BUFSIZ);
    bufspace=BUFSIZ;
    spots=BUFSIZ/sizeof(char *);
    while(*cp!='\0')
    {
        while(is_delim(*cp))
            cp++;
        if(*cp=='\0')
            break;
        //make sure the array has room (+1 for NULL)
        if(argnum+1>=spots)
        {
            args=erealloc(args,bufspace+BUFSIZ);
            bufspace+=BUFSIZ;
            spots+=(BUFSIZ/sizeof(char *));
        }
        start=cp;
        len=1;
        while(*++cp!='\0'&&!(is_delim(*cp)))
            len++;
        args[argnum++]=newstr(start,len);
    }
    args[argnum]=NULL;
    return args;
}
int syn_err(char *msg)
{
    if_state=NEUTRAL;
    fprintf(stderr,"syntax error:%s\n",msg);
    return -1;
}
int is_control_command(char *s)
{
    return (strcmp(s,"if")==0||strcmp(s,"then")==0||strcmp(s,"fi")==0);
}
int do_control_command(char **args)
{
    char *cmd=args[0];
    int rv=-1;
    if(strcmp(cmd,"if")==0)
    {
        if(if_state!=NEUTRAL)
            rv=syn_err("if unexpected");
        else
        {
            last_state=process(args+1);
            if_result=(last_state==0?SUCCESS:FAIL);
            if_state=WANT_THEN;
            rv=0;
        }
    }
    else if(strcmp(cmd,"then")==0)
    {
        if(if_state!=WANT_THEN)
            rv=syn_err("then unexpected");
        else
        {
            if_state=THEN_BLOCK;
            rv=0;
        }
    }
    else if(strcmp(cmd,"fi")==0)
    {
        if(if_state!=THEN_BLOCK)
            rv=syn_err("fi unexpected");
        else
        {
            if_state=NEUTRAL;
            rv=0;
        }
    }
    else
        fatal("internal error processing:",cmd,2);
    return rv;
}
int ok_to_execute()
{
    int rv=1;
    if(if_state==WANT_THEN)
    {
        syn_err("then expected");
        rv=0;
    }
    else if(if_state==THEN_BLOCK&&if_result==SUCCESS)
        rv=1;
    else if(if_state==THEN_BLOCK&&if_result==FAIL)
        rv=0;
    return rv;
}
int okname(char *str)
{
    char *cp;
    for(cp=str;*cp;cp++)
    {
        if((isdigit(*cp)&&cp==str)||!(isalnum(*cp)||*cp=='_'))
            return 0;
    }
    return (cp!=str);
}
int assign(char *str)
{
    char *cp;
    int rv;
    cp=strchr(str,'=');
    *cp='\0';
    rv=(okname(str)?VLstore(str,cp+1):-1);
    *cp='=';
    return rv;
}
int builtin_command(char **args,int *resultp)
{
    int rv=0;
    if(strcmp(args[0],"set")==0)
    {
        VLlist();
        *resultp=0;
        rv=1;
    }
    else if(strchr(args[0],'=')!=NULL)
    {
        *resultp=assign(args[0]);
        if(*resultp!=-1)
            rv=1;
    }
    else if(strcmp(args[0],"export")==0)
    {
        if(args[1]!=NULL&&okname(args[1]))
            *resultp=VLexport(args[1]);
        else
            *resultp=1;
        rv=1;
    }
    return rv;
}
int process(char **args)
{
    int rv=0;
    if(args[0]==NULL)
        rv=0;
    else if(is_control_command(args[0]))
        rv=do_control_command(args);
    else if(ok_to_execute())
    {
        if(!builtin_command(args,&rv))
            rv=execute(args);
    }
    return rv;
}
int main()
{
    char *cmdline,*prompt,**arglist;
    int result;
    prompt=DFL_PROMPT;
    setup();
    while((cmdline=next_cmd(prompt,stdin))!=NULL)
    {
        if((arglist=splitline(cmdline))!=NULL)
        {
            result=process(arglist);
            freelist(arglist);
        }
        free(cmdline);
    }
    return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值