/* file:		matrix.c
 * author:		Robert S. Laramee
 * class:		cs720/820
 * date started:  	27 Jan 98
 * date finished:	27 Jan 98
 * project:		assignment 1
 * description:		This program should read in the following command
 *			line arguments: name of the data file, number of
 * rows and columns in matrixA, and the number of rows and columns in
 * matrixB, in this order.  For example % matrix mat.dat 2 10 10 5
 *
 *  argv[0] = matrix	-name of program
 *  argv[1] = mat.dat	-name of input file
 *  argv[2] = x		-number of rows in matrix A
 *  argv[3] = x		-number of columnss in matrix A
 *  argv[4] = x		-number of rows in matrix B
 *  argv[5] = x		-number of columns in matrix B
 */

#include 	/* for fork(), wait(), getpid(),	*/
#include 	/* for wait(), 				*/
#include 	/* for fork(), exec(), read()		*/
#include 	/* for printf(), scanf()		*/
#include 	/* for 					*/
#include 	/* for strcmp()				*/
#include 	/* for errno, EINTR			*/
#define YES 0
#define NO -1

void main(int argc,char *argv[]) {

   pid_t childpid;
   pid_t child1pid, child2pid, child3pid;   /* the children's process ID */
   int status, i;
   int addsubtract = YES;
   int multiply = YES;		
   char row[50], row3[50];
   int num_rows = atoi(argv[2]);

   if (argc != 6) {	/* check command line	*/
      printf("\n Error in usage. e.g. % matrix mat.dat 2 10 10 5 \n");
      exit(1);
   }

   /* Check to see if matrices can be add and subracted by comparing	*/
   /* the number of rows and columns of each.	
    */

   if ( strcmp(argv[2], argv[4]) || strcmp(argv[3], argv[5]) ) {
      fprintf(stderr, "\n These matrices cannot be added or subtracted. \n");
      addsubtract = NO;
   }

   /* The product of two matrices is not defined when the number of
    * columns in the first matrix and the number of rows in the second
    * matrix are not the same
    */

   if ( strcmp(argv[3], argv[4]) ) {
      fprintf(stderr, "\n These matrices cannot be multiplied. \n");
      multiply = NO;
   }

   for (i = 0; i < num_rows; i++) {

      sprintf(row, "%d", i*2); 	/* times 2 for every other even row */
      sprintf(row3, "%d", i); 	/* separate for 3rd child */

      if (addsubtract == YES) {
         if ((childpid = fork()) == -1) {
            printf("\n Error in 1st fork() \n.");
            exit(1);
         } else if (childpid == 0) { 
            if (execl("child1", "child1", argv[1], row, argv[3], NULL) < 0) {
               printf("\n Error in 1st exec1() \n");
	       exit(1);
            }
         }

         if ((childpid = fork()) == -1) {
            printf("\n Error in 2nd fork() \n.");
            exit(1);
         } else if (childpid == 0) {
            if (execl("child2", "child2", argv[1], row, argv[3], NULL) < 0) {
               printf("\n Error in 2nd exec1() \n");
               exit(1);
            }
         }
      } /* end if addsubtract == YES */

      if (multiply == YES) {

         if ((childpid = fork()) == -1) {   
            printf("\n Error in 3rd fork() \n.");
            exit(1);
         } else if (childpid == 0) {
            if (execl("child3", "child3", argv[1], row3, 
	               argv[2], argv[3], argv[5], NULL) < 0) {
               printf("\n Error in 3rd exec1() \n");
               exit(1);
            }
         }
      } /* end if multiply == YES */ 

      /* Because none of the forked children are parents, their wait()
       * returns -1 and sets errno to ECHILD (indicates that there no
       * un-waited-for child processes). They are not blocked
       * by this second for loop.  Their identification messages can come
       * out it any order.  The message for the original process comes
       * out at the very end after it has waited for all its children.
       */
      for ( ; ; ) {
         childpid = wait(&status);
         if ((childpid == -1) && (errno != EINTR)) /* signal interruption */
            break;
      }
/*      printf("\n I am process %ld, my parent is %ld. \n", (long)getpid(),
	 						(long)getppid());
 */        
   } /* end for() */
   exit(0);
}