📄 utility.c
字号:
// 支持外部命令#include "myshell.h"
int back_bat=0; // 标志既是后台运行,又是批处理;值为1有效。
int output_num=0; // 批处理的输出重定向个数
char batchfile[MAX_PATH] ; // 当前的批处理文件
int bat_line=0;// 批处理的命令行数
int isbat=0;// 批处理标志int letter; // used in my_strtok( ) Error( )char *open; // used in my_strtok( ) Error( )
/* ******************************* 辅助函数 ******************************* */
/* Function "my_strtok" : used to <1> token the input command line(stored in buf[]) into args[],
<2> record background execute,argc,etc in states[]
<3> record the indirection files and outdirection filesget */
int my_strtok(char *buf,char **args,int *states,Redirect *Inputs,Redirect *Outputs) // InPut和OutPuts记录重定向
{
int i,j,n,m, flag,argc,errortype; // flag是空白标记;argc是参数个数(不包括重定向和后台运行)
char c ;
states[0]=states[1]=states[2]=states[3]=states[4]=0;// states[0]是后台运行标志;states[1]是输入重定向个数;states[2]是输出重定向个数; //states[3]是参数个数; states[4]标记输入重定向在键盘输入之前;
errortype=letter=argc=0; args[0]=NULL; open=NULL;// open 是打开方式;
flag=1;
i=m=n=-1;
while(buf[++i]&&buf[i]!='#') //扫描命令行, 容许用户把 '#' 用于注释
{
c=buf[i];
switch(c) // 字符解析
{
case '<': letter++; if(flag==0)
{
flag=1;
buf[i]='\0';
}
open="<"; // "r" opentype
while(buf[++i]==' '|| buf[i]=='\t'); // // 跳过多个连续的空格
if(buf[i]<32|| buf[i]=='#' ) // invlid argument '<', without inputfile!
{ errortype=Error(1,NULL,NULL,NULL,"<");// invlid argument '<', without inputfile!
break;
}
else if(buf[i]=='&'|| buf[i]=='<'|| buf[i]=='>'|| buf[i]=='|'|| buf[i]==';') // can not be <& <; << <> <|
{
letter++;
errortype=Error(2,NULL,NULL,NULL,buf+i);
break;
}
if(argc<2)
states[4]=1;
m++;
i--;
break;
case '>': letter++;
if(flag==0)
{ flag=1;
buf[i]='\0';
} n++;
if(buf[i+1]=='>')
{ buf[++i]='\0';
//n++;
open=">>"; // "a" opentype
}
else {
// n++;
open=">"; // "w" opentype
}
while(buf[++i]==' '|| buf[i]=='\t'); // 跳过多个连续的空格
if(buf[i]<32|| buf[i]=='#' )
{
errortype=Error(1,NULL,NULL,NULL,NULL);
break;
}
else if(buf[i]=='&'|| buf[i]=='<'|| buf[i]=='>'|| buf[i]=='|' || buf[i]==';') // can not be >& <; >< <|
{
letter++;
errortype=Error(2,NULL,NULL,NULL,buf+i);
break;
}
i--;
break;
case '&': letter++;
if(flag==0)
{ flag=1;
buf[i]='\0';
}
if(states[0]) { errortype= Error(0,NULL,NULL,NULL,"Format Error: argument '&' occurs more than once!");
break;
}
states[0]=1;
break;
case ' ':
case '\t': if(flag==0)
{
flag=1;
buf[i]='\0';
}
while(buf[++i]==' '|| buf[i]=='\t'); // 跳过多个连续的空格
i--;
break;
case '\n':
case '\r': buf[i]='\0';
i--;
break;
default: letter++;
if(flag)
{ flag=0; if(open&&m<=MAX_OPEN&&n<=MAX_OPEN)
{ if(m==MAX_OPEN)// too many input redirections //////// errortype=Error(5,NULL,NULL,NULL,"input"); else if(n==MAX_OPEN)// too many output redirections //////// errortype=Error(5,NULL,NULL,NULL,"output"); else if( !strcmp(open,"<" ) )
Inputs[m].filename=buf+i;
else if( !strcmp(open,">>" ) ) { strcpy(Outputs[n].opentype,"a"); strcpy(Outputs[n].open,">>"); Outputs[n].filename=buf+i; } else if( !strcmp(open,">" ) ) { strcpy(Outputs[n].opentype,"w"); strcpy(Outputs[n].open,">");
Outputs[n].filename=buf+i; }
open=NULL; }
else args[argc++]=buf+i;
}
if(c=='\\' &&buf[i+1]==' ') // 转义字符 e.g. "a\ b" means "a b" in filename or directoryname { buf[i]=' '; if( ! isspace(buf[i+2])) { j=i+1; while( buf[++j]) buf[j-1]=buf[j]; } }
} // end switch
} // end for loop
args[argc]=NULL; // args end with NULL
states[1]=m+1;// 0,12,...,m
states[2]=n+1;// 0,1,2,...,n
states[3]=argc;
if(errortype||(argc==0&&letter)) // if there's anything there Error(0,NULL,NULL,NULL,"Warning: nothing will be executed!");//
return errortype; // errortype==0 is ok ;
}
/* Function "my_shell" : keep reading a line from stdin or inputfile and call "Execute()" to execute the command line. */
int my_shell(FILE *inputfile,const Redirect *Outputs,const int *states) //
{
FILE *outputfile;
char filepath[MAX_PATH];
char buf[MAX_BUFFER];
int done=0; //
if(Outputs)
{
get_fullpath(filepath,Outputs->filename);
outputfile=freopen(filepath,Outputs->opentype,stdout);
if(outputfile==NULL)
{ Error(-6,NULL,NULL,NULL,Outputs->filename);
return -2;///
}
fprintf(stderr,"\nThe results will be writen into file \"%s\".\n",Outputs->filename);
}
bat_line=0;
do // /* keep reading input until "quit" command or eof of redirected input */
{ /* get command line from input */
if (inputfile==stdin&&Outputs==NULL) ///////////////////////////////
fprintf(stderr,"\n[%s@%s] :) ",getenv("USERNAME"),getenv("PWD")); // write prompt
if (fgets(buf, MAX_BUFFER, inputfile)) // read a line
{
bat_line++;
done=Execute(buf); //
if(done==1) // "quit" command is executed
{
if(Outputs)
freopen("/dev/tty", "w", stdout);
break;//exit(0);
}
}
} while (!feof(inputfile)); // do ... while( );
if(Outputs)
freopen("/dev/tty", "w", stdout);
return 0;
}
/* Function "Execute" : used as the function system( ), it interpret the input, and call function "my_spawn" to execute the all the commands. */
int Execute(char *buffer) // ,const int line,const int isBatchMode)
{
pid_t pid ;
char *args[MAX_ARGS]; /// pointers to arg strings
int error ;
int states[5]; // states[0] is back exec; states[1] is inputfile num; states[2] is outputfile num ;
// states[3] is priority of inputfile(not args); states[4] is argc ;
Redirect Inputs [MAX_OPEN]; // input redirection (10个)
Redirect Outputs[MAX_OPEN]; // output redirection (10)
error=my_strtok(buffer,args,states,Inputs,Outputs);// tokenize input, last entry will be NULL
if(error||args[0]==NULL) return -1; // 如果出现输入格式错误 or if there's anything there
if ( !strcmp(args[0],"quit") || !strcmp(args[0],"exit")) // "quit" command
{
if(args[1]) // no argument is needed after "quit" Error(-2,args+1,NULL,NULL,args[0]); ///
if(output_num>1)// e.g. myshell a.bat >m.txt >n.txt
{ fprintf(stderr,"Exit!\n");
return 1;
}
if(isbat) // /
fprintf(stderr,"Execution of batch file \"%s\" is finished!\n",batchfile);
else fprintf(stderr,"Exit MyShell, Goodbye!\n\n");
exit (0); // break out of 'while (!feof(stdin))' loop in "main" function
}
else if(states[0])// states[0]==1 后台执行
{
switch (pid=fork( ))
{
case -1: Error(-9,NULL,NULL,states,"fork");
case 0: // child //sleep(1);
my_delay(12);
fprintf(stderr,"\n");
my_spawn(args,Inputs,Outputs,states); exit(1);
default: if(isbat==0) //
fprintf(stderr,"pid=%d\n",pid);
}// end switch
}
else // states[0]==0 前台执行
my_spawn(args,Inputs,Outputs,states);
return 0;
}
/* Function "my_spawn" : used to exeute the command */
int my_spawn(char **args, const Redirect *Inputs,const Redirect *Outputs,int *states)
{
char filepath[MAX_PATH] , parent[MAX_ARGS] ;
FILE * outputfile=NULL,* inputfile;
pid_t newpid;
int flag ;
if (!strcmp(args[0],"myshell")||!strcmp(args[0],"shell")) // "myshell" command
{
flag=0;
if(isbat)// e.g. 在 a.bat里执行 myshell b.txt
{
switch(newpid=fork( ))
{ case -1: Error(-9,NULL,NULL,states,"fork");
case 0: if(states[0] &&(args[1]|| states[1]))
{ back_bat++;
flag=1;
}
output_num=states[2];
my_bat(args,Inputs,Outputs,states); //
if(flag) back_bat--;
output_num=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -