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
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.

View File

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

View File

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

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 "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]);
}

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

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 <stdlib.h>
#include <stdint.h>
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\
<files...> 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 <n> may be entered as hexadecimal or octal with prefixes\n\
numbers <n> 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;
}