# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <ctype.h>

# include "table.h"
# include "getword.h"

# define MAX 65
# define HINT 256

static void nomem (void)
{
  fputs ("Fatal: out of memory\n", stderr);
  exit (1);
}

static void *allocate (size_t s)
{
  void *x = malloc (s);
  if (!x)
    nomem ();
  return x;
}

static void enter_word (char *word, Table_T table)
{
  int *i = Table_get (table, word);

  if (i == NULL) {
    i = allocate (sizeof (int));
    *i = 0;
    Table_put (table, word, i);
  }
  (*i)++;
}

static int first (char c)
{
  return isalpha (c) || (c == '_');
}

static int rest (char c)
{
  return first (c) || isdigit (c);
}

static void process_file (FILE *fp, Table_T table)
{
  char buf [MAX];

  while (getword (fp, buf, MAX, first, rest) != EOF)
    enter_word (buf, table);
}

struct assoc {
  char *word;
  int count;
};

static void apply (char *word, void **value, void *cl)
{
  struct assoc **a = cl;
  int *i = *value;

  (*a)->word = word;
  (*a)->count = *i;
  (*a)++;
  free (i);
}

static struct assoc *table2array (Table_T table, int len)
{
  struct assoc *a, *tmp;

  a = allocate (len * sizeof (struct assoc));
  tmp = a;
  Table_map (table, apply, &tmp);
  return a;
}

static int cmpa (const void *x, const void *y)
{
  const struct assoc *a = x, *b = y;

  return a->count - b->count;
}

static void sorta (struct assoc *a, int len)
{
  qsort (a, len, sizeof (struct assoc), cmpa);
}

static void print1 (struct assoc *a)
{
  printf ("%s\t%d\n", a->word, a->count);
}

static void printa (struct assoc *a, int len, int n)
{
  int i;

  if (n >= 0)
    for (i = len - 1; i >= 0 && a[i].count >= n; i--)
      print1 (a + i);
  else {
    n = -n;
    for (i = 0; i < len && a[i].count <= n; i++)
      print1 (a + i);
  }
}

int main (int argc, char **argv)
{
  Table_T table;
  int n = 0;
  int len;

  if ((table = Table_new (HINT, strcmp)) == NULL)
    nomem ();

  if (argc > 1 && (argv[1][0] == '+' || argv[1][0] == '-')) {
    char *endptr;
    int x = strtol (argv [1], &endptr, 10);
    if (*endptr == '\0') {
      n = x;
      argc--;
      argv++;
    }
  }

  if (argc > 1)
    while (--argc > 0) {
      FILE *fp = fopen (*++argv, "r");
      if (fp) {
	process_file (fp, table);
	fclose (fp);
      } else
	fprintf (stderr, "Can't open `%s'\n", *argv);
    }
  else
    process_file (stdin, table);
    
  if ((len = Table_length (table)) != 0) {
    struct assoc *a = table2array (table, len);
    sorta (a, len);
    printa (a, len, n);
    free (a);
  }
  Table_free (&table);

  return 0;
}

Matthias Blume, CS Department, Princeton University