#include <stdio.h>
#include <string.h>
#include <iostream>
#include "garray.h"

int charOk(char c, char * badString) {

  for (;*badString && c != *badString; badString++);

  if (!(*badString)) return 1;
                     return 0;
}

void print_out(garray &keep_W, int in_block, char *badString) {
  int  i;

  for (i = 0; keep_W[i];i++)
    if (in_block && charOk(keep_W[i], badString))/* Only output if we are in a block. */
    {  if (keep_W[i] == '\\') i++;
       putc(keep_W[i], stdout); 
    }
   keep_W.clear();
}


enum states { 
  WAITING_FOR_TOKENS, 
  WAITING_U, 
  WAITING_S, 
  WAITING_A, 
  WAITING_G, 
  WAITING_E, 
  READING_DONE 
};

states prog_state = WAITING_FOR_TOKENS;

int check_case(char cur_ch, char to_check, garray& keep_W, states newState,
               int in_block, char* IgnoreChars) {
  if (cur_ch == to_check) {
    prog_state = newState;
    return 1;
  } else {
    prog_state = WAITING_FOR_TOKENS;
    keep_W.Put(cur_ch);
    print_out(keep_W, in_block, IgnoreChars);
    return 0;
  }
}

int main(int argc, char **argv) {
  int in_block = 0;
  char c, *tokens, *IgnoreChars = ((argc == 4) ? argv[3]:0);
  FILE *fl;
  // keep_T == keep Token, for the beginning characters of the block.
  // keep_W == keep word, the beginning keyword for the block
  garray keep_W;

  if (argc < 3) {
    printf("Usage: %s <filename> <usage-begin-end> [ignore characters]\n"
           "  <filename>  -- filename to extract usage from.\n"
           "  <usage-begin-end> -- what characters are used to indicate\n"
           "                       the beginning and end of the usage.\n"
           "                       Note that this program will look for\n"
           "                       these characters followed by 'USAGE'\n"
           "                       To begin the usage, and these characters\n"
           "                       followed by 'USAGE' to end the block.\n"
           "  <ignore characters> -- This is a string of characters neglect\n"
           "                       output of.\n", 
           argv[0]);
    exit(1);
  }
  
  if (!(fl = fopen(argv[1], "r"))) {
    printf("That is not a valid filename.\n\n");
    exit(1);
  }
  
  c = getc(fl);
  while ((prog_state != READING_DONE) && !feof(fl)) {

   switch(prog_state) {
        case WAITING_FOR_TOKENS:
          if ((tokens && c == *tokens) || c == *argv[2]) { 

            keep_W.Put(c);

            if (!tokens) tokens = argv[2]+1;
            else tokens = tokens++;
  
            if (!(*tokens))         // we have reached the end of the tokens...
              prog_state = WAITING_U;
          } else {
            if (keep_W.size()) print_out(keep_W, in_block, IgnoreChars);
            if (in_block && charOk(c, IgnoreChars)) {
              if (c == '\\') c = getc(fl);
              putc(c, stdout);
            }
            tokens = 0;
          }                
          break;
        case WAITING_U:
          if (!isspace(c))
            check_case(c, 'U', keep_W, WAITING_S, in_block, IgnoreChars);
          break;
        case WAITING_S:
          check_case(c, 'S', keep_W, WAITING_A, in_block, IgnoreChars);
          break;
        case WAITING_A:
          check_case(c, 'A', keep_W, WAITING_G, in_block, IgnoreChars);
          break;
        case WAITING_G:
          check_case(c, 'G', keep_W, WAITING_E, in_block, IgnoreChars);
          break;
        case WAITING_E:
          if (check_case(c, 'E', keep_W, WAITING_FOR_TOKENS, in_block, IgnoreChars))
            if (in_block) prog_state = READING_DONE;
            else {
              in_block = 1;
              while (c != '\n' && !feof(fl)) 
                c = getc(fl);
              keep_W.clear();
            }
          break;
        default:
          check_case('A', 'B', keep_W, WAITING_FOR_TOKENS, 0, IgnoreChars);
          break;
       }
      c = getc(fl);
  } /* while (!done && !feof(fl)) */

  /* either end of file, or we are done.. */
  fclose(fl);
  return 0;

}
