/* execute.c
   smash's ExecuteCmd function, and  process handling routines.
	    fork...look for command outside shell.
*/
 
#include "smash.h"

extern int special_sym;
extern int line_len;
extern int argcount;
int status;		 
int keep_pid;	   /* for background */
int stopped_pid; /* handling. */

CMDTABLE cmdtbl[] = {
    { "!!",             BangBang,     },
    { "exit",           ExitShell,    },
    { "cd",             ChangeDir,    },
    { "history",        PrtHis,       },
		{	"help",						Help,					},
		{	"printenv",				PrtEnv,				},	
		{ "fg",							Foreground,		},
    { NULL,             NULL,         }
};

int Interpret( int argc, char **argv)
{
  int (*shellfunc)(int,char**);
  if( (shellfunc=search( argc,argv )) != NULL )
        (*shellfunc)(argc,argv);
  else
        ExecuteCmd( argc, argv, special_sym );
	return(0);
}
 
int (*search(int argc, char** argv) )(int, char**)
{
  char *fname;
  CMDTABLE *crp = cmdtbl;
 
  if( argc < 1 ) return NULL;
  fname = argv[0];
  while( crp->name != NULL ) /* while not end of the table */
    if( strcmp( crp->name, fname ) == 0 ) /* if names matched */
      return( crp->func );  /* corresponding function is returened*/
    else
      ++crp;  /* look for next entry */
 
  return( (int(*)()) NULL );  /* can't find in the table */
}

/*--------------------------------------------------------*/
int ExecuteCmd(int argc, char **argv, int special_sym)
{
  int pid,fd;

	if( strncmp(argv[0], "version",3) == 0) 
		printf("\nMyShell, v%s, (c) 1992,1994 Jon Madison.\n",VERSION);
  else if(argv[0][0] == '!' ) 
    	Bang(argc,argv);
  else if( strcmp(argv[0], "bg" ) == 0)
			PutJobInBackground(stopped_pid);
  else 
	{
 /*not one of the shell commands...here's where the fork
   comes in */
 	switch (pid=fork())
	{
		case -1:
			perror (*argv);
			break;
		case 0:
			fflush(stdout); /*  flush the buffer... */
			signal(SIGINT, SIG_DFL); /* catch the signals */
			signal(SIGQUIT, SIG_DFL);

		/* if we have to redirect output... BROKEN RIGHT NOW. I'm going to bed. */
			if(special_sym==REDIRECT1)
      {
				printf("\ntrying to redirect %s to %s with %s  \n",\
								argv[0],argv[argcount-1],argv[1]);
				printf("\nargcount= %d\n",argcount);

        fd = open(argv[argcount-1], O_CREAT | O_TRUNC | O_WRONLY, 0600);
        dup2 (fd, 1);
        close(fd);
        execvp(argv[0], &argv[0]);
				fflush(stdout);
				exit(0);
        perror("in redirection");
      }                         
			else
				execvp(argv[0], &argv[0]);	
			perror (argv[0]); /* if execvp returns...*/
			exit(0);	/* get out of the fork! */
			break;
		default:
		if(special_sym==BKGRD)			/* if it's a background job don't wait! */
		{
			BackgroundHandler(pid);	
			/* printf("Process %d exited. \n",pid); */
		}
		else
			{
				keep_pid = pid; /* childs pid to be handled by background handler */
				signal(SIGTSTP, doStop);	/* install CTRL-Z handler... */
			 	wait (&status); 
			}
	/*	printf("Process %d exited with status %d.\n",pid,status);	 */
	}
}
return(0);
}

int BackgroundHandler(int pid_in)
{
		printf("\n(pid: %d)\n",pid_in);
		keep_pid = pid_in;
		special_sym = FALSE;	/* reset special_sym flag. */
		return(0);
}

void PutJobInBackground(int pid_in)
{
	if(pid_in) /* if it's not pid 0 */
	{	
		printf("\nPid %d to background\n",pid_in);
		kill(pid_in,SIGTTOU);
	}
}

int Foreground(int argc, char **argv)
{ 
	if(argc==1)	/* called by itself then default to pid of last job */
	{
		printf("\nforegrounding last program (Pid %d)...\n",stopped_pid);
		kill(stopped_pid,SIGCONT);
		keep_pid=stopped_pid;	/* reassign default pid to thing currently running */
		wait(&status);						 /* resume waiting. */ 
	}
	else
	{
		printf("\nforegrounding...(Pid %d)...\n",atoi(argv[1]));
		kill(atoi(argv[1]),SIGCONT);
		system("stty sane");	/* don't know why SIGS botch up the screen. */
		system("stty erase ");
		wait(&status);						 /* resume waiting. */ 
	}
	return(0);
}

void doStop(void)
{	
	printf("\nStopped (pid: %d)\n",keep_pid);
	stopped_pid = keep_pid; /* keep the pid of the job stopped.. */
	kill(keep_pid,SIGSTOP);	 /* suspend this process. */
	system("stty sane");	/* don't know why SIGS botch up the screen. */
	system("stty erase ");
}
