/*      CSCI 4830 	*/
/* A Mini-Shell by Paul	*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define LINE_LEN	80
#define MAX_ARGS   	64
#define MAX_ARG_LEN 	16
#define MAX_PATH_LEN	96
#define WHITESPACE 	" ,\t\n"

int MAX_PATHS;
int EXIT_FLAG = 0;

struct command_t 
{
    char *name;
    int argc;
    char *argv[MAX_ARGS];
};

  char* lookupPath(char**, char**);
  int parseCommand(char*, struct command_t*);
  int parsePath(char**);
  void printPrompt();
  void readCommand(char*);

int main()
{
    int k, status, concurrent, job;
    char commandLine[LINE_LEN];
    char* pathV[MAX_ARGS];
    struct command_t command;

    MAX_PATHS = parsePath(pathV);
    printf("\n\n\n");
    
    while(1)
    {
        printPrompt();
        readCommand(commandLine);
	k = strlen(commandLine);

	if(commandLine[k-1] == '&')
	{ /* & triggers background process desired */
	    commandLine[k-1] = '\0';
	    concurrent = 1;
	}

        parseCommand(commandLine, &command);
        command.name = lookupPath(command.argv, pathV);
	
	if (EXIT_FLAG == 1)
	{ /* triggered from lookupPath */
	    break;
	}

	if((k=fork())==0)
	{ /* child */
	    if(concurrent == 1)
	    { /* +background process, parent doesn't wait */
	        concurrent = 0;
	        printf("[%d] %d\n",job++,getpid());
		execve(command.name,command.argv,1);
		continue;
	    } 
	      /* else no background process */
	    execvp(command.name,command.argv);
        }
	wait(&status);
	continue;
    }
    return 0;
}

void printPrompt()
{
    printf("pjShell$ ");
}

void readCommand(char* buffer)
{
    gets(buffer);
}

int parseCommand(char* commandLine, struct command_t* command) 
{
    int argc=0;
    char** argv = malloc(MAX_ARG_LEN*sizeof(** argv));

    argv = &commandLine;

    while((command->argv[argc] = strsep(argv,WHITESPACE)) != NULL)
    {  
	command->argv[++argc] = malloc(MAX_ARG_LEN*sizeof(*command->argv[argc]));
    }

    command->argc = argc - 1;
    command->name = (char*)malloc(sizeof(command->argv[0]));
    strcpy(command->name, command->argv[0]);

    return 1;
}


int parsePath(char* dirs[])
{
    int i;
    char* pathEnvVar;
    char* thePath;

    for(i = 0; i < MAX_ARGS; i++) 
    {
        dirs[i] = NULL;
    }

    i = 0;

    pathEnvVar = (char*)getenv("PATH");
    thePath = (char*)malloc(strlen(pathEnvVar) + 1);
    strcpy(thePath, pathEnvVar);

    while((dirs[i++] = (char*)strsep(&pathEnvVar,":")) != NULL)
    {
    }

    return i - 1;
}

char* lookupPath(char **argv, char **dir) 
{
    int i;
    char* result;
    char exitc[] = "exit", quitc[] = "quit";

    if(*argv[0] == '/')
    { /* check / main directories */
        return argv[0];
    }

    for(i = 0; i < MAX_PATHS; i++)
    { /* check PATH directories */
        result = malloc(strlen(result) + strlen(dir[i]) + 2);

        strcpy(result, dir[i]);
        strcat(result, "/");
        strcat(result, argv[0]);

        if(access(result, 1) == 0)
	{
            return result;
        }
    }

    if(((strcmp(exitc,argv[0])) == 0) || ((strcmp(quitc,argv[0])) == 0))
    { /* custom command 'exit' or 'quit' kills the shell */
	EXIT_FLAG = 1;
	printf("\nthe pjShell is exiting...\n\n");
	return NULL;
    }
	else
	{
    	    fprintf(stderr, "%s: command not found\n", argv[0]);
    	    return NULL;
	}
}


