#include <stdio.h>
#include <stdlib.h>
#include "../include/pvm3.h"

#define PROC 10

/* Ok, I'll admit it. I'm stealing two functions straight out of Ray's
   code. They are both already well-written and work, and I am just too
   lazy to go and rewrite what is already perfectly good and usable code
*/

int cryptoscan( char *buf , char *s , int begin , int *offset , int
*length ) ;
void cryptocount( char *buf , char *search_string , int *found_count ) ;

main() {
    int mytid; /* Holds this processes' tid */
    int me, i, msgtype; /* me is a number 0-9 associated with this
                           process, i is a counter, and msgtype is used
                           to verify messages sent between this process
                           and the master */
    int master; /* Holds the master's tid */
    char data[1000]; /* Holds the data string */
    char *search_str; /* Holds the string to be searched for within the
                         data string */
    int words = 0; /* Holds the number of times the search string is found
                      within the data string */
    int DONE; /* This is set to 1 when the master wishes to signal
                 that the program is finished. It is 0 otherwise. */

    mytid = pvm_mytid(); /* Get this process' tid and enroll in PVM */
    master = pvm_parent(); /* Get the master's tid */

    /* Begin by receiving DONE from the master, then checking to make sure
       that this process will in fact be used */
    msgtype = 0;
    pvm_recv(-1, msgtype);
    pvm_upkint(&DONE, 1, 1);

    /* If this process is used, then get the id of this process, the
       search string, and the data string from the master process. */
       
    if(!DONE) {
        pvm_upkint(&me, 1, 1);
        pvm_upkstr(search_str);
        pvm_upkstr(data);
       
        /* Count the number of times the search string is found in the
           data string */
        cryptocount(data, search_str, &words);
                
        /* Send this information to the master, along with the id of
           this process */
        msgtype = 1;
        pvm_initsend(PvmDataDefault);
        pvm_pkint(&me, 1, 1);
        pvm_pkint(&words, 1, 1);
        pvm_send(master, msgtype);
    }

    /* The following repeats until the program is finished */
    while(!DONE) {
        words = 0; /* Reset the word counter */
        
        /* Receive DONE from the master, and check to see if the program
           is finished */
        msgtype = 0;
        pvm_recv(-1, msgtype);
        pvm_upkint(&DONE, 1, 1);
        if(!DONE) {

            /* If it isn't, get the new data string from the master */
            pvm_upkstr(data);

            /* Count the number of times the search string appears in the
               data string */
            cryptocount(data, search_str, &words);
            
            /* Send the result as well as the id of this process back to
               the master */
            msgtype = 1;
            pvm_initsend(PvmDataDefault);
            pvm_pkint(&me, 1, 1);
            pvm_pkint(&words, 1, 1);
            pvm_send(master, msgtype);
        }
    }

    /* Exit pvm and end the program */
    pvm_exit();
    exit(0);
}

int cryptoscan( char *buf , char *s , int begin , int *offset , int
*length )
{
/*
Scans "buf" for the characters of "s", starting at "begin", and
returns the "offset" of the first character, and the "length" of
the string containing the the first through last characters.
 
The return-value for the function is the offset if found, or -1
if not found.

Note that the characters in buf are possibly separated by
non-alpha characters.  These are ignored for the purposes
of searching.

Both "buf" and "s" are assumed to be null-terminated strings.

"s" is assumed to contain only alpha characters.
*/
  
int i ;     /* index in buf */
int j ;     /* index in s */
int start ; /* temporary variable that holds the tentative start
               for a string in buf */

i = begin ; 
start = i ;
j = 0 ;
while ( 1 )
  {
  /* if we're at the end of the search string, stop */
  if ( s[j] == '\0' )
    break ;

  /* ignore non-alpha chars */
  while ( ! ( isalpha( buf[i] ) || buf[i] == '\0' ) )
    i ++ ;

  /* if we're at the end of the buffer, stop */
  if ( buf[i] == '\0' )
    break ;

#ifdef debug
  printf( "buf[%d] %c  s[%d] %c\n" , i , buf[i] , j , s[j] ) ;
#endif

  /* compare the current (alphabetic characters in each string) */
  if ( tolower( buf[i] ) == tolower( s[j] ) )
    {
    /* save our starting point if this is the first character */
    if ( j == 0 )
      start = i ;
    /* increment both counters and continue searching */
    i ++ ; 
    j ++ ;
    }
  else
    {
    /* restart searching at the character following our previous start */
    i = start + 1 ;
    j = 0 ;
    start = i ;
    }
  }

/* 
if j incremented to the length of the search string, 
then the whole string was found and we return offset and length
otherwise we return not found (-1).
*/
if ( j == strlen( s ) )
  {
  *offset = start ;
  *length = i - start ;
  return( start ) ;
  }
else
  return( -1 ) ;
}

void cryptocount( char *buf , char *search_string , int *found_count )
/*
repeatedly calls cryptoscan to search a buffer (buf)
for a search_string, and increments found_count for
each occurrence.  Note that found_count is not 
initialized by this routine, only incremented;
before calling this routine for the first time, you
should initialize found_count.
*/
{
int p ;  /* current search position */
int found ;  /* where found, relative to the beginning of the buffer */
int length ;  /* length of found string, including non-alpha characters */

p = 0 ;
while( 1 )
  {
  p = cryptoscan( buf , search_string , p  , &found , &length ) ;
  if( p > 0 )
    {
#ifdef debug
    printf( "found at offset %d  length %d  \"" , found , length ) ;
    for( i = found ; i < found + length ; i ++ )
      putchar( buf[i] ) ;
    putchar( '\"' ) ;
    putchar( '\n' ) ;
#endif
    (*found_count) ++ ;
    p = found + length ;
    }
  else
    break ;
  }
}
