In: Computer Science
Create shell in C which meets the requirements below:
1. The shell must support the following internal commands:
i.
cd - Change the current default directory to
If the argument is not present, report the current directory. If the directory does not exist an appropriate error
should be reported. This command should also change the
PWD environment variable.
ii. clr - Clear the screen.
iii. dir - List the contents of directory.
iv.
environ - List all the environment strings.
v. echo - Display on the display followed by a newline (multiple spaces/tabs may be reduced to a single space).
vi. help - Display the user manual using the more filter.
vii. pause - Pause operation of the shell until 'Enter' is pressed.
viii.
quit - Quit the shell.
ix.
The shell environment should contain shell=/myshell where
/myshell is the full path for the shell executable (not a
the hardwired path back to your directory, but the one from which it was executed).
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <EN.h>
#include <string.h>
#include <dirent.h>
#define BUFFER_SIZE 1024
#define MAX_ARGS 64
#define SEPARATORS " \t\n"
#define NUM 10
#define MAX_PEN 10
#define MAX_PATH 100
struct Redirect
{
char *filename;
char Otype[3];
char PEN[3];
}
extern int EN;
extern char **environ;
int Cal(char *buffer);
int Exec_Command(char **args, const Redirect *Inputs,const Redirect *Outputs,int *St);
int Error_Find(int Error_Findtype,char **args,const Redirect * IOputs,const int *St, char * msg) ;
int Strtok_Command(char *buf,char **args,int *St,Redirect *InPuts,Redirect *OutPuts);
int Cd_Command(char **args,const Redirect *Inputs, int *St);
void Clear_Command(void);
int Dir_Command(char **args,const Redirect *Inputs, int *St);
int Echo_Command(char **args,const Redirect *Inputs,int *St);
int Environ_list(void);
int Pwd_show(void);
int Shell_Command(FILE *inputfile,const Redirect *Outputs,const int *St);
void Delay_Command(int n);
void Fullpath_get(char *fullpath,const char *shortpath);
int Help_Command(char **args,const Redirect *Outputs,int *St);
int Bat_Command(char **args,const Redirect *Inputs,const Redirect *Outputs,int *St);
int Bat_Back=0;
int OP=0;
char BF[MAX_PATH] ;
int BN=0;
int IB=0;
int Ltt;
char *PEN;
int Cal(char *buffer)
{
identity_t identity;
char *args[MAX_ARGS];
int Error_Find ;
int St[5];
Redirect Inputs [MAX_PEN];
Redirect Outputs[MAX_PEN];
Error_Find=Strtok_Command(buffer,args,St,Inputs,Outputs);
if(Error_Find||args[0]==NULL) return -1;
if ( !strcmp(args[0],"quit") || !strcmp(args[0],"exit"))
{
if(args[1])
Error_Find(-2,args+1,NULL,NULL,args[0]);
if(OP>1)
{
fprintf(stderr,"Exit\n");
return 1;
}
if(IB)
fprintf(stderr,"Batch file \"%s\" is finished!\n",BF);
else fprintf(stderr,"\nGoodbye\n\n");
exit (0);
}
else if(St[0])
{
switch (identity=fork( ))
{
case -1:
Error_Find(-9,NULL,NULL,St,"fork");
case 0:
Delay_Command(12);
fprintf(stderr,"\n");
Exec_Command(args,Inputs,Outputs,St);
exit(1);
default:
if(IB==0)
fprintf(stderr,"identity=%d\n",identity);
}
}
else
Exec_Command(args,Inputs,Outputs,St);
return 0;
}
int Exec_Command(char **args, const Redirect *Inputs,const Redirect *Outputs,int *St)
{
char path_file[MAX_PATH] , parent[MAX_ARGS] ;
FILE * outputfile=NULL,* inputfile;
identity_t newidentity;
int Anthem ;
if (!strcmp(args[0],"myshell")||!strcmp(args[0],"shell"))
{
Anthem=0;
if(IB)
{
switch(newidentity=fork( ))
{
case -1:
Error_Find(-9,NULL,NULL,St,"fork");
case 0:
if(St[0] &&(args[1]|| St[1]))
{
Bat_Back++;
Anthem=1;
}
OP=St[2];
Bat_Command(args,Inputs,Outputs,St);
if(Anthem)
Bat_Back--;
OP=0;
exit (0);
default:
waitidentity(newidentity, NULL, WUNTRACED);
}
}
else
{
if(St[0]&&(args[1]|| St[1]))
{
Bat_Back++;
Anthem=1;
}
OP=St[2];
Bat_Command(args,Inputs,Outputs,St);
if(Anthem)
Bat_Back--;
OP=0;
}
if(St[0])
exit(1);
else
return 0;
}
if(St[2])
{
Fullpath_get(path_file, Outputs->filename);
outputfile=frePEN(path_file, Outputs->Otype,stdout);
if(outputfile==NULL)
{
Error_Find(-6,NULL,NULL,NULL,Outputs->filename);
if(St[0])
exit(1);
else
return -4;
}
}
if (!strcmp(args[0],"cd"))
Cd_Command(args,Inputs,St);
else if (!strcmp(args[0],"clr")||!strcmp(args[0],"clear"))
{
if(OP==0 )
Clear_Command( );
if(args[1]|| St[1]||St[2])
Error_Find(4,NULL,NULL,NULL,args[0]);
}
else if (!strcmp(args[0],"dir"))
Dir_Command(args,Inputs,St);
else if (!strcmp(args[0],"echo"))
Echo_Command(args,Inputs,St);
else if (!strcmp(args[0],"environ"))
{
Environ_list( );
if(St[1])
Error_Find(-3,NULL,Inputs,St,"environ");
if(args[1])
Error_Find(-2,args+1,NULL,NULL,"environ");
}
else if (!strcmp(args[0],"help")||!strcmp(args[0],"?"))
{
Help_Command(args,Outputs,St);
if(St[1])
Error_Find(-3,NULL,Inputs,St,args[0]);
}
else if (!strcmp(args[0],"pause"))
{
if(args[1]|| St[1]|| St[2])
Error_Find(4,NULL,NULL,NULL,args[0]);
if(St[0]+Bat_Back==0)
pass_get("Paused\npress <Enter> key to continue");
}
else if (!strcmp(args[0],"pwd"))
{
Pwd_show( );
if(St[1])
Error_Find(-3,NULL,Inputs,St,"pwd");
if(args[1])
Error_Find(-2,args+1,NULL,NULL,"pwd");
}
else
{
strcpy(parent,"parent=") ;
strcat(parent, getenv("shell"));
switch (newidentity=fork( ))
{
case -1:
Error_Find(-9,NULL,NULL,NULL,"fork");
case 0:
if(St[1])
{
Fullpath_get(path_file,Inputs->filename);
inputfile= frePEN(path_file,"r",stdin);
if(inputfile==NULL)
{
Error_Find(-6,NULL,NULL,NULL,Inputs->filename);
exit(1);
}
}
putenv( parent);
execvp(args[0],args);
Error_Find(-1,args,NULL,NULL,NULL);
if(inputfile)
fclose(inputfile);
exit(0);
default:
if(St[0]==0 )waitidentity(newidentity, NULL, WUNTRACED);
}
}
if(outputfile)
{
fclose(outputfile);
frePEN("/dev/tty","w",stdout);
}
if(St[2]>1)
{
St[2]--;
Exec_Command (args, Inputs, Outputs+1,St) ;
}
if(St[0]) exit(0);
else return 0;
}
int Error_Find(int Error_Findtype,char **args,const Redirect * IOputs,const int *St, char * msg)
{
int i;
if(IB)
fprintf(stderr,"Line %d of inputfile \"%s\": ",BN,BF);
switch(Error_Findtype)
{
case 0:
fprintf(stderr," %s\n",msg);
break;
case 1:
fprintf(stderr,"Format Error_Find: invlid argument '%s'(Ltt %d), without PENfile\n",PEN,Ltt);
fprintf(stderr,"\nType 'help redirection' to get help information abbout '<' '>>' and '>'\n");
break;
case 2:
fprintf(stderr,"Format Error_Find(Ltt %d): '%s' followed by invlid argument '%c'\n", Ltt,PEN,*msg);
fprintf(stderr,"\nType 'help redirection' to get help information abbout '<' '>>' and '>'\n");
break;
case 3:
fprintf(stderr,"Sorry: no help information about \"%s\" found.\n",msg);
fprintf(stderr,"\nType \"man %s\" to search in the man pages of the system.\nNote: press the key <Q> to exit the search.\n",msg);
break;
case 4:
fprintf(stderr,"Note: no argument is needed after \"%s\", except the background-Cal Anthem '&' .",msg);
fprintf(stderr,"\nType 'help %s' to get usage abbout '%s'.\n",msg,msg);
break;
case 5:
fprintf(stderr,"\nSystem Note: can not PEN more than %d files as %s\n",MAX_PEN,msg);
break;
case -1:
fprintf(stderr,"\nSystem Warning: \"");
while (*args)
fprintf(stderr,"%s ",*args++);
fprintf(stderr,"\b\" is not internal command or executive file\n");
if(IB==0&&OP==0)
fprintf(stderr,"\nType \"help command\" to see supported internal commands.\n");
break;
case -2:
fprintf(stderr,"\nFormat Warning: invalid arguments \"" ) ;
while(*args)
fprintf(stderr,"%s ",*args++);
fprintf(stderr,"\b\" after command \"%s\" \n",msg);
break;
case -3:
fprintf(stderr,"Invalid input redirection: ");
for(i=0;i<St[1];i++)
fprintf(stderr,"\"<%s\" ",IOputs[i].filename);
fprintf(stderr,"after \"%s\" !\n",msg);
break;
case -4: fprintf(stderr,"Invalid output redirection: ");
for(i=0;i<St[1];i++)
fprintf(stderr,"\"%s%s\" ",IOputs[i].Otype,IOputs[i].filename);
fprintf(stderr,"after \"%s\" \n",msg);
break;
case -5:
fprintf(stderr,"Path Error_Find: \"%s\": not a directory or not exist\n",msg);
break;
case -6:
fprintf(stderr,"File Error_Find: can not PEN file \"%s\"\n",msg);
break;
case -7:
fprintf(stderr,"Overflow Error_Find: the assigned dirpath is longer than permitted longth(%d)\n",MAX_PATH);
break;
default:
fprintf(stderr,"%s: %s\n", strError_Find(EN), msg);
break;
abort( );
}
return 1;
}
int Strtok_Command(char *buf,char **args,int *St,Redirect *Inputs,Redirect *Outputs)
{
int i,j,n,m, Anthem,argc,Error_Findtype;
char c ;
St[0]=St[1]=St[2]=St[3]=St[4]=0;
Error_Findtype=Ltt=argc=0;
args[0]=NULL;
PEN=NULL;
Anthem=1;
i=m=n=-1;
while(buf[++i]&&buf[i]!='#')
{
c=buf[i];
switch(c)
{
case '<':
Ltt++;
if(Anthem==0)
{
Anthem=1;
buf[i]='\0';
}
PEN="<";
while(buf[++i]==' '|| buf[i]=='\t');
if(buf[i]<32|| buf[i]=='#' )
{
Error_Findtype=Error_Find(1,NULL,NULL,NULL,"<");
break;
}
else if(buf[i]=='&'|| buf[i]=='<'|| buf[i]=='>'|| buf[i]=='|'|| buf[i]==';')
{
Ltt++;
Error_Findtype=Error_Find(2,NULL,NULL,NULL,buf+i);
break;
}
if(argc<2)
St[4]=1;
m++;
i--;
break;
case '>':
Ltt++;
if(Anthem==0)
{
Anthem=1;
buf[i]='\0';
}
n++;
if(buf[i+1]=='>')
{
buf[++i]='\0';
PEN=">>";
}
else
PEN=">";
while(buf[++i]==' '|| buf[i]=='\t');
if(buf[i]<32|| buf[i]=='#' )
{
Error_Findtype=Error_Find(1,NULL,NULL,NULL,NULL);
break;
}
else if(buf[i]=='&'|| buf[i]=='<'|| buf[i]=='>'|| buf[i]=='|' || buf[i]==';')
{
Ltt++;
Error_Findtype=Error_Find(2,NULL,NULL,NULL,buf+i);
break;
}
i--;
break;
case '&':
Ltt++;
if(Anthem==0)
{
Anthem=1;
buf[i]='\0';
}
if(St[0])
{
Error_Findtype= Error_Find(0,NULL,NULL,NULL,"Format Error_Find: argument '&' occurs more than once");
break;
}
St[0]=1;
break;
case ' ':
case '\t':
if(Anthem==0)
{
Anthem=1;
buf[i]='\0';
}
while(buf[++i]==' '|| buf[i]=='\t');
i--;
break;
case '\n':
case '\r':
buf[i]='\0';
i--;
break;
default:
Ltt++;
if(Anthem)
{
Anthem=0;
if(PEN&&m<=MAX_PEN&&n<=MAX_PEN)
{
if(m==MAX_PEN)
Error_Findtype=Error_Find(5,NULL,NULL,NULL,"input");
else if(n==MAX_PEN)
Error_Findtype=Error_Find(5,NULL,NULL,NULL,"output");
else if( !strcmp(PEN,"<" ) )
Inputs[m].filename=buf+i;
else if( !strcmp(PEN,">>" ) )
{
strcpy(Outputs[n].Otype,"a");
strcpy(Outputs[n].PEN,">>");
Outputs[n].filename=buf+i;
}
else if( !strcmp(PEN,">" ) )
{
strcpy(Outputs[n].Otype,"w");
strcpy(Outputs[n].PEN,">");
Outputs[n].filename=buf+i;
}
PEN=NULL;
}
else args[argc++]=buf+i;
}
if(c=='\\' &&buf[i+1]==' ')
{
buf[i]=' ';
if( ! isspace(buf[i+2]))
{
j=i+1;
while( buf[++j]) buf[j-1]=buf[j];
}
}
}
}
args[argc]=NULL;
St[1]=m+1;
St[2]=n+1;
St[3]=argc;
if(Error_Findtype||(argc==0&&Ltt))
Error_Find(0,NULL,NULL,NULL,"Warning: nothing will be Cald");
return Error_Findtype;
}
int Cd_Command (char **args,const Redirect *Inputs,int *St)
{
char dirpath[MAX_PATH], path_file[MAX_PATH], dirname[MAX_PATH];
char *current_dir;
int i,Anthem;
FILE *inputfile;
if(St[4])
{
if(args[1])
Error_Find(-2,args+1,NULL,NULL,"cd");
if(--St[1])
Error_Find(-3,NULL,Inputs+1,St,"cd");
Fullpath_get(path_file,Inputs->filename);
inputfile=fPEN(path_file,"r");
if(inputfile==NULL)
{
Error_Find(-6,NULL,NULL,St,Inputs->filename);
return -2;
}
fgets(dirname,MAX_PATH,inputfile);
fclose(inputfile);
args[1] = strtok(dirname," \b\n\r");
i=2;
while (( args[i] = strtok(NULL," \b\n\r") ) ) i++;
}
else if (St[1])
Error_Find(-3,NULL,Inputs,St,"cd");
if(args[1])
{
if(args[2])
Error_Find(-2,args+2,NULL,NULL,"cd");
Fullpath_get(dirpath,args[1]);
}
else {
fprintf(stdout,"%s\n",getenv("PWD"));
return 0;
}
Anthem=chdir(dirpath);
if(Anthem)
{
Error_Find(-5,NULL,NULL,St, args[1]);
return -2;
}
current_dir=(char *)malloc(BUFFER_SIZE);
if(!current_dir)
Error_Find(-9,NULL,NULL,St,"malloc failed");
getcwd(current_dir,BUFFER_SIZE);
setenv("PWD",current_dir,1);
free(current_dir);
return 0;
}
void Clear_Command(void)
{
identity_t newidentity;
switch (newidentity=fork( ))
{
case -1:
Error_Find(-9,NULL,NULL,NULL,"fork");
case 0:
execlp("clear","",NULL);
Error_Find(-9,NULL,NULL,NULL,"execlp");
default: waitidentity(newidentity, NULL, WUNTRACED);
fprintf(stderr,"\nCleared\n\n");
}
return;
}
int Dir_Command(char **args,const Redirect *Inputs, int *St)
{
FILE *inputfile ;
identity_t newidentity;
DIR *pdir;
int i;
char path_file[MAX_PATH], dirpath[MAX_PATH], dirname[MAX_PATH];
if(St[4])
{
if(args[1])
Error_Find(-2,args+1,NULL,NULL,"dir");
if(--St[1])
Error_Find(-3,NULL,Inputs,St,"dir");
Fullpath_get(path_file,Inputs->filename);
inputfile=fPEN(path_file,"r");
if(inputfile==NULL)
{ Error_Find(-6,NULL,NULL,St,Inputs->filename);
return -2;
}
fgets(dirname,MAX_PATH,inputfile);
fclose(inputfile);
args[1] = strtok(dirname," \b\n\r");
i=2;
while (( args[i] = strtok(NULL," \b\n\r") ) ) i++;
}
else if (St[1])
Error_Find(-3,NULL,Inputs,St,"dir");
if(args[1])
{
if(args[2])
Error_Find(-2,args+2,NULL,NULL,"dir");
Fullpath_get(dirpath,args[1]);
}
else strcpy(dirpath, ".");
pdir=PENdir(dirpath);
if(pdir==NULL)
{
Error_Find(-5,NULL,NULL,St,args[1]);
return -2 ;
}
switch (newidentity=fork( ))
{
case -1:
Error_Find(-9,NULL,NULL,St,"fork");
case 0:
execlp( "ls","ls" ,"-al", dirpath, NULL);
Error_Find(-9,NULL,NULL,St,"execlp");
default: waitidentity(newidentity, NULL, WUNTRACED);
}
return 0;
}
int Echo_Command (char **args,const Redirect *Inputs,int *St)
{
FILE * inputfile;
char path_file[MAX_PATH];
char buf[BUFFER_SIZE];
int j,k;
if(St[4])
{
if(args[1])
Error_Find(-2,args+1,NULL,NULL,"echo");
for(j=0;j<St[1];j++)
{
Fullpath_get(path_file,Inputs[j].filename);
inputfile=fPEN(path_file,"r");
if(inputfile==NULL)
{
Error_Find(-6,NULL,NULL,NULL,Inputs[j].filename);
return -2;
}
if(St[2]==0&&OP==0)
fprintf(stderr,"The contents of file \"%s\" is:\n",Inputs[j].filename);
while (!feof(inputfile))
{
if(fgets(buf, BUFFER_SIZE, inputfile))
fprintf(stdout,"%s",buf);
}
fclose(inputfile);
fprintf(stdout,"\n");
}
}
else
{
if(St[1])
Error_Find(-3,NULL,Inputs,St,"echo");
if(args[1])
{
for(k=1;k<St[3]-1;k++)
fprintf(stdout,"%s ",args[k]);//fputs(args[k],outputfile);
fprintf(stdout,"%s",args[k]);
}
fprintf(stdout,"\n");
}
return 0;
}
int Environ_list (void)
{
char ** env = environ;
while(*env) fprintf(stdout,"%s\n",*env++);
return 0;
}
int Pwd_show (void)
{
fprintf(stdout,"PWD=%s\n",getenv("PWD"));
return 0;
}
int Shell_Command(FILE *inputfile,const Redirect *Outputs,const int *St)
{
FILE *outputfile;
char path_file[MAX_PATH];
char buf[BUFFER_SIZE];
int done=0;
if(Outputs)
{
Fullpath_get(path_file,Outputs->filename);
outputfile=frePEN(path_file,Outputs->Otype,stdout);
if(outputfile==NULL)
{
Error_Find(-6,NULL,NULL,NULL,Outputs->filename);
return -2;
}
fprintf(stderr,"\nThe results will be writen into file \"%s\".\n",Outputs->filename);
}
BN=0;
do
{
if (inputfile==stdin&&Outputs==NULL)
fprintf(stderr,"\n[%s@%s]$: ",getenv("USERNAME"),getenv("PWD"));
if (fgets(buf, BUFFER_SIZE, inputfile))
{
BN++;
done=Cal(buf);
if(done==1)
{
if(Outputs)
frePEN("/dev/tty", "w", stdout);
break;
}
}
}
while (!feof(inputfile));
if(Outputs)
frePEN("/dev/tty", "w", stdout);
return 0;
}
void Delay_Command(int n)
{
n=n*1000000;
while(n--) ;
}
void Fullpath_get(char *fullpath,const char *shortpath)
{
int i,j;
i=j=0;
fullpath[0]=0;
char *old_dir, *current_dir;
if(shortpath[0]=='~')
{
strcpy(fullpath, getenv("HOME"));
j=strlen(fullpath);
i=1;
}
else if(shortpath[0]=='.'&&shortpath[1]=='.')
{
old_dir=getenv("PWD");
chdir("..");
current_dir=(char *)malloc(BUFFER_SIZE);
if(!current_dir)
Error_Find(-9,NULL,NULL,NULL,"malloc failed");
getcwd(current_dir,BUFFER_SIZE);
strcpy(fullpath, current_dir);
j=strlen(fullpath);
i=2;
chdir(old_dir);
}
else if(shortpath[0]=='.')
{
strcpy(fullpath, getenv("PWD"));
j=strlen(fullpath);
i=1;
}
else if(shortpath[0]!='/')
{
strcpy(fullpath, getenv("PWD"));
strcat(fullpath, "/");
j=strlen(fullpath);
i=0;
}
strcat(fullpath+j,shortpath+i);
return;
}
int Help_Command(char **args,const Redirect *Outputs,int *St)
{
FILE *readme;
char buffer[BUFFER_SIZE];
char keywords [BUFFER_SIZE]="<help ";
int i,len;
for(i=1;args[i];i++)
{
strcat(keywords,args[i]);
strcat(keywords," ");
}
len=strlen(keywords);
keywords[len-1]='>';
keywords[len]='\0';
if(!strcmp(keywords,"<help more>"))
{
strcpy(buffer,"more ");
strcat(buffer,getenv("readme_path"));
for(i=0;i<St[2];i++)
{
strcat(buffer,Outputs[i].PEN);
strcat(buffer,Outputs[i].filename);
}
Cal(buffer);
return 0;
}
readme=fPEN(getenv("readme_path"),"r");
while(!feof(readme)&&fgets(buffer,BUFFER_SIZE,readme))
{
if(strstr(buffer,keywords))
break;
}
while(!feof(readme)&&fgets(buffer,BUFFER_SIZE,readme))
{
if(buffer[0]=='#')
break;
fputs(buffer,stdout);
}
if(feof(readme))
{
keywords[len-1]='\0';
Error_Find(3,NULL,NULL,NULL,&keywords[6]);
}
if(readme)
fclose(readme);
return 0;
}
int Bat_Command(char **args,const Redirect *Inputs,const Redirect *Outputs, int *St)
{
FILE *inputfile;
char path_file[MAX_PATH];
int i=0;
char fullpath_BF[MAX_PATH] ;
identity_t newidentity;
if(IB)
fprintf(stderr,"Line %d of inputfile \"%s\": ",BN,BF);
if(St[4])
{
if(args[1])
fprintf(stderr,"Note: can not PEN more than one inputfile after commnad '%s'.\n",args[0]);
args[1]=Inputs->filename;
--St[1];
i=1;
}
if(args[1])
{
if(St[1]>0)
Error_Find(-3,NULL,Inputs+i,St,args[0]);
if(args[2])
Error_Find(-2,args+2,NULL,NULL,args[0]);
Fullpath_get(path_file,args[1]);
Fullpath_get( fullpath_BF,BF) ;
if(IB && !strcmp(fullpath_BF,path_file))
{
fprintf(stderr,"Warning: commands not Cal, it will result in infinte loop");
return -5;
}
inputfile=fPEN(path_file,"r");
if(inputfile==NULL)
{
Error_Find(-6,NULL,NULL,NULL,args[1]);
return -2;
}
IB=1;
strcpy(BF,args[1]);
fprintf(stderr,"Turn to Cal the commands in batch file \"%s\":\n",BF);
if( ! OP)
Shell_Command(inputfile,NULL,St);
else
for(i=0;i<St[2];i++)
{
Shell_Command(inputfile,Outputs+i,St);
rewind(inputfile);
OP--;
}
fclose(inputfile);
fprintf(stderr,"\nExecution of batch file \"%s\" is finished\n",BF);
BN=IB=0;
}
else if( OP)
{
IB=0;
switch(newidentity=fork( ))
{
case -1:
Error_Find(-9,NULL,NULL,St,"fork");
case 0:
fprintf(stderr,"Please type commands, the results will be writen into \"%s\":\n",Outputs->filename);
Shell_Command(stdin,Outputs,St);
exit(0);
default:
waitidentity(newidentity, NULL, WUNTRACED);
}
if( OP>1)
{
fprintf(stderr,"\n");
OP--;
Bat_Command(args,Inputs,Outputs+1,St);
}
}
else
fprintf(stdout,"\nProduced by: Dfaults\n");
return 0;
}