Merge branch 'modern'

This commit is contained in:
Connor Olding 2017-04-24 18:24:33 +00:00
commit b6518a913a
8 changed files with 135 additions and 188 deletions

View File

@ -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 Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation 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 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,19 +1,14 @@
PROGRAM = crc32 PROGRAM = crc32
.PHONY: all clean install .PHONY: all clean install
FILES = main.c args.c crc32.c
CFLAGS += -Wall -Werror -ansi -pedantic
LDFLAGS +=
PREFIX ?= /usr/local
all: $(PROGRAM) all: $(PROGRAM)
$(PROGRAM): $(FILES) $(PROGRAM): main.c
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(FILES) $(CC) -o $@ -Wall -Winline -std=c99 $(CFLAGS) $(LDFLAGS) $^
clean: clean:
-rm -f $(PROGRAM) -rm -f $(PROGRAM)
install: install:
cp $(PROGRAM) $(PREFIX)/bin install -m 0755 -d $(PREFIX)/bin
install -m 0755 $(PROGRAM) $(PREFIX)/bin

View File

@ -5,12 +5,6 @@ It computes [crc32s,][crc] and what of it?
[crc]: http://en.wikipedia.org/wiki/Cyclic_redundancy_check [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 Usage
---- ----
``` ```
@ -25,13 +19,7 @@ crc32 - a 32-bit cyclic rendundancy check calculator
-x NOT the output -x NOT the output
-r reverse output's bits -r reverse output's bits
numbers <n> may be entered as hexadecimal or octal with prefixes numbers <n> 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) ## [Smaller Still](https://gist.github.com/notwa/5689243)

15
args.c
View File

@ -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 <stddef.h> #include <stddef.h>
#include "args.h"
static int argc, argi; static int argc, argi;
static char **argv, *flag; static char **argv, *flag;
static char *nextarg() static char *
nextarg()
{ {
char *temp = flag; char *temp = flag;
flag = NULL; flag = NULL;
@ -22,7 +15,8 @@ static char *nextarg()
return argv[argi]; 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*)) void flagfn(char, char*()), void plainfn(char*))
{ {
argc = argc_; argc = argc_;
@ -54,4 +48,3 @@ void args_parse(int argc_, char **argv_,
if (plainfn) if (plainfn)
plainfn(argv[argi]); plainfn(argv[argi]);
} }

10
args.h
View File

@ -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*));

76
crc32.c
View File

@ -1,18 +1,10 @@
/* Copyright (C) 2012 Connor Olding enum { CRC_TABLE_SIZE = 0x100 };
*
* 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.
*/
typedef unsigned long ulong; static inline uint32_t
#include "crc32.h" crc_reflect(uint32_t input)
ulong crc_reflect(ulong input)
{ {
ulong reflected = 0; uint32_t reflected = 0;
int i; for (int i = 0; i < 32; i++) {
for (i = 0; i < 4 * 8; i++) {
reflected <<= 1; reflected <<= 1;
reflected |= input & 1; reflected |= input & 1;
input >>= 1; input >>= 1;
@ -20,34 +12,56 @@ ulong crc_reflect(ulong input)
return reflected; 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 */ const uint32_t lsb = 1 << 31;
ulong poly = (big) ? polynomial : crc_reflect(polynomial); uint32_t poly = polynomial;
int c, i;
for (c = 0; c < CRC_TABLE_SIZE; c++, table++) { for (int c = 0; c < CRC_TABLE_SIZE; c++) {
*table = (big) ? c << 24 : c; uint32_t v = c << 24;
for (i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
if (*table & lsb) { if (v & lsb) {
*table = (big) ? *table << 1 : *table >> 1; v <<= 1;
*table ^= poly; v ^= poly;
} else { } 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]; const uint32_t lsb = 1;
*remainder = (((*remainder) << 8) ^ byte) & 0xFFFFFFFF; 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]; const uint8_t i = (*remainder >> 24) ^ c;
*remainder = ((*remainder) >> 8) ^ byte; *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];
} }

13
crc32.h
View File

@ -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);

179
main.c
View File

@ -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 <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
typedef unsigned long ulong; #include "crc32.c"
#include "args.c"
#include "crc32.h" typedef int bool;
#include "args.h"
#ifdef _MSC_VER
#define FREOPEN_BLANK ("")
#else
#define FREOPEN_BLANK (NULL)
#endif
#ifndef BUFFER_SIZE #ifndef BUFFER_SIZE
#define BUFFER_SIZE 4096 #define BUFFER_SIZE 4096
#endif #endif
char buff[BUFFER_SIZE]; char buff[BUFFER_SIZE];
typedef struct string_node_s string_node; #define MAX_INPUTS 256
struct string_node_s {
char *s;
string_node *next;
};
static string_node *input_node = NULL; static char *inputs[MAX_INPUTS];
static int input_n = 0;
static ulong starting = 0xFFFFFFFF; static uint32_t starting = 0xFFFFFFFF;
static char big_endian = 0; static bool big_endian = 0;
static ulong polynomial = 0x04C11DB7; static uint32_t polynomial = 0x04C11DB7;
static char print_binary = 0; static bool print_binary = 0;
static char xor_output = 1; static bool xor_output = 1;
static char reflect_output = 0; static bool reflect_output = 0;
static const char help1[] = "\ static const char help[] = "\
crc32 - a 32-bit cyclic rendundancy check calculator\n\ crc32 - a 32-bit cyclic rendundancy check calculator\n\
\n\ \n\
<files...> open files as inputs\n\ <files...> open files as inputs\n\
@ -51,12 +36,11 @@ crc32 - a 32-bit cyclic rendundancy check calculator\n\
-x NOT the output\n\ -x NOT the output\n\
-r reverse output's bits\n\ -r reverse output's bits\n\
\n\ \n\
"; numbers <n> may be in hexadecimal or octal using proper prefixes\n\
static const char help2[] = "\
numbers <n> may be entered as hexadecimal or octal with prefixes\n\
"; ";
static char *check_next(char flag, char *next) { static char
*check_next(char flag, char *next) {
if (!next) { if (!next) {
fprintf(stderr, "-%c requires another argument\n", flag); fprintf(stderr, "-%c requires another argument\n", flag);
exit(1); exit(1);
@ -64,58 +48,52 @@ static char *check_next(char flag, char *next) {
return next; return next;
} }
static void handle_flag(char flag, char *(*nextarg)()) static void
handle_flag(char flag, char *(*nextarg)())
{ {
char *next; char *next;
switch (flag) { switch (flag) {
case 'h': case 'h': {
printf(help1); printf(help);
printf(help2); } exit(0);
exit(0); case 'e': {
case 'e':
big_endian = 1; big_endian = 1;
return; } break;
case 'b': case 'b': {
print_binary = 1; print_binary = 1;
return; } break;
case 'x': case 'x': {
xor_output = 0; xor_output = 0;
return; } break;
case 'r': case 'r': {
reflect_output = 1; reflect_output = 1;
return; } break;
case 's': case 's': {
next = check_next(flag, nextarg()); next = check_next(flag, nextarg());
starting = strtoul(next, NULL, 0); starting = strtoul(next, NULL, 0);
break; } break;
case 'p': case 'p': {
next = check_next(flag, nextarg()); next = check_next(flag, nextarg());
polynomial = strtoul(next, NULL, 0); polynomial = strtoul(next, NULL, 0);
break; } break;
default: default: {
fprintf(stderr, "Unknown flag: -%c\n", flag); 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; if (input_n >= MAX_INPUTS) {
string_node *n = calloc(1, sizeof(string_node)); fprintf(stderr, "Too many inputs specified\n");
if (!n) {
fprintf(stderr, "calloc failed\n");
exit(1); exit(1);
} }
inputs[input_n++] = arg;
n->s = arg;
if (!input_node)
input_node = n;
else
last->next = n;
last = n;
} }
static FILE *open_stream(char *filename) static FILE *
open_stream(char *filename)
{ {
FILE *stream = NULL; FILE *stream = NULL;
stream = fopen(filename, "rb"); stream = fopen(filename, "rb");
@ -126,25 +104,38 @@ static FILE *open_stream(char *filename)
return stream; return stream;
} }
static inline size_t
static ulong cycle_file(FILE *stream) buff_read(FILE *stream)
{ {
ulong remainder = starting; size_t len = fread(buff, 1, BUFFER_SIZE, stream);
void (*cycle)(ulong*, ulong*, char) = if (ferror(stream)) {
(big_endian) ? crc_be_cycle : crc_le_cycle; perror(NULL);
ulong table[CRC_TABLE_SIZE]; exit(1);
int i, len; }
return len;
}
crc_fill_table(table, big_endian, polynomial); static uint32_t
do { cycle_file(FILE *stream)
len = fread(buff, 1, BUFFER_SIZE, stream); {
if (ferror(stream)) { uint32_t remainder = starting;
perror(NULL); uint32_t table[CRC_TABLE_SIZE];
exit(1);
}
for (i = 0; i < len; i++) if (big_endian)
cycle(table, &remainder, buff[i]); 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)); } while (!feof(stream));
if (xor_output) if (xor_output)
@ -154,7 +145,8 @@ static ulong cycle_file(FILE *stream)
return remainder; return remainder;
} }
static void print_crc(ulong remainder) static void
print_crc(uint32_t remainder)
{ {
if (print_binary) if (print_binary)
fwrite(&remainder, sizeof(remainder), 1, stdout); fwrite(&remainder, sizeof(remainder), 1, stdout);
@ -162,30 +154,19 @@ static void print_crc(ulong remainder)
printf("%08X\n", (int) 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); args_parse(argc, argv, handle_flag, add_input);
if (!input_node) { if (!input_n) {
freopen(FREOPEN_BLANK, "rb", stdin); freopen(NULL, "rb", stdin);
print_crc(cycle_file(stdin)); print_crc(cycle_file(stdin));
} }
for (n = input_node; n; n = n->next) { for (int i = 0; i < input_n; i++) {
FILE *stream = open_stream(n->s); FILE *stream = open_stream(inputs[i]);
print_crc(cycle_file(stream)); print_crc(cycle_file(stream));
fclose(stream); fclose(stream);
} }
free_nodes(input_node);
return 0; return 0;
} }