#include<iostream.h>
// the next include is needed for ifstream
#include<fstream.h>
// the next include is needed for exit.
#include<stdlib.h>
// the next include is needed for strtok
#include<strings.h>

// SomeUniqueWords.C
// burton rosenberg 1 April 1997

// This program reviews arrays of pointers to strings,
// the use of new, and the string library, in particular,
// strtok, strlen, strcpy and strlen.

char * DELIMIT = " \t\n" ;

const int BUFFER_N = 500 ;
const int WORDS_N = 100 ; // number of unique words to track

void processWord( char * a[], int aSize, char * oneWord ) 
{
   int i ;

   i = 0 ;
   while ( (i < aSize) && // short-circuited AND!
           (a[i] != NULL) && 
           (strcmp(a[i], oneWord) != 0) )
   {
      // if we are here, then (1) i is a valid array index,
      // (2) the entry a[i] points to a string and (3) that
      // string does not equal oneWord

      i++ ;

   }

   // When we are here, then whiel CONDITION is false.
   // Using DeMorgan's Thm', then:
   // ASSERT: i>=aSize OR a[i]==NULL OR a[i] equals oneWord.
   // We are only interested in the case a[i]==NULL (assuming
   // i < aSize).

   if ( i<aSize && a[i]==NULL ) 
   {
      // we can add a new word.
      char * newString ;
      newString = new char[strlen(oneWord)+1] ;
      a[i] = strcpy( newString, oneWord ) ;
   }      
}

void processLine( char * a[], int aSize, char * line )
{
   char * aWord ;
   aWord = strtok( line, DELIMIT ) ;
   // work word by word
   while  (aWord!=NULL)
   {
      processWord( a, aSize, aWord ) ;
      aWord = strtok( NULL, DELIMIT ) ;
   }
}

void printArrayOfStrings( char * aos[], int n )
{
   int i ;
   for ( i=0; i<n; i++ )
   {
      cout << aos[i] << endl ;
   }
}

void bailOut( char * progName ) 
{
   cout << "usage: " << progName  << " filename" << endl ;
   exit(-1) ;
}

int main( int argc, char * argv[] ) 
{
   ifstream ifs ;
   char buffer[BUFFER_N] ;
   char * words[WORDS_N] ; // an array of pointers to char.

   if ( argc<2 ) 
   {
      bailOut( argv[0] ) ;
   }

   // initialize words array with all NULL's
   int i ;
   for ( i=0; i<WORDS_N; i++ )
   {
      words[i] = NULL ;
   }

   ifs.open(argv[1]) ;
   // check if open happened
   if ( !ifs ) 
   {
      // if open did not happen, ifs is left equal to "false"
      cout << "error: could not open " << argv[1] << endl ;
      exit(-1) ;
   }

   // work line by line
   while ( ifs.getline(buffer, BUFFER_N) )
   {
      processLine( words, WORDS_N, buffer ) ;
   } 
   ifs.close() ;  

   printArrayOfStrings( words, WORDS_N ) ;

   exit(0) ;

}
