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; }