/*
 * ------------------------------------ 
 * Bullet-Proof Extensible Vote Counter
 * ------------------------------------
 *
 * In response to Daniel Horn's abominable, sick and twisted idea of running
 * a contest for programs that skew election results, I decided to counter 
 * his efforts by providing this program that not only counts votes perfectly
 * well, but also goes great lengths to verify data integrity in case of 
 * unforseen flaws or tampering attempts.
 *
 * I did not rely on his proposed vote counting framework, noting that
 * first and foremost, it could be already backdoored, and second, that
 * it does not scale well.
 *
 *   -- Michal Zalewski <lcamtuf@coredump.cx>
 *
 */


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

/* Error reporting macro */
#define fatal(x) do { fprintf(stderr,"ERROR: %s\n",x); exit(1); } while (0)

#define CHECK_INTERVAL	10	     /* How often to check database? */
#define VOTE_LIMIT      300000000    /* Maximum number of votes possible */


/* Candidates and vote count. Can be extended and modified at will.
   The last entry should be NULL, reserved for "other". */
struct candidate { char* name; unsigned int votes; } tally[] = {
  { "Bush" , 0 },
  { "Kerry", 0 },
  { "Nader", 0 },
  {  NULL  , 0 }
};

/* Total vote count - used to validate individual vote counts. */
unsigned int total = 0;

/* Display all results, including the trailing NULL ("other"). */
void show_results(void) {
  struct candidate* t = tally;
  do printf("%-8s : %u\n", t->name ? t->name : "Other", t->votes);
    while ((t++)->name);
}

/* Safely count vote. Every CHECK_INTERVAL votes, run a database integrity
   check to detect corrupted vote counts or candidate names; otherwise,
   just count the vote. */
#define VOTE_AND_CHECK(v) do { \
    if (!(total % CHECK_INTERVAL)) { \
      struct candidate* t = tally; \
      unsigned int cur_tot = 0; \
      /* Verify that votes add up to the right count... */ \
      do cur_tot += t->votes; while ((t++)->name); \
      if (cur_tot != total) fatal("Vote count tampering!"); \
      /* Go back through entries and verify every name... */ \
      t--; \
      while ((--t) != tally) \
        if (!t->name || !isupper(*t->name)) fatal("Candidate tampering!"); \
      /* Count vote, checking for erratic numbers */ \
      if ((v)++ >= VOTE_LIMIT) fatal("Too many voters!"); \
    } else (v)++; \
    total++; \
  } while (0)

/* Add one vote for candidate whose initial is given by c. If no
   matching candidate found, account as "other". */
void process_vote(unsigned char c) {
  struct candidate* t = tally;
  while (t->name) {
    if (t->name[0] == c) { 
      VOTE_AND_CHECK(t->votes); 
      return; 
    }
    t++;
  }
  VOTE_AND_CHECK(t->votes);
}


/* Run the elections! */
int main(int argc,char** argv) {
  int c;
  /* Read and process votes */
  while ((c=getchar()) != EOF) 
    if (!isspace(c)) process_vote(c);
  /* And the winner is... */
  show_results();
  return 0;
}

