/* Obfuscated V contest entry by David Mazieres */ #include #include #include #include #include #include #define NUMCHECK_NEGATIVE 0x01 /* Number is negative */ #define NUMCHECK_NONNEGATIVE 0x02 /* Number is not negative */ #define NUMCHECK_BIGGERTHANINT 0x04 /* Number cannot be contained in an int*/ #define NUMCHECK_ISMIN 0x08 /* Number is minimum singed long value */ #define NUMCHECK_ISMAXSIGNED 0x10 /* Number is max signed long value */ #define NUMCHECK_ISMAXUNSIGNED 0x20 /* Number is max unsigned long value */ #define NUMCHECK_OKTOADDONE 0x40 /* Number + 1 > number (no overflow) */ /* * This macro returns the properties of the number n, as specified * above. Note that this has to be a macro and not a function, * because for the BIGGERTHANINT and OKTOADDONE tests we want to make * sure we have an object of the appropriate type. (If NUMCHECK were * a function taking an unsigned long, then it would always report the * same thing for these tests). * * Very important: IT IS AN ERROR TO CALL NUMCHECK IF THE ARGUMENT * HAS SIDE EFFECTS. In other words, NUMCHECK (i++) is a serious * error, because the argument will be evaluated multiple times. */ #define NUMCHECK(result, n) \ do { \ result = 0; \ if ((n) < 0) \ result |= NUMCHECK_NEGATIVE; \ if ((n) >= 0) \ result |= NUMCHECK_NONNEGATIVE; \ if (sizeof (n) > sizeof (int)) \ result |= NUMCHECK_BIGGERTHANINT; \ if ((n) == LONG_MIN) \ result |= NUMCHECK_ISMIN; \ if ((n) == LONG_MAX) \ result |= NUMCHECK_ISMAXSIGNED; \ if ((n) == (unsigned long) -1) \ result |= NUMCHECK_ISMAXUNSIGNED; \ if (((n) + ((char) 1)) > (n)) \ result |= NUMCHECK_OKTOADDONE; \ result; \ } while (0) /* * Make sure a vote tally doesn't become so large that it wraps. * * Note how we copy val because NUMCHECK is not safe if val has side * effects (see above). This does mean we are assuming val is an * unsigned long, which is okay because tally is defined that way. * For good measure, we do assert that the size of val is the same as * an unsigned long, but this will still be true if val is of type * long, in which case OKTOADDONE would get the wrong value. The * bottom line is, MAKE SURE val IS OF TYPE unsigned long! * * Some of these asserts are obviously redundant, but its better to be * safe than sorry... The more things we cross-check the less chance * of some bug getting through. */ #define check_overflow(val) \ do { \ unsigned long val2 = (val); \ int res; \ assert (sizeof (val) == sizeof (val2)); \ NUMCHECK (res, val2); \ assert (!(res & NUMCHECK_NEGATIVE)); \ assert (res & NUMCHECK_NONNEGATIVE); \ assert (!(res & NUMCHECK_ISMAXUNSIGNED)); \ assert (res & NUMCHECK_OKTOADDONE); \ } while (0); /* * This macro actually tabulates a vote for candidate val and * increases the total. It does not first check if val is * whitespace--you have to do so before calling tabluate, since we * don't want whitespace characters to cause gratuitous votes for * Other. */ #define tabulate(val) \ do { \ ptrdiff_t c = val; \ assert (c >= 0); /* paranoia... */ \ assert (c < 256); /* paranoia... */ \ Tally[c]++; \ total++; \ } while (0) int main (int argc, char **argv) { int c; unsigned long total = 0; unsigned long Tally[256]; memset (Tally, 0, sizeof (Tally)); while ((c = getchar ()) != EOF) if (!isspace (c)) { check_overflow (Tally[c & 0xff]); tabulate (c); } printf ("Kerry %ld\n", Tally['K']); printf ("Bush %ld\n", Tally['B']); printf ("Nader %ld\n", Tally['N']); printf ("Other %ld\n", total - Tally['K'] - Tally['B'] - Tally['N']); return 0; }