diff --git a/LICENSE b/LICENSE index c34f735..985d160 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2012 Connor Olding +Copyright (C) 2012, 2015 Connor Olding Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -20,4 +20,3 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/Makefile b/Makefile index a5218e5..36b805b 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,14 @@ PROGRAM = crc32 .PHONY: all clean install -FILES = main.c args.c crc32.c - -CFLAGS += -Wall -Werror -ansi -pedantic -LDFLAGS += -PREFIX ?= /usr/local all: $(PROGRAM) -$(PROGRAM): $(FILES) - $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(FILES) +$(PROGRAM): main.c + $(CC) -o $@ -Wall -Winline -std=c99 $(CFLAGS) $(LDFLAGS) $^ clean: -rm -f $(PROGRAM) install: - cp $(PROGRAM) $(PREFIX)/bin - + install -m 0755 -d $(PREFIX)/bin + install -m 0755 $(PROGRAM) $(PREFIX)/bin diff --git a/README.md b/README.md index 4deba2f..7595469 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,6 @@ It computes [crc32s,][crc] and what of it? [crc]: http://en.wikipedia.org/wiki/Cyclic_redundancy_check -Update ------- -If portability isn't a concern; as in your compiler can build gnu11 code; -I'd recommend you use the ["modern"](https://github.com/notwa/crc32/tree/modern) branch. -The code is much cleaner and slightly faster. - Usage ---- ``` @@ -25,13 +19,7 @@ crc32 - a 32-bit cyclic rendundancy check calculator -x NOT the output -r reverse output's bits -numbers may be entered as hexadecimal or octal with prefixes +numbers may be in hexadecimal or octal using proper prefixes ``` -Notes ------ - -* Does not pad input. -* Big endian calculations are somewhat untested. - ## [Smaller Still](https://gist.github.com/notwa/5689243) diff --git a/args.c b/args.c index d813194..bbcea06 100644 --- a/args.c +++ b/args.c @@ -1,17 +1,10 @@ -/* Copyright (C) 2012 Connor Olding - * - * This program is licensed under the terms of the MIT License, and - * is distributed without any warranty. You should have received a - * copy of the license along with this program; see the file LICENSE. - */ - #include -#include "args.h" static int argc, argi; static char **argv, *flag; -static char *nextarg() +static char * +nextarg() { char *temp = flag; flag = NULL; @@ -22,7 +15,8 @@ static char *nextarg() return argv[argi]; } -void args_parse(int argc_, char **argv_, +static void +args_parse(int argc_, char **argv_, void flagfn(char, char*()), void plainfn(char*)) { argc = argc_; @@ -54,4 +48,3 @@ void args_parse(int argc_, char **argv_, if (plainfn) plainfn(argv[argi]); } - diff --git a/args.h b/args.h deleted file mode 100644 index e325306..0000000 --- a/args.h +++ /dev/null @@ -1,10 +0,0 @@ -/* Copyright (C) 2012 Connor Olding - * - * This program is licensed under the terms of the MIT License, and - * is distributed without any warranty. You should have received a - * copy of the license along with this program; see the file LICENSE. - */ - -void args_parse(int argc, char **argv, - void flagfn(char, char*()), void plainfn(char*)); - diff --git a/crc32.c b/crc32.c index 0016db7..eee14f9 100644 --- a/crc32.c +++ b/crc32.c @@ -1,18 +1,10 @@ -/* Copyright (C) 2012 Connor Olding - * - * This program is licensed under the terms of the MIT License, and - * is distributed without any warranty. You should have received a - * copy of the license along with this program; see the file LICENSE. - */ +enum { CRC_TABLE_SIZE = 0x100 }; -typedef unsigned long ulong; -#include "crc32.h" - -ulong crc_reflect(ulong input) +static inline uint32_t +crc_reflect(uint32_t input) { - ulong reflected = 0; - int i; - for (i = 0; i < 4 * 8; i++) { + uint32_t reflected = 0; + for (int i = 0; i < 32; i++) { reflected <<= 1; reflected |= input & 1; input >>= 1; @@ -20,34 +12,56 @@ ulong crc_reflect(ulong input) return reflected; } -void crc_fill_table(ulong *table, int big, ulong polynomial) +static inline void +crc_be_fill_table(uint32_t *table, uint32_t polynomial) { - ulong lsb = (big) ? 1 << 31 : 1; /* least significant bit */ - ulong poly = (big) ? polynomial : crc_reflect(polynomial); - int c, i; + const uint32_t lsb = 1 << 31; + uint32_t poly = polynomial; - for (c = 0; c < CRC_TABLE_SIZE; c++, table++) { - *table = (big) ? c << 24 : c; - for (i = 0; i < 8; i++) { - if (*table & lsb) { - *table = (big) ? *table << 1 : *table >> 1; - *table ^= poly; + for (int c = 0; c < CRC_TABLE_SIZE; c++) { + uint32_t v = c << 24; + for (int i = 0; i < 8; i++) { + if (v & lsb) { + v <<= 1; + v ^= poly; } else { - *table = (big) ? *table << 1 : *table >> 1; + v <<= 1; } - *table &= 0xFFFFFFFF; } + *table++ = v; } } -void crc_be_cycle(ulong *table, ulong *remainder, char c) +static inline void +crc_le_fill_table(uint32_t *table, uint32_t polynomial) { - ulong byte = table[(((*remainder) >> 24) ^ c) & 0xff]; - *remainder = (((*remainder) << 8) ^ byte) & 0xFFFFFFFF; + const uint32_t lsb = 1; + uint32_t poly = crc_reflect(polynomial); + + for (int c = 0; c < CRC_TABLE_SIZE; c++) { + uint32_t v = c; + for (int i = 0; i < 8; i++) { + if (v & lsb) { + v >>= 1; + v ^= poly; + } else { + v >>= 1; + } + } + *table++ = v; + } } -void crc_le_cycle(ulong *table, ulong *remainder, char c) +static inline void +crc_be_cycle(uint32_t *table, uint32_t *remainder, uint8_t c) { - ulong byte = table[((*remainder) ^ c) & 0xFF]; - *remainder = ((*remainder) >> 8) ^ byte; + const uint8_t i = (*remainder >> 24) ^ c; + *remainder = (*remainder << 8) ^ table[i]; +} + +static inline void +crc_le_cycle(uint32_t *table, uint32_t *remainder, uint8_t c) +{ + const uint8_t i = (*remainder & 0xFF) ^ c; + *remainder = (*remainder >> 8) ^ table[i]; } diff --git a/crc32.h b/crc32.h deleted file mode 100644 index 4e43b4a..0000000 --- a/crc32.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyright (C) 2012 Connor Olding - * - * This program is licensed under the terms of the MIT License, and - * is distributed without any warranty. You should have received a - * copy of the license along with this program; see the file LICENSE. - */ - -enum { CRC_TABLE_SIZE = 0x100 }; - -void crc_fill_table(ulong *table, int big, ulong polynomial); -void crc_be_cycle(ulong *table, ulong *remainder, char c); -void crc_le_cycle(ulong *table, ulong *remainder, char c); -ulong crc_reflect(ulong input); diff --git a/main.c b/main.c index 4609675..48bb8d1 100644 --- a/main.c +++ b/main.c @@ -1,45 +1,30 @@ -/* Copyright (C) 2012 Connor Olding - * - * This program is licensed under the terms of the MIT License, and - * is distributed without any warranty. You should have received a - * copy of the license along with this program; see the file LICENSE. - */ - #include #include +#include -typedef unsigned long ulong; +#include "crc32.c" +#include "args.c" -#include "crc32.h" -#include "args.h" - -#ifdef _MSC_VER - #define FREOPEN_BLANK ("") -#else - #define FREOPEN_BLANK (NULL) -#endif +typedef int bool; #ifndef BUFFER_SIZE #define BUFFER_SIZE 4096 #endif char buff[BUFFER_SIZE]; -typedef struct string_node_s string_node; -struct string_node_s { - char *s; - string_node *next; -}; +#define MAX_INPUTS 256 -static string_node *input_node = NULL; +static char *inputs[MAX_INPUTS]; +static int input_n = 0; -static ulong starting = 0xFFFFFFFF; -static char big_endian = 0; -static ulong polynomial = 0x04C11DB7; -static char print_binary = 0; -static char xor_output = 1; -static char reflect_output = 0; +static uint32_t starting = 0xFFFFFFFF; +static bool big_endian = 0; +static uint32_t polynomial = 0x04C11DB7; +static bool print_binary = 0; +static bool xor_output = 1; +static bool reflect_output = 0; -static const char help1[] = "\ +static const char help[] = "\ crc32 - a 32-bit cyclic rendundancy check calculator\n\ \n\ open files as inputs\n\ @@ -51,12 +36,11 @@ crc32 - a 32-bit cyclic rendundancy check calculator\n\ -x NOT the output\n\ -r reverse output's bits\n\ \n\ -"; -static const char help2[] = "\ -numbers may be entered as hexadecimal or octal with prefixes\n\ +numbers may be in hexadecimal or octal using proper prefixes\n\ "; -static char *check_next(char flag, char *next) { +static char +*check_next(char flag, char *next) { if (!next) { fprintf(stderr, "-%c requires another argument\n", flag); exit(1); @@ -64,58 +48,52 @@ static char *check_next(char flag, char *next) { return next; } -static void handle_flag(char flag, char *(*nextarg)()) +static void +handle_flag(char flag, char *(*nextarg)()) { char *next; switch (flag) { - case 'h': - printf(help1); - printf(help2); - exit(0); - case 'e': + case 'h': { + printf(help); + } exit(0); + case 'e': { big_endian = 1; - return; - case 'b': + } break; + case 'b': { print_binary = 1; - return; - case 'x': + } break; + case 'x': { xor_output = 0; - return; - case 'r': + } break; + case 'r': { reflect_output = 1; - return; - case 's': + } break; + case 's': { next = check_next(flag, nextarg()); starting = strtoul(next, NULL, 0); - break; - case 'p': + } break; + case 'p': { next = check_next(flag, nextarg()); polynomial = strtoul(next, NULL, 0); - break; - default: + } break; + default: { fprintf(stderr, "Unknown flag: -%c\n", flag); - exit(1); + } exit(1); } } -static void add_input(char *arg) +static void +add_input(char *arg) { - static string_node *last = NULL; - string_node *n = calloc(1, sizeof(string_node)); - if (!n) { - fprintf(stderr, "calloc failed\n"); + if (input_n >= MAX_INPUTS) { + fprintf(stderr, "Too many inputs specified\n"); exit(1); } - - n->s = arg; - if (!input_node) - input_node = n; - else - last->next = n; - last = n; + inputs[input_n++] = arg; } -static FILE *open_stream(char *filename) +static FILE * +open_stream(char *filename) { FILE *stream = NULL; stream = fopen(filename, "rb"); @@ -126,25 +104,38 @@ static FILE *open_stream(char *filename) return stream; } - -static ulong cycle_file(FILE *stream) +static inline size_t +buff_read(FILE *stream) { - ulong remainder = starting; - void (*cycle)(ulong*, ulong*, char) = - (big_endian) ? crc_be_cycle : crc_le_cycle; - ulong table[CRC_TABLE_SIZE]; - int i, len; + size_t len = fread(buff, 1, BUFFER_SIZE, stream); + if (ferror(stream)) { + perror(NULL); + exit(1); + } + return len; +} - crc_fill_table(table, big_endian, polynomial); - do { - len = fread(buff, 1, BUFFER_SIZE, stream); - if (ferror(stream)) { - perror(NULL); - exit(1); - } +static uint32_t +cycle_file(FILE *stream) +{ + uint32_t remainder = starting; + uint32_t table[CRC_TABLE_SIZE]; - for (i = 0; i < len; i++) - cycle(table, &remainder, buff[i]); + if (big_endian) + crc_be_fill_table(table, polynomial); + else + crc_le_fill_table(table, polynomial); + + // cast len to int to enable potential signedness optimizations. + // this is safe so long as BUFFER_SIZE can fit in an int. + if (big_endian) do { + int len = (int) buff_read(stream); + for (int i = 0; i < len; i++) + crc_be_cycle(table, &remainder, buff[i]); + } while (!feof(stream)); else do { + int len = (int) buff_read(stream); + for (int i = 0; i < len; i++) + crc_le_cycle(table, &remainder, buff[i]); } while (!feof(stream)); if (xor_output) @@ -154,7 +145,8 @@ static ulong cycle_file(FILE *stream) return remainder; } -static void print_crc(ulong remainder) +static void +print_crc(uint32_t remainder) { if (print_binary) fwrite(&remainder, sizeof(remainder), 1, stdout); @@ -162,30 +154,19 @@ static void print_crc(ulong remainder) printf("%08X\n", (int) remainder); } -static void free_nodes(string_node *n) +int +main(int argc, char **argv) { - string_node *next; - while (n) { - next = n->next; - free(n); - n = next; - } -} - -int main(int argc, char **argv) -{ - string_node *n; args_parse(argc, argv, handle_flag, add_input); - if (!input_node) { - freopen(FREOPEN_BLANK, "rb", stdin); + if (!input_n) { + freopen(NULL, "rb", stdin); print_crc(cycle_file(stdin)); } - for (n = input_node; n; n = n->next) { - FILE *stream = open_stream(n->s); + for (int i = 0; i < input_n; i++) { + FILE *stream = open_stream(inputs[i]); print_crc(cycle_file(stream)); fclose(stream); } - free_nodes(input_node); return 0; }