/* This program creates a new process.
 * The parent reports the idenfication numbers of it and the child.
 * The child executes an expanded hello-world program.
 * Here, the child uses string parsing to set up the program call. 
 *
 * Original version created by Henry Walker (2004?). 
 * Adapted by Jerod Weinman (29 August 2008).
 */

#include <sys/types.h>       /* file of data types needed for many compilers */
#include <unistd.h>          /* needed for fork, getpid procedures */
#include <string.h>          /* needed for string functions */
#include <stdio.h>
#include <stdlib.h>

#define MaxArgs 10
#define MaxStringSize 20
#define CommandLine "hello-world this is a test"
#define WHITESPACE " .,\t\n"

/* The following parsing function is based on from 
       Nutt, Operating Systems, Third Edition, Addison Wesley, p. 63
   Parse command line to construct a parameter list
*/

int main (void)
{  pid_t pid;                /* variable to record process id of child */
   
   pid = fork();             /* create new process */
   if ( -1 == pid)           /* check for error in spawning child process */
     { perror ("error in fork");  
       exit (1);
     }

   if (0 == pid)             /* check if this is the new child process */
     { /* processing for child */

       /* statically allocated space for arguments */
       char *argv[MaxArgs];
       
       int argc;
       char *workingStr; /* working copy of command line */
       char *argPtr;    /* pointer to token from strsep */

       printf ("This output comes from the child process\n");
       printf ("Preparing to execute \"Hello World\" program\n");
       
       /* setting up command */
       argc = 0;
       workingStr = strdup (CommandLine); /* copy CommandLine string */

       while ((argPtr = strsep(&workingStr, WHITESPACE)) != NULL) {
          /* Allocate space for the argument */
          argv[argc] = (char*) malloc ( strlen(argPtr)+1 );
          
          /* Copy token to argv */
          strcpy(argv[argc],argPtr);

          argc++;
       }

       /* make SURE the argument list is terminated by a null-pointer */
       argv[argc] = NULL;

       /* executing the program */
       execv (argv[0], argv);

       printf ("this line, after the exec command, is never executed\n");

     } 
  else 
     { /* processing for parent */
       printf ("This output comes from the parent process.\n");
       printf ("Parent report:  my pid = %d   child's pid = %d\n", 
                getpid(), pid);     
     }

   exit (0);                 /* quit by reporting no error */
}
