/** A program simualting shell
 * see Robbins's book on section 7.4.
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>


#define MAX_BUFFER 256

int makeargs(char *inbuf,  char ***buf);
void run(char *inbuf);
int
main(void) 
{

    int status, pid, code, inbackground, child_pid;
    char inbuf[MAX_BUFFER];
    char *backp;

    
    struct sigaction ignorehd;
   struct sigaction defaulthd;
   sigset_t blockmask;

                        /* Set up the handlers for prompt and default */
   ignorehd.sa_handler = SIG_IGN;
   sigemptyset(&ignorehd.sa_mask);
   ignorehd.sa_flags = 0;
   defaulthd.sa_handler = SIG_DFL;
   sigemptyset(&defaulthd.sa_mask);
   defaulthd.sa_flags = 0;
   if ((sigaction(SIGINT, &ignorehd, NULL) < 0) ||
       (sigaction(SIGQUIT, &ignorehd, NULL) < 0))  {
      perror("Shell failed to install signal handlers");
      exit(1);
   }
                         /* Set up a mask to block SIGINT and SIGQUIT */
   sigemptyset(&blockmask);
   sigaddset(&blockmask, SIGINT);
   sigaddset(&blockmask, SIGQUIT);
   sigprocmask(SIG_BLOCK, &blockmask, NULL);



    /* Keep checking for commands from the command line */
    while(1) {
        printf("$ ");  /* print a prompt */

        fgets(inbuf, MAX_BUFFER, stdin);  /* read a command from stdin*/
	if(*(inbuf+strlen(inbuf)-1)=='\n')
		*(inbuf+strlen(inbuf)-1)=0;

        if((backp = strchr(inbuf, '&')) == NULL) {
            inbackground = 0;
        } else {
            inbackground = 1;
            *(backp) = '\0';
        }

        if(strncmp(inbuf, "exit", strlen("exit")) == 0) {
            exit(0);
        } else {
            if((child_pid = fork()) == 0) {
                if ((sigaction(SIGINT, &defaulthd, NULL) < 0) ||
                    (sigaction(SIGQUIT, &defaulthd, NULL) < 0)) {
                    perror("Child could not restore default handlers");
                    exit(1);
                }
                sigprocmask(SIG_UNBLOCK, &blockmask, NULL);

                run(inbuf);
                printf("Error: couldn't run command\n");
            }
        }


        /* Version that handles background processes */
        if( !inbackground) {
            while((pid = waitpid(-1, NULL, 0)) > 0 ) 
                if(pid == child_pid) break;
        } else {
            while(waitpid(-1, NULL, WNOHANG) > 0) ;
        }

        /* First version that only handles foreground processes */
        /*      pid = wait(&status);*/
    }

}


void run(char *inbuf) {

    char **buf;
    int i=makeargs(inbuf, &buf);
    /*printf("%d",i);*/
    printf("%s",buf[0]);

    if(execvp(buf[0], buf) == -1){
        perror("Invalid command\n");
        exit(1);
    }
   free(&buf[0]);
}


 /**
 * the string parsing function
 */
int
makeargs(char *inbuf, char ***buf) {
    /* pull out the strings */
   	char *temp;
	char *newbuf;
	int numtokens;
	char delim[]=" \t";
	int i;
	
	newbuf=inbuf+strspn(inbuf,delim);
	if((temp=calloc(strlen(newbuf)+1,sizeof(char)))==NULL){
		*buf=NULL;
		numtokens=-1;
	}
	else{
		strcpy(temp,newbuf);
		if(strtok(temp,delim)==NULL)
			numtokens=0;
		else 
			for(numtokens=1;strtok(NULL,delim)!=NULL;numtokens++);
		if((*buf=calloc(numtokens+1,sizeof(char *)))==NULL){
			free(temp);
			numtokens=-1;
		}
		else{
			if(numtokens>0){
				/*printf("%d",numtokens);*/
				strcpy(temp,newbuf);
				**buf=strtok(temp,delim);
				for(i=1;i<numtokens+1;i++)
					*((*buf)+i)=strtok(NULL,delim);
			}
			else{
				**buf=NULL;
				free(temp);
			}
		}	
	}
	return numtokens;
}


