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;
}