
/* words.c 
   A program using hashlib.c to keep a count of the number of occurrences
   of words in a text file and the pages on which they occure.
*/

#include <stdio.h>
#include <ctype.h>
#include "userdefs.h"
#include "hashdefs.h" 
#define FALSE 0
#define TRUE  1

#define PAGELENGTH 80
#define STRLENGTH 19

extern char* malloc();

char* retkey(data)
  element   *data;
  {
    if (data == NULL)
        return NULL;
    else
        return data->word;        
  }
    
  /* note that there is no need to copy page lists */
void copyelement(one, two)
  element   *one, *two;
  {
    (void) strcpy(one->word, two->word);
    one->occurrences = two->occurrences;
    one->start_page_list = NULL;
    one->end_page_list = NULL;
  }
  
  /* Used to free the linked list of page numbers that is part of an
   element. */
void deleteelement(data)
  element   *data;
  {
    struct plist    *cur, *next;
    
    if ((data == NULL) || ( (cur = data->start_page_list) == NULL))
        return;
        
    for (next = cur->next ; next != NULL; cur = next, next = next->next)
        free ((char *) cur); 
    free ((char *) cur);
  }
  
short copyword(pos, one, two)
  char  one[], two[];
  short *pos;
  {
    short i;

    if (two[*pos] == '\0')
        return (FALSE);    
    while (!isalpha(two[*pos]))
        if (two[++(*pos)] == '\0')
            return (FALSE);
    for (i = 0; two[*pos] != '\0' && isalpha(two[*pos]) && i < STRLENGTH;
        (*pos)++, i++)
        one[i] = tolower(two[*pos]);
    one[i] = '\0';
    return (TRUE);
  }

  /* Adds a new page to the page list for the word stored in info. */
void add_occurance(info, page)
  element   *info;
  short     page;
  {
    struct plist    *temp;
    
    if ((info->end_page_list != NULL) && (info->end_page_list->page == page))
        return;

    if ( (temp = (struct plist*) malloc (sizeof(struct plist))) == NULL)
      {
        fprintf(stderr, "Out of memory!\n");
        exit(10);
      }
    temp->next = NULL;
    temp->page = page;

    if (info->start_page_list == NULL)
        info->start_page_list = temp;
    else
        info->end_page_list->next = temp;
    info->end_page_list = temp;    
  }

void printpages(word)
  element   *word;
  {
    struct plist    *cur;
    
    for (cur = word->start_page_list; cur != NULL; cur = cur->next)
        printf(" %hd ", cur->page);
    printf("\n");
  }


main(ac, av)
  int   ac;
  char  *av[];
  {
    FILE    *text_file;
    char    buffer[250], word[250];
    short   line, page, pos;
    element *info, entry;    
    long    length;
    
    
    if (ac != 3)
      {
        fprintf(stderr, "USEAGE: %s <text file> <length>\n", av[0]);
        exit (5);
      }

    if ((text_file = fopen(av[1], "r")) == NULL)
      {
        fprintf(stderr, "Could not open file %s.\n", av[1]);
        exit(5);
      } 
    sscanf(av[2], "%ld", &length);
        
    if ( makehash((long) length) == FALSE)
      {
        fprintf(stderr, "Could not make hash table of size %ld.\n", length);
        exit (10);
      }

    /*  Loop through all the input updating data information as
        necessary.*/ 
    for(page=1, line=1; fgets(buffer, 250, text_file); line++)
      {
        if (line == PAGELENGTH)
          {
            line = 1; 
            page++;
          }
        for (pos = 0; copyword(&pos, word, buffer) ; )
          {
            if ( (info = findhash(word)) == FALSE)
              {
                entry.occurrences = 0;
                (void) strcpy(entry.word, word);
                info = inserthash(&entry);
              }
            (info->occurrences) += 1;
            add_occurance(info, page);
          }
      }
    
    /* Display all the accumulated data. Notice the initial and termination
       conditions used with dupmhash(). */
    for (info = dumphash(NULL); info != NULL; info = dumphash(info->word) )
      {
        printf("%s (%hd) ", info->word, info->occurrences);
        printpages(info);
      }
      
    fclose(text_file);
    freehashtable();
  }
