/*----------------------------------------------------------------------------
File Name: Pipes.c
Author: Christopher Huyler
Date: February 15, 2002
Description:
Check arguments in command for pipe '|' symbols and fork to redirect input
and output accordingly.  Reassign arguments by redefining pointers: '|' of
parent is set to 0 (end of arguments) while child's first arg is set to the
next arg after the '|'.
----------------------------------------------------------------------------*/
#include <sys/stat.h>
#include <fcntl.h>


int set_pipes(struct command_struct*); 				// set pipes
int special_pipe(struct command_struct*,int*);    	// check for special conditions

/* set pipes -----------------------------------------------------------------
	parse args in command for | and fork() to create seperate processes
	returns boolean int whether process is being piped
	may call pipe(), fork(), dup(), and close()  */
int set_pipes(struct command_struct *command)
{
	int  file_pipes[2],			// i/o pipes
		 pid = 0,				// process id returned by fork
		 piped = 0;              // boolean value (for parent)
	char **argv;				// ptr to argument array
	
	argv = command->argv;		// set ptr to command arg array
	
	while(!piped && *argv != 0) { // check every arg
		if(strcmp("|",*argv) == 0) {
			//write(comm_pipe[1],"1",1);
			pid = fork();     // split to parent and child
			if(pid == -1)
			{ // fork error
				fprintf(stderr, "Fork failure");
           		exit(EXIT_FAILURE);
    		}
			if(pid == 0)
			{ // child of pipe
				pipe(file_pipes); 			// set pipes
				pid = fork(); 				// fork again
				if(pid == -1)
				{ // fork error
					fprintf(stderr, "Fork failure");
					exit(EXIT_FAILURE);
				}
				if(pid == 0)
				{ // this is the child - child sends data to parent
					*argv = 0;					// make '|' end of argv list
					piped = 1;                  // don't check for more pipes
					close(1);					// close stdout
					dup(file_pipes[1]);			// duplicate out_pipe in stdout fd
					close(file_pipes[0]);		// close in_pipe
					close(file_pipes[1]);		// close original out_pipe
			    } // end child of second fork
			    else
			    { // this is the parent - parent recieves data from child
			    	command->argv = ++argv;		// set next arg as first arg	
			    	if(!special_pipe(command,&file_pipes[0])) {
						close(0);				// close stdin
						dup(file_pipes[0]);		// duplicate in_pipe in stdin fd
						close(file_pipes[0]);	// close original in_pipe
						close(file_pipes[1]);	// close out_pipe
					}
				} // end parent of second fork
			}// end child of first fork
			else
			{ // parent of first fork - keeps shell from continuing
				while(wait(NULL) != -1);  // waits for child (parent) to receive all data
				exit(1);
			}
		}
		argv++;  // incriment to next arg
	}
	return piped;
}

/* special pipe --------------------------------------------------------------
   check first argument to see if it is requires a special process
   returns boolean int whether command is special or not
   may call open() close() fork() read() write() and execlp() */
int special_pipe(struct command_struct *command, int *input_pipe)
{
	int  fd,				// file_descriptor
		 pid;               // process id after fork
	char buffer[BUFSIZ+1],	// i/o buffer
		 **argv;            // argument pointer
	
	argv = command->argv;   				// initialize argument pointer
	memset(buffer, '\0', sizeof(buffer));   // initialize buffer
	
	// check for more
    if(strcmp("more",*argv) == 0)
    {   // open a temp file called pipe
    	if((fd = open("/tmp/pipe",O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IXUSR)) == -1){
    		fprintf(stderr,"Pipe Error");
    		exit(EXIT_FAILURE);
    	}

    	read(*input_pipe, buffer, BUFSIZ);  // read from pipe to buffer
    	write(fd,buffer,strlen(buffer));    // print from buffer to file
    	close(fd);                          // close file
    	
    	pid = fork();
    	if(pid == -1)
		{ // fork error
			fprintf(stderr, "Fork failure");
        	exit(EXIT_FAILURE);
    	}
    	if(pid == 0) // this is the child
    		execlp("more","more","/tmp/pipe", 0);  	// child executes more on file
    	else
    	{ // this is the parent
    		while(wait(NULL) != pid);         		// parent waits
    		//write(comm_pipe[1],"0",1);
    		execlp("rm","rm","/tmp/pipe", 0);	  	// then deletes file
    	}
    	exit(1);
    } // end more

    return 0;  // not a special pipe
 } // end special_pipe



