/*
  pgrep.c
  Jim Garlick
  2/23/99

  This program is an parallelization of a program written by Ray Ontko that
  counts the occurrances of a string in a text file. The program depends on
  a library which contains the code from that original program, pgreplib.c.
  The library functions were separated to make the source code for the master
  and the slave programs easier to manage.
  
  The architecture is fairly straight forward. The master is in charge of 
  reading in the search file, spawning the child processes, managing the child
  processes and processing the results.
*/

#include <stdio.h>
#include <ctype.h>
#include "pvm3.h"
#include "pgrep.h"

int main(int argc, char *argv[]) {
  /* File variables */
  char filename[256];
  FILE *input;
  
  /* Process information */
  int my_tid, tid, tids[32], buf_id, msg;
  int nhost, narch, num_spawned, active;
  struct pvmhostinfo *hostp;
  
  /* Program Specific Info */
  char search_str[STR_SIZE];        /* String we are searching for */
  char buf[BUF_SIZE+1];        /* Buffer containing parts of the textfile */
  int tmplen;
  /* Ray's stuff */
  int siz ;  /* number of bytes read into buffer */
  int p;  /* current search offset within the buffer */
  int i;
  int found_count, count;
  int preset;
  int last;

    /* Get info from command line */
  if (argc != 3) {
    fprintf(stderr, "Usage: pgrep <search-string> <search-filename>\n");
    exit(1);
  }
  strcpy(search_str, argv[1]);
  strcpy(filename, argv[2]);
  
    /* Open the file for reading */
  if ((input = fopen(filename, "r")) == NULL) {
    fprintf(stderr, "Error opening %s\n", filename);
    exit(1);
  }

    /* Everything's okay...start PVM */ 
  my_tid = pvm_mytid();               /* Get my task id */
  pvm_config(&nhost, &narch, &hostp); /* Get virtual machine configuration */

    /* Start up child processes */;
  num_spawned = pvm_spawn(SLAVE_NAME, 0, PvmTaskDefault, "", nhost, tids);
  active = 0;
  nhost = num_spawned;
  if (num_spawned < 1) {
    fprintf(stderr, "Sorry, not enough hosts.\n");
    exit(1);
  }
    /* Tell all of the spawned processes to "WAIT" */
  pvm_initsend(PvmDataDefault);
  pvm_mcast(tids, nhost, WAIT);
  printf("%d spawned and waiting.\n", num_spawned);

    /* Initialize the number of matches */
  found_count = 0;

  /*
    This loop is important because it is responsible for making buffers that
    contain the necessary overlap.
  */
  while((siz = fread(buf+preset, 1, BUF_SIZE-preset, input)) > 0) {
    buf[preset+siz] = '\0' ;

    /* Receive a waiting process */
    buf_id = pvm_recv(-1, -1); 
    /* Determine who sent it and what they said. */
    pvm_bufinfo(buf_id, 0, &msg, &tid);

    switch (msg) {
      /* If the process is done processing */
      case DONE:
	  /* Decrement the number of active processes*/
	active--;
	  /* Unpack the fount_count */
	pvm_upkint(&count, 1, 1);
	  /* Update the number of matches */
	found_count += count;

      /* If the process is available for use */
      case AVAILABLE: 
	/* Send the next chunk to the slave */
          /* initialize the buffers */
	pvm_initsend(PvmDataDefault);
	  /* Pack up the search string and the text buffer */
        pvm_pkstr(search_str);
	pvm_pkstr(buf);
	  /* Send the buffer to the available tid and tell the child
	     to "WORK_ON_THIS" */
	pvm_send(tid, WORK_ON_THIS);
	  /* Increment the number of active processes */
	active++;
	break;
    }

      /* Look in pgreplib.c for info about this function */
    if( last_n_alphas( buf , strlen(search_str) - 1 , &last ) >= 0 ) {
        /* Update the buffer */
      strcpy( buf , buf+last ) ;
      preset = preset + siz - last ;
    }
    else
      preset = 0 ;
  }

  /* Now we need to wait for the last of the processes to finish */
  while (active > 0) {
      /* Recieve all of the processes that are finishing up */
    buf_id = pvm_recv(-1, DONE);
      /* Get which process it was */
    pvm_bufinfo(buf_id, 0, 0, &tid);
      /* Tell the process to wait */
    pvm_initsend(PvmDataDefault);
    pvm_send(tid, WAIT);

      /* Unpack the count */
    pvm_upkint(&count, 1, 1); 
      /* Update the match count */
    found_count += count;
      /* Decrement the number of active processes */
    active--;
  }

    /* Tell all of the processes to die */
  pvm_initsend(PvmDataDefault);
  pvm_mcast(tids, nhost, DIE);

    /* Print out our results */
  printf("Found %d occurances of \"%s\"\n", found_count, search_str);

    /* Quit PVM and exit */
  pvm_exit();
  exit();
}
