text: // speller.c CC50 Pset6 Implements a spell-checker.
  
  #include <ctype.h>
  #include <stdio.h>
  #include <sys/resource.h>
  #include <sys/time.h>
  #include "dictionary.h"
  
  // default dictionary
  #define WORDS "words"
  
  // prototype
  double calculate(const struct rusage *b, const struct rusage *a);
  
  int
  main(int argc, char *argv[])
  {
      // check for correct number of args
      if (argc != 2 && argc != 3)
      {
          printf("Usage: speller [dict] file\n");
          return 1;
      }
  
      // structs for timing data
      struct rusage before, after;
  
      // benchmarks
      double ti_load = 0.0, ti_check = 0.0, ti_size = 0.0, ti_unload = 0.0;
  
      // determine dictionary to use
      char *dict = (argc == 3) ? argv[1] : WORDS;
  
      // load dictionary
      getrusage(RUSAGE_SELF, &before);
      bool loaded = load(dict);
      getrusage(RUSAGE_SELF, &after);
  
      // abort if dictionary not loaded
      if (!loaded)
      {
          printf("Could not load %s.\n", dict);
          return 2;
      }
  
      // calculate time to load dictionary
      ti_load = calculate(&before, &after);
  
      // try to open file
      char *file = (argc == 3) ? argv[2] : argv[1];
      FILE *fp = fopen(file, "r");
      if (fp == NULL)
      {
          printf("Could not open %s.\n", file);
          unload();
          return 3;
      }
  
      // prepare to report misspellings
      printf("\nMISSPELLED WORDS\n\n");
  
      // prepare to spell-check
      int index = 0, misspellings = 0, words = 0;
      char word[LENGTH+1];
  
      // spell-check each word in file
      for (int c = fgetc(fp); c != EOF; c = fgetc(fp))
      {
          // allow only alphabetical characters and apostrophes
          if (isalpha(c) || (c == '\'' && index > 0))
          {
              // append character to word
              word[index] = c;
              index++;
  
              // ignore alphabetical strings too long to be words
              if (index > LENGTH)
              {
                  // consume remainder of alphabetical string
                  while ((c = fgetc(fp)) != EOF && isalpha(c));
  
                  // prepare for new word
                  index = 0;
              }
          }
  
          // ignore words with numbers (like MS Word can)
          else if (isdigit(c))
          {
              // consume remainder of alphanumeric string
              while ((c = fgetc(fp)) != EOF && isalnum(c));
  
              // prepare for new word
              index = 0;
          }
  
          // we must have found a whole word
          else if (index > 0)
          {
              // terminate current word
              word[index] = '\0';
  
              // update counter
              words++;
  
              // check word's spelling
              getrusage(RUSAGE_SELF, &before);
              bool misspelled = !check(word);
              getrusage(RUSAGE_SELF, &after);
  
              // update benchmark
              ti_check += calculate(&before, &after);
  
              // print word if misspelled
              if (misspelled)
              {
                  printf("%s\n", word);
                  misspellings++;
              }
  
              // prepare for next word
              index = 0;
          }
      }
  
      // check whether there was an error
      if (ferror(fp))
      {
          fclose(fp);
          printf("Error reading %s.\n", file);
          unload();
          return 4;
      }
  
      // close file
      fclose(fp);
  
      // determine dictionary's size
      getrusage(RUSAGE_SELF, &before);
      unsigned int n = size();
      getrusage(RUSAGE_SELF, &after);
  
      // calculate time to determine dictionary's size
      ti_size = calculate(&before, &after);
  
      // unload dictionary
      getrusage(RUSAGE_SELF, &before);
      bool unloaded = unload();
      getrusage(RUSAGE_SELF, &after);
  
      // abort if dictionary not unloaded
      if (!unloaded)
      {
          printf("Could not unload %s.\n", dict);
          return 5;
      }
  
      // calculate time to unload dictionary
      ti_unload = calculate(&before, &after);
  
      // report benchmarks
      printf("\nWORDS MISSPELLED:     %d\n", misspellings);
      printf("WORDS IN DICTIONARY:  %d\n", n);
      printf("WORDS IN FILE:        %d\n", words);
      printf("TIME IN load:         %.2f\n", ti_load);
      printf("TIME IN check:        %.2f\n", ti_check);
      printf("TIME IN size:         %.2f\n", ti_size);
      printf("TIME IN unload:       %.2f\n", ti_unload);
      printf("TIME IN TOTAL:        %.2f\n\n", ti_load + ti_check + ti_size + ti_unload);
  
      // that's all folks
      return 0;
  }
  
  // Returns number of seconds between b and a.
  
  double
  calculate(const struct rusage *b, const struct rusage *a)
  {
      if (b == NULL || a == NULL)
          return 0;
      else
          return ((((a->ru_utime.tv_sec * 1000000 + a->ru_utime.tv_usec) -
                   (b->ru_utime.tv_sec * 1000000 + b->ru_utime.tv_usec)) +
                  ((a->ru_stime.tv_sec * 1000000 + a->ru_stime.tv_usec) -
                   (b->ru_stime.tv_sec * 1000000 + b->ru_stime.tv_usec)))
                  / 1000000.0);
  }
  