#include <stdio.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>

#define MAXCMDS 5

struct cmd {
    char *cmdname;    /* ptr to '\0' terminated string containing command   */
                      /* NULL if there is no command                        */
    char *argv[10];   /* ptr's to up to 10 arguments for this command       */
                      /* if there are i args, argv[i] is NULL               */
    char *infile;     /* NULL if no redirected input, else ptr to filename  */
    char *outfile;    /* NULL if no redirected output, else ptr to filename */
    int  pipe;        /* ==YES means there IS a pipe after this command.    */
    }  commands[MAXCMDS];  /* If there are i commands on the input command  */
                      /* line then command[j].cmdname==NULL for all j>=i    */

int background;       /* ==YES means this command line should be executed */
                      /* as a background command.                         */

extern int parsecmd(char cmdstring[]);


#define YES 1
#define NO  0
#define MAXCMDS 5

static int isitarg(char *s);
static int checkname(char *s, int);

int parsecmd(cmdstring)
char cmdstring[];      /* the '\0' terminated comamnd line entered */
{
  int cont,i,j;
  char *strptr, *strtok(), *tokenptr;
  
  /* initialization */
  for (i=0; i<MAXCMDS; i++) {
    commands[i].cmdname = commands[i].infile = commands[i].outfile=NULL;
    commands[i].pipe=0;
    for (j=0; j<10; j++)
      commands[i].argv[j] = NULL;
  }
  background=NO;
  
  cont=YES;
  for (i=0; i<MAXCMDS &&cont==YES; i++) {   /* each pass, get a prog name, */
    if (i==0)                         /* arguments, redirection/pipe info */
      strptr = strtok(cmdstring," ");    /* save program name to run */
    else strptr = strtok(NULL," ");
    commands[i].cmdname = strptr;
    cont=NO;
    
    commands[i].argv[0] = strptr;   /* UNIX convention is that argv[0] */
    /* holds name of program to run */
    for (j=1; j<10 && (isitarg(tokenptr=strtok(NULL," "))==YES); j++)
      commands[i].argv[j] = tokenptr;  /* save the command's arguments */
    commands[i].argv[j] = NULL;  
    
    if (tokenptr !=NULL) switch(*tokenptr) {   /* get redirection/pipe info */
    case '|':  
      commands[i].pipe=YES; 
      cont=YES; 
      break;  /* found a pipe */
    case '>':  
      if (tokenptr[1] == 0)
	commands[i].outfile = strtok(NULL," ");  /* found a > */
      else
	commands[i].outfile = tokenptr + 1;
      if (checkname(commands[i].outfile, YES)==0)   
	return(-1);     /* save and check output file name*/
      strptr = strtok(NULL, " ");
      if (strptr!=NULL && *strptr=='<') 
	{     /* also found a < */
	  if (strptr[1] == 0)
	    commands[i].infile = strtok(NULL," ");
	  else
	    commands[i].infile = strptr + 1;
	  if (checkname(commands[i].infile,NO)==0)
	    return(-2);         /* check input file name*/
	  if ( (strptr = strtok(NULL," ")) != NULL)
	    if (*strptr=='&')
	      background=YES;
	    else                             
	      return(-3);         /* must be end */
	}
      else if (strptr!=NULL && *strptr=='&') background=YES;
      else if (strptr!=NULL) return(-3);
      break;
    case '<':  
      if (tokenptr[1] == 0)
	commands[i].infile = strtok(NULL," ");  /* save file name */
      else
	commands[i].infile = tokenptr + 1;
      if (checkname(commands[i].infile, NO)==0)
	return(-1);              /* check input file name*/
      strptr = strtok(NULL, " ");
      if (strptr!=NULL && *strptr=='>') 
	{
	  if (strptr[1] == 0)
	    commands[i].outfile = strtok(NULL," ");
	  else
	    commands[i].outfile = strptr + 1;
	  if (checkname(commands[i].outfile,YES)==0)
	    return(-4);         /* check input file name*/
	  if ( (strptr = strtok(NULL," ")) != NULL)
	    if (*strptr=='&')
	      background=YES;
	    else                             
	      return(-3);         /* must be end */
	}
      else if (strptr!=NULL && *strptr=='&') 
	background=YES;
      else if (strptr!=NULL && *strptr=='|') 
	{
	  commands[i].pipe=YES;
	  cont = YES;
	}
      else if (strptr!=NULL) return(-3);
      break;
    case '&': 
      background = YES;
      break;
    default:
      return(-6);          
    }
    if (commands[i].pipe==NO)
      if (strtok(NULL," ")!=NULL) return(-7);  /* must be EOL */
  }
  
  return(i);
}

static int checkname(s,isitoutfile)
     char *s;   /* ptr to file name to check */
     int isitoutfile;  /* ==1, file will opened for output (writing) */
{
  FILE *fopen(), *fp;
  if (isitoutfile==YES)
    fp = fopen(s,"w");
  else
    fp = fopen(s,"r");
  if (fp == NULL)
    return(0);  /* try to open named file for reading or writing */
  fclose(fp);
  return(1);     /* successful return */
}


static int isitarg(s)   /* return NO if string is NULL or begins with >, <, |, or & */
     char *s;
{
  if (s && *s!='>' && *s!='<' && *s!='|' && *s!='&')
    return(YES);
  else
    return(NO);
}



