/*   Program: mainprog.c
     Author: Kalen Martens
     Date: Dec/96

     This is the main program to demostrate my own versions of popen 
     and pclose. The first part is opening a pipe to the sort program 
     and sending it strings. The second part is opening a pipe to the 
     ls program to obtain a listing of the current directory.
*/

#include
#include

main()
{
 FILE *r_pipe, *w_pipe;      /* Pipes to read and write from */

 char buffer[80];            /* Buffer to keep strings read from pipe */
 int i;                      /* For increment counter */
 int dummy;                  /* Return of k_pclose function */

 FILE *k_popen(const char *command, const char *mode);
 int k_pclose(FILE *fp);

 char *str[5] = {"abba\n","beatles\n","ac_dc\n","zep\n","pink_floyd\n"};

 printf("\nStart of program!!\n\n");
 
 printf("  Opening pipe to write five strings to sort facility. The\n");
 printf("  strings (in the order they are sent) are: \n");
 printf(" %s %s %s %s %s \n", str[0], str[1], str[2], str[3], str[4]);

 if ((w_pipe = k_popen("/usr/ucb/sort", "w")) == NULL)
   {
      printf("Error opening pipe to write.");
      exit(-1);
   }

 for (i=0; i<5; i++)
 {
    if (fputs(str[i], w_pipe) == EOF ) {
        printf(" Error for fputs: errno = &d\n", errno); }
    fflush(w_pipe);
    fflush(stdout);
 }

 dummy = k_pclose(w_pipe);
 if ( dummy == EOF)  {
      printf(" Problem closing pipe."); }

/* Now try to get a directory listing from the ls program and print it. */

 printf("\n  Opening pipe to ls program to get directory listing.\n\n");

 if ((r_pipe = k_popen("/usr/ucb/ls", "r")) == NULL) {
      printf("Error opening pipe to read.");
      exit(-1);    }

 while (fgets(buffer, sizeof(buffer), r_pipe) != NULL) {
      printf("%s", buffer);
      fflush(stdout); }

  dummy = k_pclose(r_pipe);
  if ( dummy == EOF)  {  
      printf(" Problem closing pipe."); } 
}

/* Functions: k_popen.c and k_pclose.c
   Author:    Kalen Martens
   Date:      Dec/96

   These functions are my versions of the C program 
   library routines popen and pclose.  My functions
   are not as robust as the popen and pclose, and they
   do not conform to POSIX, etc. But they sure do work!

   k_popen operates by first creating a pipe, then forks
   a child process. The parent and child close off the
   appropriate end of the pipe depending on if the mode 
   is to read or write. The child then duplicates its 
   end of the pipe to stdin or stdout depending on the 
   mode and then changes itself into the program specified
   by command.

   k_pclose merely calls the function fclose to close the 
   stream. It also calls waitpid to see the child terminate. 

                                       */

#include
#include 
#include 
#include
#include

static pid_t child_pid;    /* This is a variable defined such that 
                              k_pclose can determine the PID of the
                              child process that was spawned by
                              k_popen         */


FILE *k_popen(const char *command, const char *mode)
{
    int k_pipe[2];                /* File descriptors for the pipe        */
    pid_t ierr;                   /* Return value of fork()               */
    FILE *fp;                     /* Pointer to k_pipe stream ; to be returned
                                      to calling function.                */

/* Create the pipe */
    
    if (pipe(k_pipe) < 0 ) {
        printf("Pipe command failed.\n");
        return(NULL);
    }

/* Fork the process */

    if (( ierr = fork()) < 0 )
      {
           printf("popen: Fork failed.\n");
           return(NULL);
      }
    else if ( ierr == 0 )    /* I am the CHILD  */
      { 
         if (mode[0] == 'r')  {
             close(k_pipe[0]);
             if ( k_pipe[1] != STDOUT_FILENO ) {
                 if (dup2(k_pipe[1], STDOUT_FILENO)==-1) {
                      printf("Duplication failed.\n");
                      return(NULL);    }
             }
             close(k_pipe[1]);
             execl("/bin/sh","sh","-c",command,NULL);
             _exit(127);   }
         else if (mode[0] == 'w') {
             close(k_pipe[1]);
             if ( k_pipe[0] != STDIN_FILENO ) {
                 if (dup2(k_pipe[0], STDIN_FILENO)==-1) {
                      printf("Duplication failed.\n");
                      return(NULL);    }
             }
             close(k_pipe[0]);
             execl("/bin/sh","sh","-c",command,NULL);
             _exit(127);   }
      }
   else              /* I am the PARENT      */
      {
         if (mode[0] == 'r') {
            close(k_pipe[1]);
            fp = fdopen(k_pipe[0], &mode[0]);
            child_pid = ierr; }
         else if (mode[0] == 'w') {
            close(k_pipe[0]);
            fp = fdopen(k_pipe[1], &mode[0]); 
            child_pid = ierr; }
         else  
            fp = NULL;           /* Not read or write is an error */
      }          
    return(fp);
    
  
}

/****************************************************************/

int k_pclose(FILE *fp)
{

 int stat;

 if (fclose(fp) != 0) 
 {
      printf("Problem with closing of stream.\n");
      return(EOF);
 }
 if (waitpid(child_pid, &stat, 0) == -1) {
       printf(" Error on waitpid"); 
       return(EOF);  }
}