Merge branch 'modern'
This commit is contained in:
commit
b6518a913a
8 changed files with 135 additions and 188 deletions
3
LICENSE
3
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
|
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.
|
||||||
|
|
||||||
|
|
13
Makefile
13
Makefile
|
@ -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
|
||||||
|
|
14
README.md
14
README.md
|
@ -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
15
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 <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
10
args.h
|
@ -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
76
crc32.c
|
@ -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
13
crc32.h
|
@ -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);
|
|
173
main.c
173
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 <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) =
|
|
||||||
(big_endian) ? crc_be_cycle : crc_le_cycle;
|
|
||||||
ulong table[CRC_TABLE_SIZE];
|
|
||||||
int i, len;
|
|
||||||
|
|
||||||
crc_fill_table(table, big_endian, polynomial);
|
|
||||||
do {
|
|
||||||
len = fread(buff, 1, BUFFER_SIZE, stream);
|
|
||||||
if (ferror(stream)) {
|
if (ferror(stream)) {
|
||||||
perror(NULL);
|
perror(NULL);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
static uint32_t
|
||||||
cycle(table, &remainder, buff[i]);
|
cycle_file(FILE *stream)
|
||||||
|
{
|
||||||
|
uint32_t remainder = starting;
|
||||||
|
uint32_t table[CRC_TABLE_SIZE];
|
||||||
|
|
||||||
|
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));
|
} 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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue