Compare commits

..

17 Commits

Author SHA1 Message Date
1206f776ca Updated README file. 2022-09-19 21:53:58 +02:00
06ae68eaea Added support for the "--append-length" option. 2022-09-19 21:41:32 +02:00
70132c3ac1 Do not show I/O error, if process was interrupted before. 2022-09-18 14:24:18 +02:00
336913002e Improved "binary" output mode. 2022-09-17 18:37:20 +02:00
8dad8628b3 Added simple build scripts for Linux, FreeBSD, Win32 and MacOS X platforms. 2022-09-17 18:27:25 +02:00
31d32b4fce Adjust buffer size + small improvement to is_directory() function + code clean-up. 2022-09-17 13:43:28 +02:00
7581eccaa0 Small Makefile improvement. 2022-09-15 21:58:05 +02:00
1b8e9aba42 Various improvements to options parsing. 2022-09-15 21:52:33 +02:00
3f0b4c5788 Various improvements to self-test code. 2022-09-14 01:36:07 +02:00
92cc30b6be Implemented self-test. 2022-09-14 00:49:38 +02:00
9937ad3cba Some improvements to error handling. 2022-09-12 23:56:49 +02:00
a324600117 Updated README file. 2022-09-12 22:02:20 +02:00
078cda1a31 Options "--init-with-zero" and "--negate-final" have been implemented. 2022-09-12 21:42:12 +02:00
1fb3709fa7 Use more appropriate file name for 'stdin' input on Win32. 2022-09-11 21:41:34 +02:00
eb3f56e210 Small Makefile improvement. 2022-09-11 14:16:29 +02:00
8d1fcca4ff Flush standard output stream after each file. Added option to disable flushing. 2022-09-11 14:11:52 +02:00
5e4f8bcfe9 Added README file. 2022-09-10 22:04:00 +02:00
11 changed files with 464 additions and 92 deletions

View File

@ -1,8 +1,11 @@
MACHINE := $(shell $(CC) -dumpmachine || echo unknown) MACHINE := $(shell $(CC) -dumpmachine || echo unknown)
STATIC ?= 1
STRIP ?= 1
ifneq (,$(firstword $(filter x86_64-%,$(MACHINE)))) ifneq (,$(firstword $(filter x86_64-%,$(MACHINE))))
MARCH ?= x86-64 MARCH ?= x86-64
MTUNE ?= nocona MTUNE ?= znver3
else else
ifneq (,$(firstword $(filter i686-%,$(MACHINE)))) ifneq (,$(firstword $(filter i686-%,$(MACHINE))))
MARCH ?= i586 MARCH ?= i586
@ -10,7 +13,11 @@ else
endif endif
endif endif
CFLAGS = -Wall -std=gnu99 -O3 -DNDEBUG CFLAGS = -Wall -std=gnu99 -pedantic -Ofast -DNDEBUG
ifneq (,$(XCFLAGS))
CFLAGS += $(XCFLAGS)
endif
ifneq (,$(MARCH)) ifneq (,$(MARCH))
CFLAGS += -march=$(MARCH) CFLAGS += -march=$(MARCH)
@ -26,10 +33,16 @@ else
endif endif
ifneq (,$(firstword $(filter %-w64-mingw32 %w64-windows-gnu,$(MACHINE)))) ifneq (,$(firstword $(filter %-w64-mingw32 %w64-windows-gnu,$(MACHINE))))
CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -mconsole -municode CFLAGS += -mconsole -municode
endif endif
CFLAGS += -s -static ifeq ($(STATIC),1)
CFLAGS += -static
endif
ifeq ($(STRIP),1)
CFLAGS += -s
endif
.PHONY: all .PHONY: all

39
README.md Normal file
View File

@ -0,0 +1,39 @@
# CRC-64
Simple cross-platform command-line tool for computing **CRC-64** ([ECMA-182](https://www.ecma-international.org/wp-content/uploads/ECMA-182_1st_edition_december_1992.pdf)) checksums.
The `crc64` utility writes to the standard output three whitespace separated fields for each input file. These fields are the CRC (Cyclic Redundancy Check) checksum of the file, the total number of octets in the file and the file name. If *no* file name is specified, the standard input is used.
The generator polynomial use for CRC-64 computations is: **`0x42F0E1EBA9EA3693`**
## Synopsis
```
crc64.exe [OPTIONS] [<file_1> [<file_2> ... <file_n>]]
```
## Options
| Option | Description |
|-----------------------------|--------------------------------------------------------|
| `-h`, `--help`, `--version` | Show help screen / show version information |
| `-b`, `--binary` | Output digest in binary format (default is hex-string) |
| `-d`, `--decimal` | Output digest in decimal string format |
| `-u`, `--upper-case` | Print digest as upper-case (default is lower-case) |
| `-p`, `--no-padding` | Print digest **without** any leading zeros |
| `-s`, `--silent` | Suppress error messages |
| `-e`, `--ignore-errors` | Ignore I/O errors and proceed with the next file |
| `-f`, `--no-flush` | Do **not** flush output stream after each file |
| `-z`, `--init-with-zero` | Initialize CRC with 0x000…000 (default is 0xFFF…FFF) |
| `-n`, `--negate-final` | Negate the final CRC result |
| `-l`, `--append-length` | Append to the input its length for CRC computation |
| `-t`, `--self-test` | Run integrated self-test and exit program |
## License
This work has been released under the **CC0 1.0 Universal** license.
For details, please refer to:
<https://creativecommons.org/publicdomain/zero/1.0/legalcode>

373
crc64.c
View File

@ -3,6 +3,14 @@
/* This work has been released under the CC0 1.0 Universal license! */ /* This work has been released under the CC0 1.0 Universal license! */
/********************************************************************/ /********************************************************************/
#ifndef _WIN32
#define _FILE_OFFSET_BITS 64
#endif
#if defined(__MINGW32__) || defined(__MINGW64__)
#define __USE_MINGW_ANSI_STDIO 0
#endif
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -11,26 +19,61 @@
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <ctype.h>
#include <signal.h> #include <signal.h>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#include <io.h>
#include <fcntl.h> #include <fcntl.h>
#include <io.h>
#endif #endif
static const int VERSION_MAJOR = 1; static const int VERSION_MAJOR = 1;
static const int VERSION_MINOR = 0; static const int VERSION_MINOR = 0;
static const int VERSION_PATCH = 0; static const int VERSION_PATCH = 3;
#define OPT_HELPSC 0x01 #define OPT_HELPSC 0x0001
#define OPT_BINARY 0x02 #define OPT_VERSNO 0x0002
#define OPT_UPPERC 0x04 #define OPT_BINARY 0x0004
#define OPT_DECIML 0x08 #define OPT_UPPERC 0x0008
#define OPT_NOPADD 0x10 #define OPT_DECIML 0x0010
#define OPT_IGNERR 0x20 #define OPT_NOPADD 0x0020
#define OPT_SILENT 0x40 #define OPT_IGNERR 0x0040
#define OPT_SILENT 0x0080
#define OPT_NOFLSH 0x0100
#define OPT_ZEROIN 0x0200
#define OPT_NEGATE 0x0400
#define OPT_LENGTH 0x0800
#define OPT_SLFTST 0x1000
/* ======================================================================== */
/* Compiler */
/* ======================================================================== */
#if defined(__GNUC__) || defined(__INTEL_LLVM_COMPILER)
#define ALIGNED(X) __attribute__((aligned(X)))
#define PURE __attribute__((pure))
#define FORCE_INLINE __attribute__((always_inline)) __inline__
#define COUNTOF(X) (sizeof(X) / sizeof((X)[0]))
#define ATOMIC_INC(X) __sync_add_and_fetch((X), 1L);
#ifdef _WIN32
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#elif defined(_MSC_VER)
#define ALIGNED(X) __declspec(align(X))
#define PURE __declspec(noalias)
#define FORCE_INLINE __forceinline
#define COUNTOF(X) _countof(X)
#define ATOMIC_INC(X) _InterlockedIncrement((X));
#pragma warning(disable: 4996)
#else
#error Unsupported compiler, please fix !!!
#endif
/* ======================================================================== */ /* ======================================================================== */
/* Platform */ /* Platform */
@ -42,10 +85,15 @@ static const int VERSION_PATCH = 0;
#define CHAR wchar_t #define CHAR wchar_t
#define MAIN wmain #define MAIN wmain
#define STRCASECMP _wcsicmp #define STRCASECMP _wcsicmp
#define STRLEN wcslen
#define ISSPACE iswspace
#define TOLOWER towlower
#define PRINTF wprintf #define PRINTF wprintf
#define FPUTS fputws #define FPUTS fputws
#define FPRINTF fwprintf #define FPRINTF fwprintf
#define FOPEN _wfopen #define FOPEN _wfopen
#define STAT_T struct _stati64
#define FSTAT(X,Y) _fstati64(_fileno(X), (Y))
#define __T(X) L##X #define __T(X) L##X
#define T(X) __T(X) #define T(X) __T(X)
#ifndef S_IFMT #ifndef S_IFMT
@ -62,10 +110,15 @@ int _dowildcard = -1;
#define CHAR char #define CHAR char
#define MAIN main #define MAIN main
#define STRCASECMP strcasecmp #define STRCASECMP strcasecmp
#define STRLEN strlen
#define ISSPACE isspace
#define TOLOWER tolower
#define PRINTF printf #define PRINTF printf
#define FPUTS fputs #define FPUTS fputs
#define FPRINTF fprintf #define FPRINTF fprintf
#define FOPEN fopen #define FOPEN fopen
#define STAT_T struct stat
#define FSTAT(X,Y) fstat(fileno(X), (Y))
#define __T(X) X #define __T(X) X
#define T(X) __T(X) #define T(X) __T(X)
@ -75,13 +128,13 @@ int _dowildcard = -1;
/* Signal handler */ /* Signal handler */
/* ======================================================================== */ /* ======================================================================== */
static volatile int g_stop_flag = 0; static volatile long g_aborted = 0L;
static void sigint_handler(const int sig) static void sigint_handler(const int sig)
{ {
if (sig == SIGINT) if (sig == SIGINT)
{ {
g_stop_flag = 1; ATOMIC_INC(&g_aborted);
} }
} }
@ -91,7 +144,7 @@ static void sigint_handler(const int sig)
static const uint64_t CRC64_INITIALIZER = UINT64_C(~0); static const uint64_t CRC64_INITIALIZER = UINT64_C(~0);
static const uint64_t CRC64_TABLE[256] = static const uint64_t ALIGNED(64) CRC64_TABLE[256] =
{ {
0x0000000000000000ULL, 0x42f0e1eba9ea3693ULL, 0x85e1c3d753d46d26ULL, 0xc711223cfa3e5bb5ULL, 0x0000000000000000ULL, 0x42f0e1eba9ea3693ULL, 0x85e1c3d753d46d26ULL, 0xc711223cfa3e5bb5ULL,
0x493366450e42ecdfULL, 0x0bc387aea7a8da4cULL, 0xccd2a5925d9681f9ULL, 0x8e224479f47cb76aULL, 0x493366450e42ecdfULL, 0x0bc387aea7a8da4cULL, 0xccd2a5925d9681f9ULL, 0x8e224479f47cb76aULL,
@ -159,14 +212,12 @@ static const uint64_t CRC64_TABLE[256] =
0x5dedc41a34bbeeb2ULL, 0x1f1d25f19d51d821ULL, 0xd80c07cd676f8394ULL, 0x9afce626ce85b507ULL 0x5dedc41a34bbeeb2ULL, 0x1f1d25f19d51d821ULL, 0xd80c07cd676f8394ULL, 0x9afce626ce85b507ULL
}; };
static uint64_t crc64_update(uint64_t crc, const uint8_t *const buffer, const size_t count) static uint64_t PURE FORCE_INLINE crc64_update(uint64_t crc, const uint8_t *ptr, const size_t count)
{ {
const uint8_t *p = buffer; const uint8_t *const endptr = ptr + count;
size_t i, t; while (ptr < endptr)
for (i = 0U; i < count; ++i)
{ {
t = ((crc >> 56) ^ (*p++)) & 0xFF; crc = CRC64_TABLE[((crc >> 56) ^ (*ptr++)) & 0xFF] ^ (crc << 8);
crc = CRC64_TABLE[t] ^ (crc << 8);
} }
return crc; return crc;
} }
@ -175,38 +226,50 @@ static uint64_t crc64_update(uint64_t crc, const uint8_t *const buffer, const si
/* Detect directory */ /* Detect directory */
/* ======================================================================== */ /* ======================================================================== */
#ifdef _MSC_VER
#pragma warning(disable: 4100)
#endif
static int is_directory(FILE *const file) static int is_directory(FILE *const file)
{ {
#ifndef _WIN32 STAT_T statbuf;
struct stat statbuf; if (!FSTAT(file, &statbuf))
if (!fstat(fileno(file), &statbuf))
{ {
if ((statbuf.st_mode & S_IFMT) == S_IFDIR) if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
{ {
return 1; return 1;
} }
} }
#endif
return 0; return 0;
} }
/* ======================================================================== */
/* Store 64-Bit value (LE) */
/* ======================================================================== */
static size_t store_uint64(uint64_t value, uint8_t *const buffer)
{
size_t count = 0U;
for (; value; value >>= 8)
{
buffer[count++] = value & 0xFF;
}
return count;
}
/* ======================================================================== */ /* ======================================================================== */
/* Process File */ /* Process File */
/* ======================================================================== */ /* ======================================================================== */
const CHAR *const STR_STDIN = T("/dev/stdin"); #define BUFF_SIZE (sizeof(uintptr_t) * sizeof(uintptr_t) * 256U)
#define BUFF_SIZE 4096U #ifdef _WIN32
const wchar_t *const STR_STDIN = L"CONIN$";
#else
const char *const STR_STDIN = "/dev/stdin";
#endif
static int process(const CHAR *const file_name, const int options) static int process_file(const CHAR *const file_name, const int options)
{ {
int retval = EXIT_FAILURE; int retval = EXIT_FAILURE;
FILE *input = NULL; FILE *input = NULL;
uint64_t crc = CRC64_INITIALIZER, total_size = 0U; uint64_t crc = (!(options & OPT_ZEROIN)) ? CRC64_INITIALIZER : UINT64_C(0), total_size = 0U;
uint8_t buffer[BUFF_SIZE]; uint8_t buffer[BUFF_SIZE];
input = file_name ? FOPEN(file_name, T("rb")) : stdin; input = file_name ? FOPEN(file_name, T("rb")) : stdin;
@ -229,7 +292,7 @@ static int process(const CHAR *const file_name, const int options)
goto clean_up; goto clean_up;
} }
while ((!feof(input)) && (!g_stop_flag)) while (!feof(input))
{ {
const size_t count = fread(buffer, sizeof(uint8_t), BUFF_SIZE, input); const size_t count = fread(buffer, sizeof(uint8_t), BUFF_SIZE, input);
if (count > 0U) if (count > 0U)
@ -241,7 +304,7 @@ static int process(const CHAR *const file_name, const int options)
{ {
if (!(options & OPT_IGNERR)) if (!(options & OPT_IGNERR))
{ {
if (!(options & OPT_SILENT)) if (!((options & OPT_SILENT) || g_aborted))
{ {
FPUTS(T("I/O Error: Failed to read input data!\n"), stderr); FPUTS(T("I/O Error: Failed to read input data!\n"), stderr);
} }
@ -252,6 +315,21 @@ static int process(const CHAR *const file_name, const int options)
break; /*ignore the read error*/ break; /*ignore the read error*/
} }
} }
if (g_aborted)
{
goto clean_up; /*process was interrupted*/
}
}
if (total_size && (options & OPT_LENGTH))
{
const size_t count = store_uint64(total_size, buffer);
crc = crc64_update(crc, buffer, count);
}
if (options & OPT_NEGATE)
{
crc = ~crc;
} }
if (!(options & OPT_BINARY)) if (!(options & OPT_BINARY))
@ -295,7 +373,15 @@ static int process(const CHAR *const file_name, const int options)
} }
else else
{ {
const CHAR *const name_ptr = file_name ? file_name : STR_STDIN;
fwrite(&crc, sizeof(uint64_t), 1U, stdout); fwrite(&crc, sizeof(uint64_t), 1U, stdout);
fwrite(&total_size, sizeof(uint64_t), 1U, stdout);
fwrite(name_ptr, sizeof(CHAR), STRLEN(name_ptr) + 1U, stdout);
}
if (!(options & OPT_NOFLSH))
{
fflush(stdout);
} }
retval = EXIT_SUCCESS; retval = EXIT_SUCCESS;
@ -310,16 +396,112 @@ clean_up:
return retval; return retval;
} }
/* ======================================================================== */
/* Self-test */
/* ======================================================================== */
static const struct
{
uint64_t expected[2U];
size_t loops;
const char *input;
}
CRC64_TESTCASE[] =
{
{ { 0xffffffffffffffffULL, 0x0000000000000000ULL }, 0x0000001, "" },
{ { 0x9d13a61c0e5b0ff5ULL, 0x6c40df5f0b497347ULL }, 0x0000001, "123456789" },
{ { 0xfb747ec5060b68fdULL, 0x66501a349a0e0855ULL }, 0x0000001, "abc" },
{ { 0xe48092e3bf0112faULL, 0x29d18301fe33ca5dULL }, 0x0000001, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ { 0x763e5273763ec641ULL, 0x86751df1edd9a621ULL }, 0x0000001, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
{ { 0x80459bd12d319927ULL, 0x3377cec7a585e11fULL }, 0x00F4240, "a" },
{ { 0x5343b9581532ecbdULL, 0x9c5f7a86307e23ceULL }, 0x1000000, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" },
{ { 0x771555a0a9bdf4cbULL, 0xfbd4c4d2a72a6865ULL }, 0xFFFFFC7, "\x20!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" },
{ { 0x3514226b46672b42ULL, 0xb9d5b31948f0b7ecULL }, 0xFFFFFC7, ")F9ow<I]PrX5kgbjJ'(`A&\".qHt6|{}-\x20paCe%Q:*,#x0NiMuzUG>V;!_S+dym/\\cL$73@4T?8DO2B[EhnKY^slZ~=RWvf1" }
};
static int self_test(void)
{
size_t i, j, k;
for (i = 0U; i < COUNTOF(CRC64_TESTCASE); ++i)
{
const size_t len = strlen(CRC64_TESTCASE[i].input);
for (j = 0U; j < 2U; ++j)
{
uint64_t crc = (j < 1U) ? CRC64_INITIALIZER : UINT64_C(0);
for (k = 0U; k < CRC64_TESTCASE[i].loops; ++k)
{
crc = crc64_update(crc, (const uint8_t*)CRC64_TESTCASE[i].input, len);
if (g_aborted)
{
return EXIT_FAILURE;
}
}
FPRINTF(stderr, T("%016") T(PRIx64) T(" [%s]\n"), crc, (crc == CRC64_TESTCASE[i].expected[j]) ? T("OK") : T("Failed!"));
fflush(stderr);
if (crc != CRC64_TESTCASE[i].expected[j])
{
FPRINTF(stderr, T("Expected result was 0x%016") T(PRIx64) T(", but got 0x%016") T(PRIx64) T("\n"), CRC64_TESTCASE[i].expected[j], crc);
return EXIT_FAILURE;
}
}
}
return EXIT_SUCCESS;
}
/* ======================================================================== */
/* Parse options */
/* ======================================================================== */
#define ISALPHA(X) (((X) != T('\0')) && ((((X) >= T('a')) && ((X) <= T('z'))) || (((X) >= T('A')) && ((X) <= T('Z')))))
static const struct
{
CHAR c;
const CHAR *name;
int flag;
}
CLI_OPTION_NAMES[] =
{
{ T('h'), T("help"), OPT_HELPSC },
{ T('v'), T("version"), OPT_VERSNO },
{ T('b'), T("binary"), OPT_BINARY },
{ T('u'), T("upper-case"), OPT_UPPERC },
{ T('d'), T("decimal"), OPT_DECIML },
{ T('p'), T("no-padding"), OPT_NOPADD },
{ T('e'), T("ignore-errors"), OPT_IGNERR },
{ T('s'), T("silent"), OPT_SILENT },
{ T('f'), T("no-flush"), OPT_NOFLSH },
{ T('z'), T("init-with-zero"), OPT_ZEROIN },
{ T('n'), T("negate-final"), OPT_NEGATE },
{ T('l'), T("append-length"), OPT_LENGTH },
{ T('t'), T("self-test"), OPT_SLFTST }
};
static int parse_option(int *const options, const CHAR c, const CHAR *const name)
{
size_t i;
for (i = 0U; i < COUNTOF(CLI_OPTION_NAMES); ++i)
{
if ((c == CLI_OPTION_NAMES[i].c) || (name && (!STRCASECMP(name, CLI_OPTION_NAMES[i].name))))
{
*options |= CLI_OPTION_NAMES[i].flag;
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
/* ======================================================================== */ /* ======================================================================== */
/* MAIN */ /* MAIN */
/* ======================================================================== */ /* ======================================================================== */
int MAIN(int argc, CHAR *argv[]) int MAIN(int argc, CHAR* argv[])
{ {
int arg_off = 1, options = 0, exit_code = EXIT_SUCCESS; int arg_off = 1, options = 0, exit_code = EXIT_SUCCESS;
#ifdef _WIN32 #ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); _seterrormode(3);
_setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stderr), _O_U8TEXT); _setmode(_fileno(stderr), _O_U8TEXT);
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);
@ -331,50 +513,68 @@ int MAIN(int argc, CHAR *argv[])
sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, NULL);
#endif #endif
while ((arg_off < argc) && (argv[arg_off][0] == '-') && (argv[arg_off][1] == '-')) if ((argc > 1) && (!STRCASECMP(argv[1], T("/?"))))
{
const CHAR *const arg_val = argv[arg_off++] + 2U;
if (arg_val[0] != '\0')
{
if ((!STRCASECMP(arg_val, T("help"))) || (!STRCASECMP(arg_val, T("version"))))
{ {
options |= OPT_HELPSC; options |= OPT_HELPSC;
goto print_help;
} }
else if (!STRCASECMP(arg_val, T("binary")))
while ((arg_off < argc) && (argv[arg_off][0] == T('-')) && ((argv[arg_off][1] == T('-')) || ISALPHA(argv[arg_off][1])))
{ {
options |= OPT_BINARY; const CHAR *arg_ptr = argv[arg_off++] + 1U;
} if (*arg_ptr == T('-'))
else if (!STRCASECMP(arg_val, T("upper-case")))
{ {
options |= OPT_UPPERC; if (*(++arg_ptr) != T('\0'))
}
else if (!STRCASECMP(arg_val, T("decimal")))
{ {
options |= OPT_DECIML; if (parse_option(&options, T('\0'), arg_ptr) != EXIT_SUCCESS)
}
else if (!STRCASECMP(arg_val, T("no-padding")))
{ {
options |= OPT_NOPADD; FPRINTF(stderr, T("Error: Option \"--%s\" is not recognized!\n"), arg_ptr);
}
else if (!STRCASECMP(arg_val, T("ignore-errors")))
{
options |= OPT_IGNERR;
}
else if (!STRCASECMP(arg_val, T("silent")))
{
options |= OPT_SILENT;
}
else
{
FPRINTF(stderr, T("Option \"--%s\" is not recognized!\n"), arg_val);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
else else
{ {
break; /*stop option processing*/ break; /*stop option processing here*/
} }
} }
else
{
for(; ISALPHA(*arg_ptr); ++arg_ptr)
{
if (parse_option(&options, TOLOWER(*arg_ptr), NULL) != EXIT_SUCCESS)
{
FPRINTF(stderr, T("Error: Option \"-%c\" is not recognized!\n"), *arg_ptr);
return EXIT_FAILURE;
}
}
}
}
print_help:
if ((options & OPT_HELPSC) || (options & OPT_VERSNO))
{
FPRINTF(stderr, T("CRC-64 %d.%d.%d [%s]\n"), VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, T(__DATE__));
if (options & OPT_HELPSC)
{
FPUTS(T("\nSynopsis:\n"), stderr);
FPUTS(T(" ") PROGRAM_NAME T(" [OPTIONS] [<file_1> [<file_2> ... <file_n>]]\n\n"), stderr);
FPUTS(T("Options:\n"), stderr);
FPUTS(T(" -h --help --version Show help screen / show version information\n"), stderr);
FPUTS(T(" -b --binary Output digest in binary format (default is hex-string)\n"), stderr);
FPUTS(T(" -d --decimal Output digest in decimal string format\n"), stderr);
FPUTS(T(" -u --upper-case Print digest as upper-case (default is lower-case)\n"), stderr);
FPUTS(T(" -p --no-padding Print digest *without* any leading zeros\n"), stderr);
FPUTS(T(" -s --silent Suppress error messages\n"), stderr);
FPUTS(T(" -e --ignore-errors Ignore I/O errors and proceed with the next file\n"), stderr);
FPUTS(T(" -f --no-flush Do *not* flush output stream after each file\n"), stderr);
FPUTS(T(" -z --init-with-zero Initialize CRC with 0x000..000 (default is 0xFFF..FFF)\n"), stderr);
FPUTS(T(" -n --negate-final Negate the final CRC result\n"), stderr);
FPUTS(T(" -l --append-length Append to the input its length for CRC computation\n"), stderr);
FPUTS(T(" -t --self-test Run integrated self-test and exit program\n\n"), stderr);
}
return EXIT_SUCCESS;
}
if ((options & OPT_BINARY) && (options & OPT_DECIML)) if ((options & OPT_BINARY) && (options & OPT_DECIML))
{ {
@ -382,21 +582,24 @@ int MAIN(int argc, CHAR *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (options & OPT_HELPSC) if (options & OPT_SLFTST)
{ {
FPRINTF(stderr, T("CRC64 %d.%d.%d [%s]\n\n"), VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, T(__DATE__)); FPUTS(T("Running CRC-64 self-test, please wait...\n"), stderr);
FPUTS(T("Synopsis:\n"), stderr); fflush(stderr);
FPUTS(T(" ") PROGRAM_NAME T(" [OPTIONS] [<file_1> [<file_2> ... <file_n>]]\n\n"), stderr); if (self_test() == EXIT_SUCCESS)
FPUTS(T("Options:\n"), stderr); {
FPUTS(T(" --help --version Print help screen / show version information\n"), stderr); FPUTS(T("All tests completed successfully :-)\n"), stderr);
FPUTS(T(" --binary Output the digest in binary format (default is hex-format)\n"), stderr);
FPUTS(T(" --decimal Output the digest in decimal string format\n"), stderr);
FPUTS(T(" --upper-case Print hex-string in upper-case letters (default is lower-case)\n"), stderr);
FPUTS(T(" --no-padding Print the digest *without* any leading zeros\n"), stderr);
FPUTS(T(" --silent Suppress error messages\n"), stderr);
FPUTS(T(" --ignore-errors Ignore I/O errors and proceeed with the next file\n\n"), stderr);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
else
{
if (!(options & OPT_SILENT))
{
FPUTS(g_aborted ? T("Error: Test was interrupted!\n") : T("At least one test has failed :-(\n"), stderr);
}
return EXIT_FAILURE;
}
}
#ifdef _WIN32 #ifdef _WIN32
_setmode(_fileno(stdout), (options & OPT_BINARY) ? _O_BINARY : _O_U8TEXT); _setmode(_fileno(stdout), (options & OPT_BINARY) ? _O_BINARY : _O_U8TEXT);
@ -404,9 +607,9 @@ int MAIN(int argc, CHAR *argv[])
if (arg_off < argc) if (arg_off < argc)
{ {
while ((arg_off < argc) && (!g_stop_flag)) while ((arg_off < argc) && (!g_aborted))
{ {
if (process(argv[arg_off++], options) != EXIT_SUCCESS) if (process_file(argv[arg_off++], options) != EXIT_SUCCESS)
{ {
if (!(options & OPT_IGNERR)) if (!(options & OPT_IGNERR))
{ {
@ -418,7 +621,7 @@ int MAIN(int argc, CHAR *argv[])
} }
else else
{ {
if (process(NULL, options) != EXIT_SUCCESS) if (process_file(NULL, options) != EXIT_SUCCESS)
{ {
if (!(options & OPT_IGNERR)) if (!(options & OPT_IGNERR))
{ {
@ -427,13 +630,13 @@ int MAIN(int argc, CHAR *argv[])
} }
} }
if (g_stop_flag && (!(options & OPT_SILENT))) if (g_aborted && (!(options & OPT_IGNERR)))
{
if (!(options & OPT_SILENT))
{ {
FPUTS(T("Error: Process was interrupted!\n"), stderr); FPUTS(T("Error: Process was interrupted!\n"), stderr);
if (!(options & OPT_IGNERR))
{
exit_code = 128 + SIGINT;
} }
exit_code = 128 + SIGINT;
} }
return exit_code; return exit_code;

9
dist/freebsd/mk-release.sh vendored Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
# pkg install gmake gcc12
set -e
cd -- "$(dirname -- "$0")/../.."
gmake -B CC=gcc12 XCFLAGS="-m32" MARCH=i586 MTUNE=pentium2 OUTNAME="crc64-i686"
gmake -B CC=gcc12 XCFLAGS="-m64" MARCH=x86-64 MTUNE=znver3 OUTNAME="crc64-x86_64"
echo "Build completed successfully."

36
dist/linux/mk-musl-libc.sh vendored Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
# sudo apt install curl crossbuild-essential-{i386,armel,armhf,arm64,mipsel,mips64el}
set -e
cd -- "$(dirname -- "${BASH_SOURCE[0]}")"
function mk_musl() {
printf "\033[1;36m\nBuilding musl-libc for: ${1}\033[0m\n\n"
local outdir="/usr/local/musl/${1}"
local build="musl-build-${1}"
rm -rf "${build}" && mkdir -p "${build}"
tar -xvf "musl-latest.tar.gz" --strip-components=1 -C "${build}"
pushd "${build}"
local optdirs="$(find './src' -mindepth 1 -maxdepth 1 -type d -printf '%f,' | sed 's/,$//g')"
CFLAGS="${3}" ./configure --enable-optimize="${optdirs}" --disable-shared --prefix="${outdir}" ${2:+--host=$2}
make
sudo rm -rf "${outdir}"
sudo make install
popd
}
if [ "$(gcc -dumpmachine)" != "x86_64-linux-gnu" ]; then
echo "This script is supposed to run on the native \"x86_64-linux-gnu\" platform !!!"
exit 1
fi
curl -vkf -o "musl-latest.tar.gz" "https://musl.libc.org/releases/musl-latest.tar.gz"
mk_musl x86_64 "" "-march=x86-64 -mtune=znver3"
mk_musl i686 i686-linux-gnu "-march=i586 -mtune=pentium2"
mk_musl armel arm-linux-gnueabi
mk_musl armhf arm-linux-gnueabihf
mk_musl arm64 aarch64-linux-gnu
mk_musl mipsel mipsel-linux-gnu
mk_musl mips64el mips64el-linux-gnuabi64
printf "\033[1;32m\nBuild completed successfully.\033[0m\n\n"

10
dist/linux/mk-release.sh vendored Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
set -e
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
find /usr/local/musl -mindepth 2 -type f -executable \( -name 'musl-gcc' -or -name 'musl-clang' \) -printf '%P\0' | \
while IFS= read -r -d '' filename; do
make -B CC="/usr/local/musl/${filename}" OUTNAME="crc64-$(grep -Po '^[^/\\]+' <<< "${filename}")"
done
printf "\033[1;32m\nBuild completed successfully.\033[0m\n\n"

11
dist/macosx/mk-release.sh vendored Executable file
View File

@ -0,0 +1,11 @@
#!/bin/zsh
# xcode-select -install
set -e
cd -- "$(dirname -- "$0")/../.."
make -B MARCH= MTUNE= STATIC=0 STRIP=0 XCFLAGS="-target x86_64-apple-darwin" OUTNAME="crc64-x86_64"
make -B MARCH= MTUNE= STATIC=0 STRIP=0 XCFLAGS="-target arm64-apple-darwin" OUTNAME="crc64-arm64"
strip crc64-*
echo "Build completed successfully."

34
dist/win32/mk-release.cmd vendored Normal file
View File

@ -0,0 +1,34 @@
@echo off
setlocal enabledelayedexpansion
cd "%~dp0\..\..\win32"
if "%MSVC_PATH%"=="" (
set "MSVC_PATH=C:\Program Files\Microsoft Visual Studio\2022\Community\VC"
)
if not exist "%MSVC_PATH%\Auxiliary\Build\vcvarsall.bat" (
echo MSVC not found. Please check MSVC_PATH and try again ^^!^^!^^!
pause
goto:eof
)
for %%p in (x86,x64,ARM64) do (
echo ------------------------------------------------------------------------------
echo [%%p]
echo ------------------------------------------------------------------------------
call "%MSVC_PATH%\Auxiliary\Build\vcvarsall.bat" %%~p
for %%t in (Clean,Rebuild) do (
MSBuild.exe /property:Configuration=Release /property:Platform=%%p /target:%%t /verbosity:normal "%CD%\crc64.sln"
if not "!ERRORLEVEL!"=="0" goto:BuildFailed
)
echo.
)
echo Build completed successfully.
pause
goto:eof
:BuildFailed
echo.
echo Build has failed ^^!^^!^^!
pause

14
win32/crc64.props Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<XPDeprecationWarning>false</XPDeprecationWarning>
</PropertyGroup>
<PropertyGroup />
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="XPDeprecationWarning">
<Value>$(XPDeprecationWarning)</Value>
</BuildMacro>
</ItemGroup>
</Project>

View File

@ -53,12 +53,15 @@
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="crc64.props" />
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="crc64.props" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="crc64.props" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">