diff --git a/.gitignore b/.gitignore
index 7bd36bf93b53402a42c0988343b536a38f63139e..19e3f191889588c8abe151b17d4e16ac9efdcab9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 *~
 *.a
 src/test_suite
+lib/hush
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d6205afb0df6714a83afba5950b5c983cc456a58
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
+# Most of this is so that you can do
+# $ make all
+# and kick off a recursive make
+# Also, "make src/all" turns into "make -C src all"
+
+SUBDIRS = src \
+	  lib
+
+.DEFAULT_GOAL := all
+
+%:
+	+for dir in $(SUBDIRS); do $(MAKE) -C $${dir} $@; done
+
+define SUBDIR_TEMPLATE
+$(1)/%:
+	$$(MAKE) -C $(1) $$*
+endef
+
+$(foreach dir,$(SUBDIRS),$(eval $(call SUBDIR_TEMPLATE,$(dir))))
+
+#.DEFAULT:
+#	$(if $(findstring ./,$(dir $@)),$(error No rule to make target `$@'),$(MAKE) -C $(dir $@) $(notdir $@))
\ No newline at end of file
diff --git a/common.mk b/common.mk
index 70f453b98b1216b4a722cd09d0bcc72b510fede5..57e80ddce26ef183d36664f3618f8bc0f9f92ce0 100644
--- a/common.mk
+++ b/common.mk
@@ -1,19 +1,36 @@
-CFLAGS := $(shell pkg-config --cflags glib-2.0) -std=gnu99
+CFLAGS := $(shell pkg-config --cflags glib-2.0) -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter
 LDFLAGS := $(shell pkg-config --libs glib-2.0)
 CC := gcc
-
+# Set V=1 for verbose mode...
+V := 0
 CFLAGS += -DINCLUDE_TESTS
+HUSH = $(TOPLEVEL)/lib/hush
+
+# Check to make sure variables are properly set
+ifeq ($(TOPLEVEL),)
+$(error $$TOPLEVEL is unset)
+endif
+
+ifsilent = $(if $(findstring 0, $(V)),$(1),)
+hush = $(call ifsilent,$(HUSH) $(1))
+#.SUFFIXES:
 
-.SUFFIX:
+ifeq ($(V),0)
+.SILENT:
+endif
 
 .DEFAULT_GOAL:=all
 
-%.a:
+%.a: $(call ifsilent,| $(HUSH))
 	-rm -f $@
-	ar crv $@ $^
+	$(call hush,"Archiving $@") ar cr $@ $^
 
-%.o: %.c
-	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.c $(call ifsilent,| $(HUSH))
+	$(call hush, "Compiling $<") $(CC) $(CFLAGS) -c -o $@ $<
 
 clean:
 	-rm -f $(OUTPUTS)
+
+$(TOPLEVEL)/lib/hush: $(TOPLEVEL)/lib/hush.c
+	make -C $(TOPLEVEL)/lib hush
diff --git a/lib/Makefile b/lib/Makefile
index d95ec6b482afe493a3cbc25b74e48dcbd0617a34..a6b11b66aaebc508c813c29f158dbe3a61be85fe 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,12 @@
-include ../common.mk
 
 OUTPUTS := \
 	allocator.o
 
+TOPLEVEL := ../
+
+include ../common.mk
+
 all: allocator.o
 
+hush: hush.c
+	$(CC) $(CFLAGS) -o $@ $<
diff --git a/lib/hush.c b/lib/hush.c
new file mode 100644
index 0000000000000000000000000000000000000000..23926d6d50b64151f87d9be939d36c0d2fb9b764
--- /dev/null
+++ b/lib/hush.c
@@ -0,0 +1,64 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main (int argc, char** argv) {
+	// Argv[1] is the message
+	// argv[2] is the name of the child
+	// the rest are passed to the child
+	if (argc < 3) return 1;
+	printf ("\x1b[1;32m*\x1b[0m %s...", argv[1]);
+	char cbuf[4096];
+	argc-=2;
+	argv+=1;
+	for (int i = 0; i < argc; i++)
+		argv[i] = argv[i+1];
+	argv[argc] = NULL;
+	int fd[2];
+
+	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fd) == -1) {
+		printf ("\n");
+		execvp(argv[0], argv);
+	}
+	int pid;
+	if ((pid=fork()) == -1) {
+		printf ("\n");
+		execvp(argv[0], argv);
+	} else if (pid == 0) { // child
+		printf ("Child");
+		close(fd[1]);
+		dup2(fd[0],0);
+		dup2(0,1);
+		dup2(0,2);
+		execvp(argv[0], argv);
+	} else { // parent
+		char* cols1 = getenv("COLUMNS");
+		int cols;
+		if (cols1) { cols = atoi(cols1); } else { cols = 80; }
+		close(fd[0]);
+		int delta = 1;
+		int ct = 0;
+		while (delta != 0) {
+			delta = read (fd[1], cbuf+ct, 4096-ct);
+			ct+= delta;
+		}
+		cbuf[ct] = 0;
+		int status;
+		wait(&status);
+		fflush (NULL);
+		if (status) {
+			fprintf (stderr, "\x1b[%dG\x1b[1;34m[\x1b[1;31m!!\x1b[1;34m]\x1b[0m\n", cols-4);
+		} else if (ct) {
+			fprintf (stderr, "\x1b[%dG\x1b[1;34m[\x1b[0;33mWW\x1b[1;34m]\x1b[0m\n", cols-4);
+		} else {
+			fprintf (stderr, "\x1b[%dG\x1b[1;34m[\x1b[1;32mOK\x1b[1;34m]\x1b[0m\n", cols-4);
+		}
+		fflush (NULL);
+		printf ("%s", cbuf);
+		fflush (NULL);
+		return WEXITSTATUS(status);
+	}
+}
diff --git a/src/Makefile b/src/Makefile
index e9f76f2b165ea8340db0317bed306eeeab278455..7e006c512acd4f8f868067445f6f07de17996133 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,14 +1,18 @@
--include ../common.mk
 
 OUTPUTS := bitreader.o \
 	   hammer.o \
 	   libhammer.a \
 	   test_suite
 
+TOPLEVEL := ../
+
+include ../common.mk
+
+
 all: libhammer.a test_suite
 
 test_suite: test_suite.o libhammer.a
-	$(CC) -o $@ $^ $(LDFLAGS)
+	$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
 
 libhammer.a: bitreader.o hammer.o
 
diff --git a/src/bitreader.c b/src/bitreader.c
index b1f91fe81b8fb2c30faab4c6922ab8b64e9f2535..6d5f784d7559fad87dbbd1c643b4c47333433cd9 100644
--- a/src/bitreader.c
+++ b/src/bitreader.c
@@ -12,41 +12,54 @@ long long read_bits(input_stream_t* state, int count, char signed_p) {
   long long out = 0;
   int offset = 0;
   long long msb = (!!signed_p) << (count - 1); // 0 if unsigned, else 1 << (nbits - 1)
-  while (count) {
-    int segment, segment_len;
-    // Read a segment...
-    if (state->endianness & BIT_BIG_ENDIAN) {
-      if (count >= state->bit_offset) {
-	segment_len = state->bit_offset;
-	state->bit_offset = 8;
-	segment = state->input[state->index] & ((1 << segment_len) - 1);
-	state->index++;
-      } else {
-	segment_len = count;
-	state->bit_offset -= count;
-	segment = (state->input[state->index] >> state->bit_offset) & ((1 << segment_len) - 1);
-      }
-    } else { // BIT_LITTLE_ENDIAN
-      if (count + state->bit_offset >= 8) {
-	segment_len = 8 - state->bit_offset;
-	segment = (state->input[state->index] >> state->bit_offset);
-	state->index++;
-	state->bit_offset = 0;
-      } else {
-	segment_len = count;
-	segment = (state->input[state->index] >> state->bit_offset) & ((1 << segment_len) - 1);
-	state->bit_offset += segment_len;
+  if ((state->bit_offset & 0x7) == 0 && (count & 0x7) == 0) {
+    // fast path
+    if (state->endianness & BYTE_BIG_ENDIAN) {
+      while (count > 0)
+	out = (out << 8) | state->input[state->index++];
+    } else {
+      while (count > 0) {
+	count -= 8;
+	out |= state->input[state->index++] << count;
       }
     }
-
-    // have a valid segment; time to assemble the byte
-    if (state->endianness & BYTE_BIG_ENDIAN) {
-      out = out << segment_len | segment;
-    } else { // BYTE_LITTLE_ENDIAN
-      out |= segment << offset;
-      offset += segment_len;
+  } else {
+    while (count) {
+      int segment, segment_len;
+      // Read a segment...
+      if (state->endianness & BIT_BIG_ENDIAN) {
+	if (count >= state->bit_offset) {
+	  segment_len = state->bit_offset;
+	  state->bit_offset = 8;
+	  segment = state->input[state->index] & ((1 << segment_len) - 1);
+	  state->index++;
+	} else {
+	  segment_len = count;
+	  state->bit_offset -= count;
+	  segment = (state->input[state->index] >> state->bit_offset) & ((1 << segment_len) - 1);
+	}
+      } else { // BIT_LITTLE_ENDIAN
+	if (count + state->bit_offset >= 8) {
+	  segment_len = 8 - state->bit_offset;
+	  segment = (state->input[state->index] >> state->bit_offset);
+	  state->index++;
+	  state->bit_offset = 0;
+	} else {
+	  segment_len = count;
+	  segment = (state->input[state->index] >> state->bit_offset) & ((1 << segment_len) - 1);
+	  state->bit_offset += segment_len;
+	}
+      }
+      
+      // have a valid segment; time to assemble the byte
+      if (state->endianness & BYTE_BIG_ENDIAN) {
+	out = out << segment_len | segment;
+      } else { // BYTE_LITTLE_ENDIAN
+	out |= segment << offset;
+	offset += segment_len;
+      }
+      count -= segment_len;
     }
-    count -= segment_len;
   }
   return (out ^ msb) - msb; // perform sign extension
 }
@@ -55,7 +68,7 @@ long long read_bits(input_stream_t* state, int count, char signed_p) {
 
 #define MK_INPUT_STREAM(buf,len,endianness_)   \
   {					      \
-    .input = buf,						\
+    .input = (uint8_t*)buf,					\
       .length = len,						\
       .index = 0,						\
       .bit_offset = (((endianness_) & BIT_BIG_ENDIAN) ? 8 : 0),	\
diff --git a/src/hammer.c b/src/hammer.c
index e5d9bc32d28f1e9fc11fe8856f8f9fa7b329c6fb..d7e7070b85c6af32aea409c920700a64cca219df 100644
--- a/src/hammer.c
+++ b/src/hammer.c
@@ -122,7 +122,7 @@ const parser_t* token(const uint8_t *str, const size_t len) {
 }
 
 static parse_result_t* parse_ch(void* env, parse_state_t *state) {
-  uint8_t c = (uint8_t)env;
+  uint8_t c = (uint8_t)GPOINTER_TO_UINT(env);
   uint8_t r = (uint8_t)read_bits(&state->input_stream, 8, false);
   if (c == r) {
     parsed_token_t *tok = g_new(parsed_token_t, 1);    
@@ -135,7 +135,7 @@ static parse_result_t* parse_ch(void* env, parse_state_t *state) {
 
 const parser_t* ch(const uint8_t c) {  
   parser_t *ret = g_new(parser_t, 1);
-  ret->fn = parse_ch; ret->env = (void*)c;
+  ret->fn = parse_ch; ret->env = GUINT_TO_POINTER(c);
   return (const parser_t*)ret;
 }