aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-08-28 16:42:05 +0200
committerMattias Andrée <maandree@kth.se>2024-08-28 16:42:05 +0200
commita24071ae913b223487df78859c8d830f9e69f580 (patch)
treee2ec712cc29461c82cfdd477e8b1ba961b50018d
parentFirst commit (diff)
downloadanysum-a24071ae913b223487df78859c8d830f9e69f580.tar.gz
anysum-a24071ae913b223487df78859c8d830f9e69f580.tar.bz2
anysum-a24071ae913b223487df78859c8d830f9e69f580.tar.xz
Second commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile41
-rw-r--r--README288
-rw-r--r--anysum.1428
-rw-r--r--anysum.c164
-rw-r--r--b224sum.1224
-rw-r--r--b256sum.1224
-rw-r--r--b384sum.1224
-rw-r--r--b512sum.1224
-rw-r--r--barrier.c (renamed from createbarriergroup.c)58
-rw-r--r--barriersend.c16
-rw-r--r--barrierwait.c17
-rw-r--r--bsum.1240
-rw-r--r--calculate.c55
-rw-r--r--check.c282
-rw-r--r--cmdline.c84
-rw-r--r--cmdline_bsum.c102
-rw-r--r--cmdline_other.c60
-rw-r--r--cmdline_sha3sum.c321
-rw-r--r--command.c101
-rw-r--r--common.h101
-rw-r--r--config.mk4
-rw-r--r--destroyhashers.c12
-rw-r--r--feedbuffer.c23
-rw-r--r--get.c99
-rw-r--r--hash.c98
-rw-r--r--hex.c13
-rw-r--r--inithashers.c21
-rw-r--r--keccak224sum.1209
-rw-r--r--keccak256sum.1209
-rw-r--r--keccak384sum.1209
-rw-r--r--keccak512sum.1209
-rw-r--r--keccaksum.1241
-rw-r--r--killbarriergroup.c29
-rw-r--r--md2sum.1203
-rw-r--r--md4sum.1203
-rw-r--r--md5sum.1203
-rw-r--r--mk/before-config.mk21
-rw-r--r--mk/blake224=yes.mk3
-rw-r--r--mk/blake256=yes.mk3
-rw-r--r--mk/blake384=yes.mk3
-rw-r--r--mk/blake512=yes.mk3
-rw-r--r--mk/keccak=yes.mk2
-rw-r--r--mk/md2=yes.mk2
-rw-r--r--mk/md4=yes.mk2
-rw-r--r--mk/md5=yes.mk2
-rw-r--r--mk/rawshake=yes.mk2
-rw-r--r--mk/ripemd-128=yes.mk2
-rw-r--r--mk/ripemd-160=yes.mk2
-rw-r--r--mk/ripemd-256=yes.mk2
-rw-r--r--mk/ripemd-320=yes.mk2
-rw-r--r--mk/sha1=yes.mk3
-rw-r--r--mk/sha2=yes.mk2
-rw-r--r--mk/sha3=yes.mk2
-rw-r--r--mk/shake=yes.mk2
-rw-r--r--open.c (renamed from openfile.c)18
-rw-r--r--opts.c130
-rw-r--r--patheq.c20
-rw-r--r--proc.c73
-rw-r--r--rawshake128sum.1214
-rw-r--r--rawshake256sum.1214
-rw-r--r--rawshake512sum.1214
-rw-r--r--read.c78
-rw-r--r--rmd128sum.1201
-rw-r--r--rmd160sum.1201
-rw-r--r--rmd256sum.1201
-rw-r--r--rmd320sum.1201
-rw-r--r--sha0sum.1203
-rw-r--r--sha1sum.1203
-rw-r--r--sha224sum.1202
-rw-r--r--sha256sum.1202
-rw-r--r--sha3-224sum.1209
-rw-r--r--sha3-256sum.1209
-rw-r--r--sha3-384sum.1209
-rw-r--r--sha3-512sum.1209
-rw-r--r--sha384sum.1202
-rw-r--r--sha3sum.1218
-rw-r--r--sha512-224sum.1202
-rw-r--r--sha512-256sum.1202
-rw-r--r--sha512sum.1202
-rw-r--r--shake128sum.1214
-rw-r--r--shake256sum.1214
-rw-r--r--shake512sum.1214
-rw-r--r--shiftbuffer.c16
-rw-r--r--write.c (renamed from format_result.c)33
-rw-r--r--writeall.c21
85 files changed, 10114 insertions, 334 deletions
diff --git a/Makefile b/Makefile
index ab1b4e4..f061ffa 100644
--- a/Makefile
+++ b/Makefile
@@ -10,24 +10,28 @@ include mk/after-config.mk
OBJ =\
anysum.o\
- patheq.o\
- openfile.o\
- hex.o\
- writeall.o\
- barrierwait.o\
- barriersend.o\
- format_result.o\
- feedbuffer.o\
- createbarriergroup.o\
- killbarriergroup.o\
- inithashers.o\
- destroyhashers.o\
- shiftbuffer.o\
- calculate.o
+ get.o\
+ check.o\
+ barrier.o\
+ hash.o\
+ write.o\
+ open.o\
+ read.o\
+ proc.o\
+ command.o\
+ opts.o\
+ cmdline_bsum.o\
+ cmdline_sha3sum.o\
+ cmdline_other.o\
+ cmdline.o
HDR =\
common.h
+MAN1 =\
+ anysum.1\
+ $(ALIASES:=.1)
+
all: anysum
$(OBJ): $(HDR)
@@ -41,11 +45,16 @@ install: anysum
mkdir -p -- "$(DESTDIR)$(PREFIX)/bin"
mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1/"
cp -- anysum "$(DESTDIR)$(PREFIX)/bin/"
- cp -- anysum.1 "$(DESTDIR)$(MANPREFIX)/man1/"
+ cp -- $(MAN1) "$(DESTDIR)$(MANPREFIX)/man1/"
+ set -e; for a in $(ALIASES); do\
+ test ! -d "$(DESTDIR)$(PREFIX)/bin/$$a";\
+ ln -sf -- anysum "$(DESTDIR)$(PREFIX)/bin/$$a";\
+ done
uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/bin/anysum"
- -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/anysum.1"
+ -cd -- "$(DESTDIR)$(MANPREFIX)/man1/" && rm -f -- $(MAN1)
+ -cd -- "$(DESTDIR)$(PREFIX)/bin/" && rm -f -- $(ALIASES)
clean:
-rm -f -- *.o *.a *.lo *.su *.so *.so.* *.gch *.gcov *.gcno *.gcda
diff --git a/README b/README
new file mode 100644
index 0000000..cfef42b
--- /dev/null
+++ b/README
@@ -0,0 +1,288 @@
+NAME
+ anysum - compute or verify against multiple checksums
+
+SYNOPSIS
+ anysum (-c [-w] | [-a algoritms] ...) [-W options] ...
+ [-z] [file] ...
+
+DESCRIPTION
+ The anysum utility can calculate checksums of a file using
+ multiple hash functions, or using different parameters for
+ the function, in parallel (the utility can calculate checksums
+ for multiple files, but these are not calculated in parallel).
+
+ The anysum utility can also check a file against multiple
+ checksums using multiple hash function and hash function
+ parameters in parallel, and check that the file matches at
+ least one of the listed checksums.
+
+OPTIONS
+ The anysum utility conforms to the Base Definitions volume of
+ POSIX.1-2017, Section 12.2, Utility Syntax Guidelines.
+
+ The following options are supported:
+
+ -a algorithms
+ Comma-separated list of hash functions and
+ parameters to compute checksums with.
+
+ Currently supported values are:
+
+ md2
+ For MD2.
+
+ md4
+ For MD4.
+
+ md5
+ For MD5.
+
+ ripemd128 or rmd128
+ For RIPEMD-128.
+
+ ripemd160 or rmd160
+ For RIPEMD-160.
+
+ ripemd256 or rmd256
+ For RIPEMD-256.
+
+ ripemd320 or rmd320
+ For RIPEMD-320.
+
+ sha0
+ For SHA-0.
+
+ sha1
+ For SHA-1.
+
+ sha224
+ For the 224 bit version of SHA-2.
+
+ sha256
+ For the 256 bit version of SHA-2.
+
+ sha384
+ For the 384 bit version of SHA-2.
+
+ sha512
+ For the 512 bit version of SHA-2.
+
+ sha512/224
+ For the 224 bit output variant of the
+ 512 (and 384) bit version of SHA-2.
+
+ sha512/256
+ For the 256 bit output variant of the
+ 512 (and 384) bit version of SHA-2.
+
+ keccak[r=BITRATE,c=CAPACITY,n=LENGTH,z=SQUEEZES]
+ For Keccak. The brackets and there parameter
+ list, and each parameter, are optional. Any
+ parameter the is skipped is automatically
+ determined. BITRATE and CAPACITY are the
+ Keccak function's bitrate and capacity bit
+ bits, and LENGTH is the hash length is bits.
+ SQUEEZES is the number of squeezes to perform
+ after a input has been feed into the function;
+ the default is one, and any number in excess
+ of this is the number of squeezes to perform
+ before squeezing out the hash.
+
+ keccak-224
+ For Keccak[r=1152,c=448,n=224].
+
+ keccak-256
+ For Keccak[r=1088,c=512,n=256].
+
+ keccak-384
+ For Keccak[r=832,c=768,n=384].
+
+ keccak-512
+ For Keccak[r=576,c=1024,n=512].
+
+ sha3-224
+ For the 224 bit version of SHA-3.
+
+ sha3-256
+ For the 256 bit version of SHA-3.
+
+ sha3-384
+ For the 384 bit version of SHA-3.
+
+ sha3-512
+ For the 512 bit version of SHA-3.
+
+ shake-128[n=LENGTH]
+ For the 128 bit version of SHAKE. The brackets
+ and n=LENGTH are optional; LENGTH shall the
+ output size in bits (default is 128).
+
+ shake-256[n=LENGTH]
+ For the 256 bit version of SHAKE. The brackets
+ and n=LENGTH are optional; LENGTH shall the
+ output size in bits (default is 256).
+
+ shake-512[n=LENGTH]
+ For the 512 bit version of SHAKE. The brackets
+ and n=LENGTH are optional; LENGTH shall the
+ output size in bits (default is 512).
+
+ rawshake-128[n=LENGTH]
+ For the 128 bit version of RawSHAKE. The
+ brackets and n=LENGTH are optional; LENGTH
+ shall the output size in bits (default is 128).
+
+ rawshake-256[n=LENGTH]
+ For the 256 bit version of RawSHAKE. The
+ brackets and n=LENGTH are optional; LENGTH
+ shall the output size in bits (default is 256).
+
+ rawshake-512[n=LENGTH]
+ For the 512 bit version of RawSHAKE. The
+ brackets and n=LENGTH are optional; LENGTH
+ shall the output size in bits (default is 512).
+
+ blake224[salt=SALT] or b224[salt=SALT]
+ For the 224 bit version of BLAKE. The brackets
+ and salt=SALT are optional; SALT shall be a 32
+ character long hexadecimal value.
+
+ blake256[salt=SALT] or b256[salt=SALT]
+ For the 256 bit version of BLAKE. The brackets
+ and salt=SALT are optional; SALT shall be a 32
+ character long hexadecimal value.
+
+ blake384[salt=SALT] or b384[salt=SALT]
+ For the 384 bit version of BLAKE. The brackets
+ and salt=SALT are optional; SALT shall be a 64
+ character long hexadecimal value.
+
+ blake512[salt=SALT] or b512[salt=SALT]
+ For the 512 bit version of BLAKE. The brackets
+ and salt=SALT are optional; SALT shall be a 64
+ character long hexadecimal value.
+
+ The utility does also recognise similar values
+ that are obviously equivalent.
+
+ -b
+ Read in binary mode when computing hashes.
+
+ -c
+ Verify the the files listed in file against the
+ checksums listed on the same lines. The file
+ shall be formatted as the output of the utility
+ when this option is not used. See the STDOUT
+ section for more information. If a file is listed
+ multiple times, it need only match one of the
+ checksums listed for the file.
+
+ The length of the listed checksums need not match
+ the length output by this utility; before the
+ checksums are compared, they are truncated to the
+ shorter of the two checksums.
+
+ -t
+ Read in text mode when computing hashes.
+
+ -W options
+ Comma-sepearated list of implementation-specific
+ options. The following options are supported:
+
+ output=format
+ format shall be "lowercase" if the checksums
+ shall be printed in lowercase hexadecimal
+ format (default), "uppercase" for uppercase
+ hexadecimal format, or "binary" for binary
+ format without anything but the checksum
+ printed to standard output. This option is
+ ignored if the -c option is used.
+
+ input=format
+ format shall be "binary" if the files are
+ be read in binary mode, "text" if the files
+ shall be read in text mode, or "hexadecimal"
+ they shall be decoded from hexadecimal to
+ binary. If the -c option is used, the mode
+ specification associated with a file is
+ overrides this behaviour for that file if
+ the line specifies hexadecimal mode.
+
+ threads=count
+ The maximum number of threads that the
+ utility may use. If "auto" is specified,
+ the utility selects a default value, which
+ currently is the number of online CPU threads
+ (at any time; assumed to be 8 if it cannot
+ be determined) minus 2, or 1 if this would
+ be less than 1.
+
+ recursive
+ If a file operand is a directory, the checksum
+ is computed for all files recursively.
+ This option is ignored if the -c option is
+ used.
+
+ no-recursive
+ The utility shall traverse directories.
+ (This is the default behaviour).
+
+ -w
+ Warn about, but skip, lines that are not properly
+ formatted.
+
+ -z
+ Use NUL byte as line ending instead of LF.
+
+ There is no difference between binary mode and text mode,
+ so the -b and -t options are ignored.
+
+OPERANDS
+ The following operand is supported:
+
+ file
+ The file to read and compute the checksum for, or if
+ the -c option is used, use as the listing of files
+ and checksums to verify the files against. If dash
+ ('-') is used or if no file operand is specified,
+ standard input will be used.
+
+STDOUT
+ If the -c option is not used, the utility shall print the
+ following line for each calculated checksum, however there
+ are options that modify the format; see the OPTIONS section
+ for more information:
+
+ "%s:%s %c%s\n", <hash function>, <hash>, <mode>,
+ <file>
+
+ where <mode> is SP (' ') for text mode, an asterisk ('*')
+ for binary mode, or a pound sign ('#') for hexadecimal
+ mode; however if there is no difference between binary
+ mode and text mode and either is selected, SP (' ')
+ (text mode) is used.
+
+ If the -c option the output shall be on the format:
+
+ "%s: %s\n", <file>, <validity>
+
+ where <validity> is an implementation specified string
+ that describes whether the checksum was valid (possibly
+ with remarks), the file did not exist, the file could
+ not be read (possibly with error information), or if
+ the checksum was invalid or could not be compared
+ (possibly with remarks). The -z option does not modify
+ the line ending.
+
+EXIT STATUS
+ The following exit values are returned:
+
+ 0 Successful completion.
+
+ 1 Checksums did not match or a file did not exist.
+
+ 2 An error occurred.
+
+NOTES
+ Other implementations do not necessarily recognise the
+ '#' mode specifier in checksum list files.
diff --git a/anysum.1 b/anysum.1
new file mode 100644
index 0000000..b2038cc
--- /dev/null
+++ b/anysum.1
@@ -0,0 +1,428 @@
+.TH ANYSUM 1 anysum
+.SH NAME
+anysum - compute or verify against multiple checksums
+
+.SH SYNOPSIS
+.B anysum
+.RB ( -c
+.RB [ -w ]
+|
+.RB [ -a
+.IR algoritms ]\ ...)
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B anysum
+utility can calculate checksums of a file using
+multiple hash functions, or using different parameters for
+the function, in parallel (the utility can calculate checksums
+for multiple files, but these are not calculated in parallel).
+.PP
+The
+.B anysum
+utility can also check a file against multiple
+checksums using multiple hash function and hash function
+parameters in parallel, and check that the file matches at
+least one of the listed checksums.
+
+.SH OPTIONS
+The anysum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.BR -a \ \fIalgorithms\fP
+Comma-separated list of hash functions and
+parameters to compute checksums with.
+
+Currently supported values are:
+.RS
+.TP
+.B md2
+For MD2.
+.TP
+.B md4
+For MD4.
+.TP
+.B md5
+For MD5.
+.TP
+.BR ripemd128 " or " rmd128
+For RIPEMD-128.
+.TP
+.BR ripemd160 " or " rmd160
+For RIPEMD-160.
+.TP
+.BR ripemd256 " or " rmd256
+For RIPEMD-256.
+.TP
+.BR ripemd320 " or " rmd320
+For RIPEMD-320.
+.TP
+.B sha0
+For SHA-0.
+.TP
+.B sha1
+For SHA-1.
+.TP
+.B sha224
+For the 224 bit version of SHA-2.
+.TP
+.B sha256
+For the 256 bit version of SHA-2.
+.TP
+.B sha384
+For the 384 bit version of SHA-2.
+.TP
+.B sha512
+For the 512 bit version of SHA-2.
+.TP
+.B sha512/224
+For the 224 bit output variant of the
+512 (and 384) bit version of SHA-2.
+.TP
+.B sha512/256
+For the 256 bit output variant of the
+512 (and 384) bit version of SHA-2.
+.TP
+.BI keccak[r= bitrate ,c= capacity ,n= length ,z= squeezes ]
+For Keccak. The brackets and there parameter
+list, and each parameter, are optional. Any
+parameter the is skipped is automatically
+determined.
+.I bitrate
+and
+.I capacity
+are the Keccak function's bitrate and
+capacity bit bits, and
+.I length
+is the hash length is bits.
+.I squeezes
+is the number of squeezes to perform
+after a input has been feed into the function;
+the default is one, and any number in excess
+of this is the number of squeezes to perform
+before squeezing out the hash.
+.TP
+.B keccak-224
+For Keccak[r=1152,c=448,n=224].
+.TP
+.B keccak-256
+For Keccak[r=1088,c=512,n=256].
+.TP
+.B keccak-384
+For Keccak[r=832,c=768,n=384].
+.TP
+.B keccak-512
+For Keccak[r=576,c=1024,n=512].
+.TP
+.B sha3-224
+For the 224 bit version of SHA-3.
+.TP
+.B sha3-256
+For the 256 bit version of SHA-3.
+.TP
+.B sha3-384
+For the 384 bit version of SHA-3.
+.TP
+.B sha3-512
+For the 512 bit version of SHA-3.
+.TP
+.BI shake-128[n= length ]
+For the 128 bit version of SHAKE. The brackets and
+.BI n= length
+are optional;
+.I length
+shall the output size in bits (default is 128).
+.TP
+.BI shake-256[n= length ]
+For the 256 bit version of SHAKE. The brackets and
+.BI n= length
+are optional;
+.I length
+shall the output size in bits (default is 256).
+.TP
+.BI shake-512[n= length ]
+For the 512 bit version of SHAKE. The brackets and
+.BI n= length
+are optional;
+.I length
+shall the output size in bits (default is 512).
+.TP
+.BI rawshake-128[n= length ]
+For the 128 bit version of RawSHAKE. The
+brackets and
+.BI n= length
+are optional;
+.I length
+shall the output size in bits (default is 128).
+.TP
+.BI rawshake-256[n= length ]
+For the 256 bit version of RawSHAKE. The
+brackets and
+.BI n= length
+are optional;
+.I length
+shall the output size in bits (default is 256).
+.TP
+.BI rawshake-512[n= length ]
+For the 512 bit version of RawSHAKE. The
+brackets and
+.BI n= length
+are optional;
+.I length
+shall the output size in bits (default is 512).
+.TP
+.BR blake224[salt= \fIsalt\fP ] " or " b224[salt= \fIsalt\fP ]
+For the 224 bit version of BLAKE. The brackets and
+.BI salt= salt
+are optional;
+.I salt
+shall be a 32 character long hexadecimal value.
+.TP
+.BR blake256[salt= \fIsalt\fP ] " or " b256[salt= \fIsalt\fP ]
+For the 256 bit version of BLAKE. The brackets and
+.BI salt= salt
+are optional;
+.I salt
+shall be a 32 character long hexadecimal value.
+.TP
+.BR blake384[salt= \fIsalt\fP ] " or " b384[salt= \fIsalt\fP ]
+For the 384 bit version of BLAKE. The brackets and
+.BI salt= salt
+are optional;
+.I salt
+shall be a 64 character long hexadecimal value.
+.TP
+.BR blake512[salt= \fIsalt\fP ] " or " b512[salt= \fIsalt\fP ]
+For the 512 bit version of BLAKE. The brackets and
+.BI salt= salt
+are optional;
+.I salt
+shall be a 64 character long hexadecimal value.
+.PP
+The utility does also recognise similar values
+that are obviously equivalent.
+.RE
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.BI threads= count
+The maximum number of threads that the
+utility may use. If
+.RB \(dq auto \(dq
+is specified, the utility selects a default
+value, which currently is the number of
+online CPU threads (at any time; assumed to
+be 8 if it cannot be determined) minus 2,
+or 1 if this would be less than 1.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s:%s %c%s\en\(dq,
+.RI < "hash function" >\fB,\fP
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR md2sum (1),
+.BR md4sum (1),
+.BR md5sum (1),
+.BR rmd128sum (1),
+.BR rmd256sum (1),
+.BR rmd384sum (1),
+.BR rmd512sum (1),
+.BR sha0sum (1),
+.BR sha1sum (1),
+.BR sha224sum (1),
+.BR sha256sum (1),
+.BR sha384sum (1),
+.BR sha512sum (1),
+.BR sha512-224sum (1),
+.BR sha512-256sum (1),
+.BR sha3sum (1),
+.BR sha3-224sum (1),
+.BR sha3-256sum (1),
+.BR sha3-384sum (1),
+.BR sha3-512sum (1),
+.BR keccaksum (1),
+.BR keccak224sum (1),
+.BR keccak256sum (1),
+.BR keccak384sum (1),
+.BR keccak512sum (1),
+.BR shake128sum (1),
+.BR shake256sum (1),
+.BR shake512sum (1),
+.BR rawshake128sum (1),
+.BR rawshake256sum (1),
+.BR rawshake512sum (1),
+.BR bsum (1),
+.BR b224sum (1),
+.BR b256sum (1),
+.BR b384sum (1),
+.BR b512sum (1)
diff --git a/anysum.c b/anysum.c
index a478a7a..6853ca5 100644
--- a/anysum.c
+++ b/anysum.c
@@ -1,75 +1,117 @@
/* See LICENSE file for copyright and license details. */
#include "common.h"
-#include <libsimple-arg.h>
-NUSAGE(2, "[file] ...");
-
-static int
-calculate_and_print(const char *file, struct barrier_group *group, struct global_data *global)
-{
- size_t i;
- if (calculate(file, group, global))
- return -1;
- for (i = 0; i < global->nalgorithms; i++)
- writeall(STDOUT_FILENO, global->algorithms[i].result, global->algorithms[i].result_length, "<stdout>");
- return 0;
-}
-
-
-static int
-calculate_each_and_print(char **files, struct algorithm *algorithms, size_t nalgorithms, enum format format)
-{
- size_t wanted_nalgorithms = nalgorithms;
- struct buffer buffer = {0};
- int r, ret = 0;
- struct barrier_group group;
- struct global_data global;
-
- global.format = format;
- global.buffer = &buffer;
- global.algorithms = algorithms;
- global.nalgorithms = nalgorithms;
-
- createbarriergroup(&group, nalgorithms, &global);
-
- if (!*files) {
- global.file = "-";
- ret = calculate_and_print("-", &group, &global) ? 2 : 0;
- }
- while (*files) {
- global.file = *files;
- r = calculate_and_print(*files++, &group, &global) ? 2 : 0;
- ret = MAX(r, ret);
- }
-
- if (nalgorithms != wanted_nalgorithms)
- ret = 2;
-
- killbarriergroup(&group, &global);
-
- free(buffer.buf);
- return ret;
-}
+static const char *default_algostrs[] = {
+#if defined(SUPPORT_MD2) && 0 /* skipping: compromised is theory */
+ "MD2",
+#endif
+#if defined(SUPPORT_MD4) && 0 /* skipping: compromised */
+ "MD4",
+#endif
+#if defined(SUPPORT_MD5) && 0 /* skipping: compromised */
+ "MD5",
+#endif
+#if defined(SUPPORT_RIPEMD_128) && 1
+ "RIPEMD-128",
+#endif
+#if defined(SUPPORT_RIPEMD_160) && 1
+ "RIPEMD-160",
+#endif
+#if defined(SUPPORT_RIPEMD_256) && 1
+ "RIPEMD-256",
+#endif
+#if defined(SUPPORT_RIPEMD_320) && 1
+ "RIPEMD-320",
+#endif
+#if defined(SUPPORT_SHA0) && 0 /* skipping: compromised */
+ "SHA0",
+#endif
+#if defined(SUPPORT_SHA1) && 0 /* skipping: compromised */
+ "SHA1",
+#endif
+#if defined(SUPPORT_SHA2) && 1
+ "SHA-224",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512",
+ "SHA-512/224",
+ "SHA-512/256",
+#endif
+#if defined(SUPPORT_SHA3) && 1
+ "SHA3-224",
+ "SHA3-256",
+ "SHA3-384",
+ "SHA3-512",
+#endif
+#if defined(SUPPORT_KECCAK) && 1
+ "Keccak-224",
+ "Keccak-256",
+ "Keccak-384",
+ "Keccak-512",
+#endif
+#if defined(SUPPORT_RAWSHAKE) && 1
+ "RawSHAKE128",
+ "RawSHAKE256",
+ "RawSHAKE512",
+#endif
+#if defined(SUPPORT_SHAKE) && 1
+ "SHAKE128",
+ "SHAKE256",
+ "SHAKE512",
+#endif
+#if defined(SUPPORT_BLAKE224) && 1
+ "BLAKE224",
+#endif
+#if defined(SUPPORT_BLAKE256) && 1
+ "BLAKE256",
+#endif
+#if defined(SUPPORT_BLAKE384) && 1
+ "BLAKE384",
+#endif
+#if defined(SUPPORT_BLAKE512) && 1
+ "BLAKE512",
+#endif
+ NULL
+};
int
-main(int argc, char *argv[])
+main(int argc, char **argv)
{
- enum format format = LOWERCASE_HEX | WITH_ALGOSTR | WITH_FILENAME | WITH_LF;
- struct algorithm algorithms[] = {{"sha1"}, {"sha2-512/224"}, {"sha1"}};
- size_t i, nalgorithms = ELEMSOF(algorithms);
+ struct algorithm default_algorithms[ELEMSOF(default_algostrs)];
+ struct config config = {.format = LOWERCASE_HEX | WITH_FILENAME | WITH_LF};
+ char stdin_str[] = "-";
+ char *stdin_array[] = {stdin_str, NULL};
+ size_t i;
int ret;
libsimple_default_failure_exit = 2;
+ cmdline(&argc, &argv, &config);
+ if (!*argv)
+ argv = stdin_array;
+
+ if (config.verify) {
+ ret = verify_checksums(argv, config.algorithms, config.nalgorithms, config.format,
+ config.threads, config.warn_improper_format, config.hexinput);
+ } else {
+ if (!config.nalgorithms) {
+ memset(default_algorithms, 0, sizeof(default_algorithms));
+ for (i = 0; default_algostrs[i]; i++) {
+ default_algorithms[i].algostr = default_algostrs[i];
+ default_algorithms[i].result = NULL;
+ }
+ config.nalgorithms = i;
+ if (!config.nalgorithms) {
+ eprintf("not compiled to support any default hash functions");
+ }
+ }
+ ret = calculate_and_print_each(argv, config.algorithms, config.nalgorithms, config.threads,
+ config.format, config.hexinput, config.recursive);
+ }
- ARGBEGIN {
- default:
- usage();
- } ARGEND;
-
- ret = calculate_each_and_print(argv, algorithms, nalgorithms, format);
- for (i = 0; i < nalgorithms; i++)
- free(algorithms[i].result);
+ for (i = 0; i < config.nalgorithms; i++)
+ free(config.algorithms[i].result);
+ free(config.algorithms);
return ret;
}
diff --git a/b224sum.1 b/b224sum.1
new file mode 100644
index 0000000..7f3551f
--- /dev/null
+++ b/b224sum.1
@@ -0,0 +1,224 @@
+.TH B224SUM 1 anysum
+.SH NAME
+b224sum - compute or verify against multiple BLAKE-224 hashes
+
+.SH SYNOPSIS
+.B b224sum
+.RB [ -c
+.RB [ -w ]]
+.BR [ -S
+.IR salt ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B b224sum
+utility calculates and prints or checks BLAKE-224
+checksums.
+.PP
+The
+.B b224sum
+utility can also check a file against multiple BLAKE-224
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The b224sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -B
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -L
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -S \ \fIsalt\fP
+16-byte salt, encoded as a 32 character long
+hexadecimal string.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.B -U
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/b256sum.1 b/b256sum.1
new file mode 100644
index 0000000..511542a
--- /dev/null
+++ b/b256sum.1
@@ -0,0 +1,224 @@
+.TH B256SUM 1 anysum
+.SH NAME
+b256sum - compute or verify against multiple BLAKE-256 hashes
+
+.SH SYNOPSIS
+.B b256sum
+.RB [ -c
+.RB [ -w ]]
+.BR [ -S
+.IR salt ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B b256sum
+utility calculates and prints or checks BLAKE-256
+checksums.
+.PP
+The
+.B b256sum
+utility can also check a file against multiple BLAKE-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The b256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -B
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -L
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -S \ \fIsalt\fP
+16-byte salt, encoded as a 32 character long
+hexadecimal string.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.B -U
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/b384sum.1 b/b384sum.1
new file mode 100644
index 0000000..43aca61
--- /dev/null
+++ b/b384sum.1
@@ -0,0 +1,224 @@
+.TH B384SUM 1 anysum
+.SH NAME
+b384sum - compute or verify against multiple BLAKE-384 hashes
+
+.SH SYNOPSIS
+.B b384sum
+.RB [ -c
+.RB [ -w ]]
+.BR [ -S
+.IR salt ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B b384sum
+utility calculates and prints or checks BLAKE-384
+checksums.
+.PP
+The
+.B b384sum
+utility can also check a file against multiple BLAKE-384
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The b384sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -B
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -L
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -S \ \fIsalt\fP
+32-byte salt, encoded as a 64 character long
+hexadecimal string.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.B -U
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/b512sum.1 b/b512sum.1
new file mode 100644
index 0000000..92d883d
--- /dev/null
+++ b/b512sum.1
@@ -0,0 +1,224 @@
+.TH B512SUM 1 anysum
+.SH NAME
+b512sum - compute or verify against multiple BLAKE-512 hashes
+
+.SH SYNOPSIS
+.B b512sum
+.RB [ -c
+.RB [ -w ]]
+.BR [ -S
+.IR salt ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B b512sum
+utility calculates and prints or checks BLAKE-512
+checksums.
+.PP
+The
+.B b512sum
+utility can also check a file against multiple BLAKE-512
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The b512sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -B
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -L
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -S \ \fIsalt\fP
+32-byte salt, encoded as a 64 character long
+hexadecimal string.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.B -U
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/createbarriergroup.c b/barrier.c
index 694032b..cd7bae8 100644
--- a/createbarriergroup.c
+++ b/barrier.c
@@ -2,6 +2,35 @@
#include "common.h"
+void
+barrierwait(pthread_barrier_t *barrier)
+{
+#ifndef SINGLE_THREADED
+ int r = pthread_barrier_wait(barrier);
+ if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) {
+ errno = r;
+ eprintf("pthread_barrier_wait:");
+ }
+#else
+ (void) barrier;
+#endif
+}
+
+
+void
+barriersend(struct barrier_group *group, struct global_data *global, void (*action)(struct algorithm *, struct global_data *))
+{
+ size_t index;
+ global->action = action;
+ if (group->nthreads)
+ barrierwait(&group->barrier);
+ for (index = 0; index < global->nalgorithms; index += group->nthreads + 1U)
+ (*action)(&global->algorithms[index], global);
+ if (group->nthreads)
+ barrierwait(&group->barrier);
+}
+
+
#ifndef SINGLE_THREADED
static void *
slaveloop(void *thread_param)
@@ -31,8 +60,6 @@ createbarriergroup(struct barrier_group *group_out, size_t count, struct global_
#ifndef SINGLE_THREADED
size_t i;
- count = MAX(count, 64);
-
group_out->nthreads = count - 1U;
group_out->threads = NULL;
if (!group_out->nthreads)
@@ -57,3 +84,30 @@ createbarriergroup(struct barrier_group *group_out, size_t count, struct global_
(void) count;
#endif
}
+
+
+void
+killbarriergroup(struct barrier_group *group, struct global_data *global)
+{
+#ifndef SINGLE_THREADED
+ size_t i;
+
+ if (!group->nthreads)
+ return;
+
+ global->action = NULL;
+ for (i = 0; i < group->nthreads; i++)
+ group->threads[i].global = global;
+ barrierwait(&group->barrier);
+
+ for (i = 0; i < group->nthreads; i++)
+ if ((errno = pthread_join(group->threads[i].thread, NULL)))
+ weprintf("pthread_join:");
+ pthread_barrier_destroy(&group->barrier);
+
+ free(group->threads);
+#else
+ (void) group;
+ (void) global;
+#endif
+}
diff --git a/barriersend.c b/barriersend.c
deleted file mode 100644
index a947357..0000000
--- a/barriersend.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-void
-barriersend(struct barrier_group *group, struct global_data *global, void (*action)(struct algorithm *, struct global_data *))
-{
- size_t index;
- global->action = action;
- if (group->nthreads)
- barrierwait(&group->barrier);
- for (index = 0; index < global->nalgorithms; index += group->nthreads + 1U)
- (*action)(&global->algorithms[index], global);
- if (group->nthreads)
- barrierwait(&group->barrier);
-}
diff --git a/barrierwait.c b/barrierwait.c
deleted file mode 100644
index a310a27..0000000
--- a/barrierwait.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-void
-barrierwait(pthread_barrier_t *barrier)
-{
-#ifndef SINGLE_THREADED
- int r = pthread_barrier_wait(barrier);
- if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) {
- errno = r;
- eprintf("pthread_barrier_wait:");
- }
-#else
- (void) barrier;
-#endif
-}
diff --git a/bsum.1 b/bsum.1
new file mode 100644
index 0000000..e897946
--- /dev/null
+++ b/bsum.1
@@ -0,0 +1,240 @@
+.TH BSUM 1 anysum
+.SH NAME
+bsum - compute or verify against multiple BLAKE hashes
+
+.SH SYNOPSIS
+.B bsum
+.RB [ -c
+.RB [ -w ]]
+.BR [ -l
+.IR bits ]
+.BR [ -S
+.IR salt ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B bsum
+utility calculates and prints or checks BLAKE
+checksums.
+.PP
+The
+.B bsum
+utility can also check a file against multiple BLAKE
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The bsum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -B
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -L
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -l \ \fIbits\fP
+Version select: 224, 256, 384, or 512 for
+BLAKE-224 (default), BLAKE-256, BLAKE-384, or
+BLAKE-512, respectively.
+.TP
+.BR -S \ \fIsalt\fP
+If
+.I bits
+(the
+.B -l
+option) is 224, 256 or unspecified:
+16-byte salt, encoded as a 32 character long
+hexadecimal string.
+
+Otherwise:
+32-byte salt, encoded as a 64 character long
+hexadecimal string.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.B -U
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/calculate.c b/calculate.c
deleted file mode 100644
index 69181dd..0000000
--- a/calculate.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-static void
-process(struct algorithm *algorithm, struct global_data *global)
-{
- size_t r;
- r = algorithm->hasher.process(&algorithm->hasher,
- &global->buffer->buf[algorithm->offset],
- global->buffer->length - algorithm->offset);
- algorithm->offset += r;
-}
-
-
-static void
-finalise(struct algorithm *algorithm, struct global_data *global)
-{
- if (algorithm->hasher.finalise_const(&algorithm->hasher, &global->buffer->buf[algorithm->offset],
- global->buffer->length - algorithm->offset, 0))
- abort();
- format_result(algorithm, global->file, global->format);
-}
-
-
-int
-calculate(const char *file, struct barrier_group *group, struct global_data *global)
-{
- int fd, is_new_fd, r, ret = -1;
- const char *fname;
-
- global->nalgorithms = inithashers(global->algorithms, global->nalgorithms);
- if (!global->nalgorithms)
- return 0;
-
- fd = openfile(file, &is_new_fd, &fname);
- if (fd < 0)
- return -1;
-
- global->buffer->length = 0;
- while (!(r = feedbuffer(fd, global->buffer, fname))) {
- barriersend(group, global, &process);
- shiftbuffer(global->algorithms, global->nalgorithms, global->buffer);
- }
- if (r < 0)
- goto fail;
-
- barriersend(group, global, &finalise);
- ret = 0;
-fail:
- destroyhashers(global->algorithms, global->nalgorithms);
- if (is_new_fd)
- close(fd);
- return ret;
-}
diff --git a/check.c b/check.c
new file mode 100644
index 0000000..d014d65
--- /dev/null
+++ b/check.c
@@ -0,0 +1,282 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+union str_or_off {
+ const char *s;
+ size_t off;
+};
+
+struct listing {
+ union str_or_off algorithm;
+ union str_or_off filename; /* first char determines mode */
+ union str_or_off checksum;
+};
+
+
+static int
+listingcmp(const void *av, const void *bv)
+{
+ const struct listing *a = av, *b = bv;
+ int r = strcmp(a->filename.s, b->filename.s);
+ if (r)
+ return r;
+ return strcmp(a->algorithm.s, b->algorithm.s);
+}
+
+
+static int
+parse_listing(struct listing **listingp, size_t *listing_lenp, size_t *listing_sizep,
+ struct buffer *buffer, const char *fname, int warn_improper_format, enum format format)
+{
+ size_t lineno = 1U;
+ char end = (format & WITH_NUL) ? '\0' : '\n';
+
+ for (; buffer->procoff < buffer->offset; lineno++) {
+ for (; buffer->procoff < buffer->offset; buffer->procoff++)
+ if (buffer->buf[buffer->procoff] == end)
+ break;
+ if (buffer->procoff == buffer->offset) {
+ weprintf("last line in \"%s\" is not terminated", fname);
+ if (!warn_improper_format)
+ return -1;
+ if (buffer->offset == buffer->size)
+ buffer->buf = erealloc(buffer->buf, buffer->size += 1U);
+ }
+ buffer->buf[buffer->procoff++] = '\0';
+
+ if (*listing_lenp == *listing_sizep)
+ *listingp = ereallocarray(*listingp, *listing_sizep += 512U, sizeof(**listingp));
+
+ (*listingp)[*listing_lenp].algorithm.off = buffer->ready;
+ if (format & WITH_ALGOSTR) {
+ for (; buffer->buf[buffer->ready] != ':'; buffer->ready++)
+ if (isspace(buffer->buf[buffer->ready]) || !buffer->buf[buffer->ready])
+ goto badline;
+ buffer->buf[buffer->ready++] = '\0';
+ }
+
+ (*listingp)[*listing_lenp].checksum.off = buffer->ready;
+ for (; isxdigit(buffer->buf[buffer->ready]); buffer->ready++)
+ buffer->buf[buffer->ready] = (char)tolower(buffer->buf[buffer->ready]);
+ if (buffer->buf[buffer->ready] != ' ')
+ goto badline;
+ buffer->buf[buffer->ready++] = '\0';
+
+ if (buffer->buf[buffer->ready] != ' ' &&
+ buffer->buf[buffer->ready] != '*')
+ goto badline;
+ if (buffer->buf[buffer->ready] == '*')
+ buffer->buf[buffer->ready] = ' '; /* binary is insignificant */
+ (*listingp)[*listing_lenp].filename.off = buffer->ready;
+
+ if (!buffer->buf[(*listingp)[*listing_lenp].algorithm.off] ||
+ !buffer->buf[(*listingp)[*listing_lenp].checksum.off] ||
+ !buffer->buf[(*listingp)[*listing_lenp].filename.off + 1U])
+ goto badline;
+
+ *listing_lenp += 1U;
+nextline:
+ buffer->ready = buffer->procoff;
+ }
+
+ return 0;
+
+badline:
+ weprintf("line %zu in \"%s\" is improperly formatted", lineno, fname);
+ if (warn_improper_format)
+ goto nextline;
+ return -1;
+}
+
+
+static int
+get_listing(char **files, struct listing **listingp, size_t *listing_lenp, size_t *listing_sizep,
+ struct buffer *buffer, struct algorithm *algorithms, size_t nalgorithms,
+ enum format format, int warn_improper_format)
+{
+ const char *fname;
+ int r, fd, is_new_fd;
+ size_t i;
+
+ format &= (enum format)~FORMAT_MASK;
+ format |= LOWERCASE_HEX;
+
+ buffer->procoff = 0;
+ for (; *files; files++) {
+ fd = openfile(*files, &is_new_fd, &fname);
+ if (fd < 0)
+ return -1;
+
+ while (!(r = feedbuffer(fd, buffer, fname)));
+ if (r < 0)
+ goto fail;
+
+ if (is_new_fd) {
+ close(fd);
+ is_new_fd = 0;
+ }
+
+ if (parse_listing(listingp, listing_lenp, listing_sizep, buffer,
+ fname, warn_improper_format, format))
+ goto fail;
+ }
+
+ for (i = 0; i < *listing_lenp; i++) {
+ (*listingp)[i].algorithm.s = &buffer->buf[(*listingp)[i].algorithm.off];
+ (*listingp)[i].filename.s = &buffer->buf[(*listingp)[i].filename.off];
+ (*listingp)[i].checksum.s = &buffer->buf[(*listingp)[i].checksum.off];
+ }
+ if (!(format & WITH_ALGOSTR)) {
+ if (nalgorithms != 1U)
+ abort();
+ for (i = 0; i < *listing_lenp; i++)
+ (*listingp)[i].algorithm.s = algorithms[0].algostr;
+ }
+
+ return 0;
+
+fail:
+ if (is_new_fd)
+ close(fd);
+ return -1;
+}
+
+
+static int
+compare(const char *hash, size_t hash_len, const struct listing *listing, size_t nlisting, int *truncated_out)
+{
+ int truncated, ok = 0;
+ size_t len;
+ *truncated_out = 0;
+ for (; nlisting--; listing++) {
+ len = strlen(listing->checksum.s);
+ truncated = len < hash_len;
+ len = MIN(hash_len, len);
+ if (!strncmp(hash, listing->checksum.s, len)) {
+ ok = 1;
+ if (!truncated)
+ return 1;
+ }
+ }
+ *truncated_out = 1;
+ return ok;
+}
+
+
+static int
+check_file(struct listing *listing, size_t nlisting, size_t nthreads, struct global_data *global,
+ struct barrier_group *group, size_t *group_size)
+{
+ size_t i, j, n, orig_count, nthreads_cur, nthreads_now;
+ int cmp, truncated;
+
+ memset(global->algorithms, 0, nlisting * sizeof(*global->algorithms));
+ global->algorithms[0].algostr = listing[0].algorithm.s;
+ global->algorithms[0].result = NULL;
+ global->nalgorithms = 1U;
+ for (i = 1U; i < nlisting; i++) {
+ if (!strcmp(listing[i].algorithm.s, listing[i - 1U].algorithm.s)) {
+ listing[i].algorithm.s = listing[i - 1U].algorithm.s;
+ } else {
+ global->algorithms[global->nalgorithms].algostr = listing[i].algorithm.s;
+ global->algorithms[global->nalgorithms].result = NULL;
+ global->nalgorithms++;
+ }
+ }
+
+ nthreads_now = nthreads ? nthreads : getautonthreads();
+ nthreads_cur = MAX(MIN(global->nalgorithms, nthreads_now), 1U);
+ if (nthreads_cur > *group_size) {
+ if (*group_size)
+ killbarriergroup(group, global);
+ createbarriergroup(group, nthreads_cur, global);
+ }
+
+ orig_count = global->nalgorithms;
+ if (calculate(global->file, group, global)) {
+ printf("%s: %s\n", global->file, errno == ENOENT ? "Missing" : "Error");
+ return errno == ENOENT ? 1 : 2;
+ }
+
+ for (i = 0, j = 0; i < global->nalgorithms; i++, j += n) {
+ n = 1U;
+ for (; n < j - nlisting; n++)
+ if (listing[j].algorithm.s != listing[j + n].algorithm.s)
+ break;
+ cmp = strcmp(global->algorithms[0].algostr, listing[j].algorithm.s);
+ if (cmp < 0)
+ abort();
+ else if (cmp > 0)
+ continue;
+ if (compare(global->algorithms[0].result, global->algorithms[0].result_length, &listing[j], n, &truncated)) {
+ printf("%s: OK%s\n", global->file, truncated ? " (calculated hash was shorted the listed checksum)" : "");
+ return 0;
+ }
+ }
+
+ if (global->nalgorithms == orig_count) {
+ printf("%s: Fail\n", global->file);
+ return 1;
+ } else if (global->nalgorithms) {
+ printf("%s: Fail (some hash functions were not supported)\n", global->file);
+ return 2;
+ } else {
+ printf("%s: Fail (no hash function was supported)\n", global->file);
+ return 2;
+ }
+}
+
+
+int
+verify_checksums(char **files, struct algorithm *algorithms, size_t nalgorithms, size_t nthreads,
+ enum format format, int warn_improper_format, int hexinput)
+{
+ struct listing *listing = NULL;
+ size_t listing_len = 0;
+ size_t listing_size = 0;
+ struct buffer listbuffer = {0};
+ struct buffer filebuffer = {0};
+ size_t i, first, n;
+ int r, ret = 0;
+ struct global_data global;
+ size_t algorithms_size = 0;
+ struct barrier_group group;
+ size_t group_size = 0;
+
+ if (get_listing(files, &listing, &listing_len, &listing_size, &listbuffer,
+ algorithms, nalgorithms, format, warn_improper_format))
+ goto fail;
+ qsort(listing, listing_len, sizeof(*listing), &listingcmp);
+
+ global.algorithms = NULL;
+ global.buffer = &filebuffer;
+ for (i = 0; i < listing_len;) {
+ first = i++;
+ while (i < listing_len && !strcmp(listing[i].filename.s, listing[first].filename.s))
+ i++;
+ n = i - first;
+ if (n > algorithms_size) {
+ algorithms_size = n;
+ global.algorithms = ereallocarray(global.algorithms, n, sizeof(*global.algorithms));
+ }
+ global.file = &listing[i].filename.s[1];
+ global.hexinput = (hexinput || listing[i].filename.s[0] == '#');
+ r = check_file(&listing[i], n, nthreads, &global, &group, &group_size);
+ if (r < 0)
+ goto fail;
+ ret = MAX(r, ret);
+ }
+
+out:
+ if (group_size)
+ killbarriergroup(&group, &global);
+ free(listing);
+ free(listbuffer.buf);
+ free(filebuffer.buf);
+ return ret;
+
+fail:
+ ret = 2;
+ goto out;
+}
diff --git a/cmdline.c b/cmdline.c
new file mode 100644
index 0000000..182a29d
--- /dev/null
+++ b/cmdline.c
@@ -0,0 +1,84 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static enum command command = ANYSUM;
+static enum libhashsum_algorithm algorithm;
+
+
+#define USAGE_COMMON "[-c [-w]] [-W options] ... [-z] [file] ..."
+#define USAGE_BSUM "[-l bits] [-S salt] "USAGE_COMMON
+#define USAGE_SHA3SUM "[-a bits] "USAGE_COMMON
+#define USAGE_KECCAK "[-R rate] [-C capacity] [-N output-size] [-S state-size] [-W word-size] [-Z squeeze-count] "USAGE_COMMON
+#define USAGE_SHAKE "[-N output-bits] "USAGE_COMMON
+#define USAGE_RAWSHAKE "[-N output-bits] "USAGE_COMMON
+#define USAGE_ANYSUM "(-c [-w] | [-a algoritms] ... ) [-W options] ... [-z] [file] ..."
+
+#define static
+NUSAGE(libsimple_default_failure_exit,
+ (command == ANYSUM ? USAGE_ANYSUM :
+ command == BSUM ? USAGE_BSUM :
+ command == SHA3SUM ? USAGE_SHA3SUM :
+ (algorithm == LIBHASHSUM_BLAKE224 ||
+ algorithm == LIBHASHSUM_BLAKE256 ||
+ algorithm == LIBHASHSUM_BLAKE384 ||
+ algorithm == LIBHASHSUM_BLAKE512) ? USAGE_BSUM :
+ (algorithm == LIBHASHSUM_SHAKE128 ||
+ algorithm == LIBHASHSUM_SHAKE256 ||
+ algorithm == LIBHASHSUM_SHAKE512) ? USAGE_SHAKE :
+ (algorithm == LIBHASHSUM_RAWSHAKE128 ||
+ algorithm == LIBHASHSUM_RAWSHAKE256 ||
+ algorithm == LIBHASHSUM_RAWSHAKE512) ? USAGE_RAWSHAKE :
+ algorithm == LIBHASHSUM_KECCAK ? USAGE_KECCAK : USAGE_COMMON));
+#undef static
+
+
+void
+cmdline(int *argcp, char ***argvp, struct config *config)
+{
+ int old_argc = *argcp;
+ int argc = *argcp;
+ char **argv = *argvp;
+ const char *algostr = NULL;
+ char *algostrbuf = NULL;
+
+ argv0 = argv[0];
+ command = getcommand(&algostr, &algorithm);
+ switch (getsupercommand(command, algorithm)) {
+ case BSUM:
+ argc = cmdline_bsum(argc, argv, command, config, &algostr, &algorithm, &algostrbuf);
+ break;
+ case SHA3SUM:
+ argc = cmdline_sha3sum(argc, argv, command, config, &algostr, &algorithm, &algostrbuf);
+ break;
+ case ANYSUM:
+ case SPECIALISED:
+ default:
+ argc = cmdline_other(argc, argv, command, config);
+ break;
+ }
+
+ if (config->warn_improper_format > config->verify)
+ usage();
+
+ if (command == ANYSUM) {
+ if (config->verify && config->nalgorithms)
+ usage();
+ config->format |= WITH_ALGOSTR;
+ }
+ if (!config->verify) {
+ if ((config->format & FORMAT_MASK) == BINARY)
+ config->format &= FORMAT_MASK;
+ }
+
+ if (algostr) {
+ config->algorithms = erealloc(config->algorithms, sizeof(*config->algorithms));
+ (config->algorithms)[0].algostr = algostr;
+ config->nalgorithms = 1U;
+ }
+
+ *argcp = argc;
+ *argvp = &argv[old_argc - argc];
+
+ free(algostrbuf);
+}
diff --git a/cmdline_bsum.c b/cmdline_bsum.c
new file mode 100644
index 0000000..d267314
--- /dev/null
+++ b/cmdline_bsum.c
@@ -0,0 +1,102 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+cmdline_bsum(int argc, char **argv, enum command command, struct config *config,
+ const char **algostr, enum libhashsum_algorithm *algorithm, char **algostrbuf)
+{
+ const char *salt = NULL;
+ char *arg;
+
+ *algostrbuf = NULL;
+
+ ARGBEGIN {
+ case 'b': /* binary input (compat) */
+ case 't': /* text input (compat) */
+ config->hexinput = 0;
+ break;
+
+ case 'c':
+ config->verify = 1;
+ break;
+
+ case 'w':
+ config->warn_improper_format = 1;
+ break;
+
+ case 'z':
+ config->format &= (enum format)~WITH_LF;
+ config->format |= WITH_NUL;
+ break;
+
+ case 'l':
+ if (command != BSUM)
+ usage();
+ arg = ARG();
+ if (!strcmp(arg, "224")) *algostr = "blake224", *algorithm = LIBHASHSUM_BLAKE224;
+ else if (!strcmp(arg, "256")) *algostr = "blake256", *algorithm = LIBHASHSUM_BLAKE256;
+ else if (!strcmp(arg, "384")) *algostr = "blake384", *algorithm = LIBHASHSUM_BLAKE384;
+ else if (!strcmp(arg, "512")) *algostr = "blake512", *algorithm = LIBHASHSUM_BLAKE512;
+ else
+ eprintf("unsupport value on -l option, expected 224, 256, 384, or 512");
+ break;
+
+ case 'S':
+ if (salt)
+ usage();
+ arg = ARG();
+ if (!strncasecmp(arg, "0x", 2))
+ arg = &arg[2];
+ if (!*arg)
+ usage();
+ salt = arg;
+ while (isxdigit(*arg))
+ arg++;
+ if (!*arg)
+ eprintf("expected hexadecimal value for -S option");
+ break;
+
+ case 'x': /* (compat) */
+ config->hexinput = 1;
+ break;
+
+ case 'L': /* (compat) */
+ config->format &= (enum format)~FORMAT_MASK;
+ config->format |= LOWERCASE_HEX;
+ break;
+
+ case 'U': /* (compat) */
+ config->format &= (enum format)~FORMAT_MASK;
+ config->format |= UPPERCASE_HEX;
+ break;
+
+ case 'B': /* (compat) */
+ config->format &= (enum format)~FORMAT_MASK;
+ config->format |= BINARY;
+ break;
+
+ case 'W':
+ arg = parseopts(config, ARG(), &parseopt_vendor);
+ if (*arg)
+ eprintf("unsupported -W options: %s", arg);
+ break;
+
+ default:
+ usage();
+ } ARGEND;
+
+ if (salt) {
+ size_t expected_salt_len = 64; /* BLAKEb */
+ if (*algorithm == LIBHASHSUM_BLAKE224 || *algorithm == LIBHASHSUM_BLAKE256)
+ expected_salt_len = 32; /* BLAKEs */
+ if (strlen(salt) != expected_salt_len)
+ eprintf("salt for BLAKE%s is expected to be %zu hexadecimal characters long",
+ &(*algostr)[5], expected_salt_len);
+ *algostrbuf = malloc(strlen(*algostr) + strlen(salt) + sizeof("[salt=]"));
+ sprintf(*algostrbuf, "%s[salt=%s]", *algostr, salt);
+ *algostr = *algostrbuf;
+ }
+
+ return argc;
+}
diff --git a/cmdline_other.c b/cmdline_other.c
new file mode 100644
index 0000000..167bc84
--- /dev/null
+++ b/cmdline_other.c
@@ -0,0 +1,60 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static int
+parseopt_algorithm(void *config_, char *opt, char *val)
+{
+ struct config *config = config_;
+ if (val)
+ return 0;
+ config->algorithms = ereallocarray(config->algorithms, config->nalgorithms + 1U, sizeof(*config->algorithms));
+ memset(&config->algorithms[config->nalgorithms], 0, sizeof(*config->algorithms));
+ config->algorithms[config->nalgorithms].algostr = opt;
+ config->algorithms[config->nalgorithms].result = NULL;
+ config->nalgorithms++;
+ return 1;
+}
+
+
+int
+cmdline_other(int argc, char **argv, enum command command, struct config *config)
+{
+ char *arg;
+
+ ARGBEGIN {
+ case 'b': /* binary input (compat) */
+ case 't': /* text input (compat) */
+ config->hexinput = 0;
+ break;
+
+ case 'c':
+ config->verify = 1;
+ break;
+
+ case 'w':
+ config->warn_improper_format = 1;
+ break;
+
+ case 'z':
+ config->format &= (enum format)~WITH_LF;
+ config->format |= WITH_NUL;
+ break;
+
+ case 'W':
+ arg = parseopts(config, ARG(), &parseopt_algorithm);
+ if (*arg)
+ eprintf("unsupported -W options: %s", arg);
+ break;
+
+ case 'a':
+ if (command != ANYSUM || *parseopts(config, ARG(), &parseopt_algorithm))
+ usage();
+ break;
+
+ default:
+ usage();
+ } ARGEND;
+
+ return argc;
+}
diff --git a/cmdline_sha3sum.c b/cmdline_sha3sum.c
new file mode 100644
index 0000000..8fc33fd
--- /dev/null
+++ b/cmdline_sha3sum.c
@@ -0,0 +1,321 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifdef SUPPORT_SHA3
+#include <libkeccak.h>
+#endif
+
+
+static void
+intopt(long int *valp, char flag, const char *arg)
+{
+ if (*valp)
+ usage();
+ if (!isdigit(*arg))
+ goto invalid;
+ for (; isdigit(*arg); arg++) {
+ if (*valp > (LONG_MAX - (*arg & 15)) / 10)
+ goto invalid;
+ *valp = *valp * 10 + (*arg & 15);
+ }
+ if (*arg || !*valp) {
+ invalid:
+ eprintf("invalid value for -%c option, expected integer within [1, %li]", flag, LONG_MAX);
+ }
+}
+
+
+static char *
+fmtalgostr(const char *f, long int r, long int c, long int n, long int z)
+{
+ char *ret, *p;
+ int len;
+ len = snprintf(NULL, 0, "%s[r=%li,c=%li,n=%li,z=%li]", f, r, c, n, z);
+ if (len <= 0)
+ abort();
+ ret = emalloc((size_t)len);
+ p = stpcpy(ret, f);
+ *p++ = '[';
+ if (r)
+ p += sprintf(p, "r=%li%s", r, (c | n | z) ? "," : "");
+ if (c)
+ p += sprintf(p, "c=%li%s", c, (n | z) ? "," : "");
+ if (n)
+ p += sprintf(p, "n=%li%s", n, z ? "," : "");
+ if (z)
+ p += sprintf(p, "z=%li", z);
+ *p++ = ']';
+ *p = '\0';
+ return ret;
+}
+
+
+int
+cmdline_sha3sum(int argc, char **argv, enum command command, struct config *config,
+ const char **algostr, enum libhashsum_algorithm *algorithm, char **algostrbuf)
+{
+ long int r = 0, c = 0, n = 0, s = 0, w = 0, z = 0, bits;
+ char *arg, *p;
+ int verbose = 0;
+#ifdef SUPPORT_SHA3
+ struct libkeccak_generalised_spec gspec;
+ struct libkeccak_spec spec;
+ const char *suffix;
+#endif
+
+ *algostrbuf = NULL;
+
+ ARGBEGIN {
+ case 'c':
+ config->verify = 1;
+ break;
+
+ case 'w':
+ config->warn_improper_format = 1;
+ break;
+
+ case 'z':
+ config->format &= (enum format)~WITH_LF;
+ config->format |= WITH_NUL;
+ break;
+
+ case 'a':
+ if (command != SHA3SUM)
+ usage();
+ arg = ARG();
+ if (!strcmp(arg, "224")) *algostr = "sha3-224", *algorithm = LIBHASHSUM_SHA3_224;
+ else if (!strcmp(arg, "256")) *algostr = "sha3-256", *algorithm = LIBHASHSUM_SHA3_256;
+ else if (!strcmp(arg, "384")) *algostr = "sha3-384", *algorithm = LIBHASHSUM_SHA3_384;
+ else if (!strcmp(arg, "512")) *algostr = "sha3-512", *algorithm = LIBHASHSUM_SHA3_512;
+ else
+ eprintf("unsupport value on -a option, expected 224, 256, 384, or 512");
+ break;
+
+ case 'b': /* (compat) */
+ config->format &= (enum format)~FORMAT_MASK;
+ config->format |= BINARY;
+ break;
+
+ case 'l': /* (compat) */
+ config->format &= (enum format)~FORMAT_MASK;
+ config->format |= LOWERCASE_HEX;
+ break;
+
+ case 'u': /* (compat) */
+ config->format &= (enum format)~FORMAT_MASK;
+ config->format |= UPPERCASE_HEX;
+ break;
+
+ case 'x': /* (compat) */
+ config->hexinput = 1;
+ break;
+
+ case 'v': /* (compat) */
+ verbose = 1;
+ break;
+
+ case 'R':
+ intopt(&r, FLAG(), ARG());
+ break;
+
+ case 'C':
+ intopt(&c, FLAG(), ARG());
+ break;
+
+ case 'N':
+ case 'O': /* (compat) */
+ intopt(&n, FLAG(), ARG());
+ break;
+
+ case 'S':
+ case 'B': /* (compat) */
+ intopt(&s, FLAG(), ARG());
+ break;
+
+ case 'Z':
+ intopt(&z, FLAG(), ARG());
+ break;
+
+ case 'W':
+ p = arg = ARG();
+ while (isdigit(*p))
+ p++;
+ if (*arg && !*p) {
+ intopt(&w, FLAG(), arg);
+ } else {
+ arg = parseopts(config, arg, &parseopt_vendor);
+ if (*arg)
+ eprintf("unsupported -W options: %s", arg);
+ }
+ break;
+
+ default:
+ usage();
+ } ARGEND;
+
+#ifdef SUPPORT_SHA3
+ libkeccak_generalised_spec_initialise(&gspec);
+#endif
+
+ switch (*algorithm) {
+ case LIBHASHSUM_KECCAK:
+#ifdef SUPPORT_SHA3
+ suffix = "";
+#endif
+ break;
+ case LIBHASHSUM_KECCAK_224: bits = 224; goto spec_keccak;
+ case LIBHASHSUM_KECCAK_256: bits = 256; goto spec_keccak;
+ case LIBHASHSUM_KECCAK_384: bits = 384; goto spec_keccak;
+ case LIBHASHSUM_KECCAK_512: bits = 512; spec_keccak:
+ if (r | c | n | s | w | z)
+ usage();
+#ifdef SUPPORT_SHA3
+ libkeccak_spec_sha3((struct libkeccak_spec *)&gspec, bits);
+ suffix = "";
+#endif
+ break;
+ case LIBHASHSUM_SHA3_224: bits = 224; goto spec_sha3;
+ case LIBHASHSUM_SHA3_256: bits = 256; goto spec_sha3;
+ case LIBHASHSUM_SHA3_384: bits = 384; goto spec_sha3;
+ case LIBHASHSUM_SHA3_512: bits = 512; spec_sha3:
+ if (r | c | n | s | w | z)
+ usage();
+#ifdef SUPPORT_SHA3
+ libkeccak_spec_sha3((struct libkeccak_spec *)&gspec, bits);
+ suffix = LIBKECCAK_SHA3_SUFFIX;
+#endif
+ break;
+ case LIBHASHSUM_SHAKE128: bits = 128; goto spec_shake;
+ case LIBHASHSUM_SHAKE256: bits = 256; goto spec_shake;
+ case LIBHASHSUM_SHAKE512: bits = 512; spec_shake:
+ if (r | c | s | w | z)
+ usage();
+#ifdef SUPPORT_SHA3
+ libkeccak_spec_shake((struct libkeccak_spec *)&gspec, bits, bits);
+ suffix = LIBKECCAK_SHAKE_SUFFIX;
+#endif
+ break;
+ case LIBHASHSUM_RAWSHAKE128: bits = 128; goto spec_rawshake;
+ case LIBHASHSUM_RAWSHAKE256: bits = 256; goto spec_rawshake;
+ case LIBHASHSUM_RAWSHAKE512: bits = 512; spec_rawshake:
+ if (r | c | s | w | z)
+ usage();
+#ifdef SUPPORT_SHA3
+ libkeccak_spec_rawshake((struct libkeccak_spec *)&gspec, bits, bits);
+ suffix = LIBKECCAK_RAWSHAKE_SUFFIX;
+#endif
+ break;
+ default:
+ case LIBHASHSUM_MD2:
+ case LIBHASHSUM_MD4:
+ case LIBHASHSUM_MD5:
+ case LIBHASHSUM_RIPEMD_128:
+ case LIBHASHSUM_RIPEMD_160:
+ case LIBHASHSUM_RIPEMD_256:
+ case LIBHASHSUM_RIPEMD_320:
+ case LIBHASHSUM_SHA0:
+ case LIBHASHSUM_SHA1:
+ case LIBHASHSUM_SHA_224:
+ case LIBHASHSUM_SHA_256:
+ case LIBHASHSUM_SHA_384:
+ case LIBHASHSUM_SHA_512:
+ case LIBHASHSUM_SHA_512_224:
+ case LIBHASHSUM_SHA_512_256:
+ case LIBHASHSUM_BLAKE224:
+ case LIBHASHSUM_BLAKE256:
+ case LIBHASHSUM_BLAKE384:
+ case LIBHASHSUM_BLAKE512:
+ abort();
+ }
+
+ z = z ? z : 1U;
+
+#ifdef SUPPORT_SHA3
+ gspec.bitrate = r ? r : gspec.bitrate;
+ gspec.capacity = c ? c : gspec.capacity;
+ gspec.output = n ? n : gspec.output;
+ gspec.state_size = s ? s : gspec.state_size;
+ gspec.word_size = w ? w : gspec.word_size;
+
+# define CASE(N, S) case LIBKECCAK_GENERALISED_SPEC_ERROR_##N: eprintf("%s", S)
+ switch (libkeccak_degeneralise_spec(&gspec, &spec)) {
+ case 0:
+ break;
+ CASE(STATE_NONPOSITIVE, "the state size must be positive");
+ CASE(STATE_TOO_LARGE, "the state size is too large, may not exceed 1600");
+ CASE(STATE_MOD_25, "the state size must be a multiple of 25");
+ CASE(WORD_NONPOSITIVE, "the word size must be positive");
+ CASE(WORD_TOO_LARGE, "the word size is too large, may not exceed 64");
+ CASE(STATE_WORD_INCOHERENCY, "the state size must be exactly 25 times the word size");
+ CASE(CAPACITY_NONPOSITIVE, "the capacity must be positive");
+ CASE(CAPACITY_MOD_8, "the capacity must be a multiple of 8");
+ CASE(BITRATE_NONPOSITIVE, "the rate must be positive");
+ CASE(BITRATE_MOD_8, "the rate must be a multiple of 8");
+ CASE(OUTPUT_NONPOSITIVE, "the output size must be positive");
+ CASE(STATE_BITRATE_CAPACITY_INCONSISTENCY, "the sum of the rate and capacity must equal"
+ " the state size (25 times the word size)");
+ default:
+ eprintf("unknown error in algorithm parameters");
+ }
+# undef CASE
+
+# define CASE(N, S) case LIBKECCAK_SPEC_ERROR_##N: eprintf("%s", S)
+ switch (libkeccak_spec_check(&spec)) {
+ case 0:
+ break;
+ CASE(BITRATE_NONPOSITIVE, "the rate size must be positive");
+ CASE(BITRATE_MOD_8, "the rate must be a multiple of 8");
+ CASE(CAPACITY_NONPOSITIVE, "the capacity must be positive");
+ CASE(CAPACITY_MOD_8, "the capacity must be a multiple of 8");
+ CASE(OUTPUT_NONPOSITIVE, "the output size must be positive");
+ CASE(STATE_TOO_LARGE, "the state size is too large, may not exceed 1600");
+ CASE(STATE_MOD_25, "the state size must be a multiple of 25");
+ CASE(WORD_NON_2_POTENT, "the word size must be a power of 2");
+ CASE(WORD_MOD_8, "the word size must be a multiple of 8");
+ default:
+ eprintf("unknown error in algorithm parameters");
+ }
+# undef TEST
+
+ if (verbose) {
+ fprintf(stderr, "rate: %li\n", gspec.bitrate);
+ fprintf(stderr, "capacity: %li\n", gspec.capacity);
+ fprintf(stderr, "output size: %li\n", gspec.output);
+ fprintf(stderr, "state size: %li\n", gspec.state_size);
+ fprintf(stderr, "word size: %li\n", gspec.word_size);
+ fprintf(stderr, "squeezes: %li\n", z);
+ fprintf(stderr, "suffix: %s\n", suffix);
+ }
+#else
+ (void) verbose;
+#endif
+
+ if (*algorithm == LIBHASHSUM_KECCAK && !s && !w)
+ *algostr = *algostrbuf = fmtalgostr(*algostr, r, c, n, z);
+
+#ifdef SUPPORT_SHA3
+ r = spec.bitrate;
+ c = spec.capacity;
+ n = spec.output;
+#else
+ if (w && !s)
+ s = w * 25;
+ if (!!r + !!c == 2 && !s) {
+ n = n ? n : MAX(c * 2, 8);
+ } else if (!!r + !!c == 1) {
+ c = c ? c : (s ? s : 1600) - r;
+ r = r ? r : (s ? s : 1600) - c;
+ n = n ? n : MAX(c * 2, 8);
+ } else {
+ c = (s ? s : 1600) * 9 / 25;
+ r = (s ? s : 1600) - c;
+ n = n ? n : MAX(r / 2, 8);
+ }
+#endif
+
+ if (*algorithm == LIBHASHSUM_KECCAK && (s || w))
+ *algostr = *algostrbuf = fmtalgostr(*algostr, r, c, n, z);
+ else if (*algorithm != LIBHASHSUM_KECCAK && n != bits)
+ *algostr = *algostrbuf = fmtalgostr(*algostr, 0, 0, n, 0);
+
+ return argc;
+}
diff --git a/command.c b/command.c
new file mode 100644
index 0000000..d280766
--- /dev/null
+++ b/command.c
@@ -0,0 +1,101 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+enum command
+getcommand(const char **name_out, enum libhashsum_algorithm *algorithm_out)
+{
+ const char *name, *p;
+
+ name = strrchr(argv0, '/');
+ name = name ? &name[1] : argv0;
+
+ if (strstarts(name, "anysum")) {
+ name = &name[6];
+ while (isdigit(*name) || *name == '.' || *name == '_')
+ name++;
+ if (*name++ != '-')
+ return ANYSUM;
+ }
+
+ if (strcasestarts(name, "sha")) {
+ p = &name[3];
+ if (*p == '-')
+ p++;
+ if (*p++ == '3') {
+ if (!*p || !strcasecmp(p, "sum")) {
+ *algorithm_out = LIBHASHSUM_SHA3_224;
+ return SHA3SUM;
+ }
+ }
+ }
+
+ p = name;
+ if (*p != 'b' && *p != 'B')
+ goto specialised;
+ if (!strncasecmp(++p, "lake", 4))
+ p = &p[4];
+ if (*p && strcasecmp(p, "sum"))
+ goto specialised;
+ *name_out = "blake224";
+ *algorithm_out = LIBHASHSUM_BLAKE224;
+ return BSUM;
+
+specialised:
+ if (!libhashsum_get_algorithm_string(algorithm_out, name))
+ eprintf("invalid command name, is not \"anysum\" and "
+ "does not match any known hash function");
+ if (strchr(name, '['))
+ eprintf("invalid command name, cannot contain parameters");
+ *name_out = name;
+ return SPECIALISED;
+}
+
+
+enum command
+getsupercommand(enum command cmd, enum libhashsum_algorithm algo)
+{
+ if (cmd != SPECIALISED)
+ return cmd;
+ switch (algo) {
+ case LIBHASHSUM_MD2:
+ case LIBHASHSUM_MD4:
+ case LIBHASHSUM_MD5:
+ case LIBHASHSUM_RIPEMD_128:
+ case LIBHASHSUM_RIPEMD_160:
+ case LIBHASHSUM_RIPEMD_256:
+ case LIBHASHSUM_RIPEMD_320:
+ case LIBHASHSUM_SHA0:
+ case LIBHASHSUM_SHA1:
+ case LIBHASHSUM_SHA_224:
+ case LIBHASHSUM_SHA_256:
+ case LIBHASHSUM_SHA_384:
+ case LIBHASHSUM_SHA_512:
+ case LIBHASHSUM_SHA_512_224:
+ case LIBHASHSUM_SHA_512_256:
+ return SPECIALISED;
+ case LIBHASHSUM_KECCAK:
+ case LIBHASHSUM_KECCAK_224:
+ case LIBHASHSUM_KECCAK_256:
+ case LIBHASHSUM_KECCAK_384:
+ case LIBHASHSUM_KECCAK_512:
+ case LIBHASHSUM_SHA3_224:
+ case LIBHASHSUM_SHA3_256:
+ case LIBHASHSUM_SHA3_384:
+ case LIBHASHSUM_SHA3_512:
+ case LIBHASHSUM_SHAKE128:
+ case LIBHASHSUM_SHAKE256:
+ case LIBHASHSUM_SHAKE512:
+ case LIBHASHSUM_RAWSHAKE128:
+ case LIBHASHSUM_RAWSHAKE256:
+ case LIBHASHSUM_RAWSHAKE512:
+ return SHA3SUM;
+ case LIBHASHSUM_BLAKE224:
+ case LIBHASHSUM_BLAKE256:
+ case LIBHASHSUM_BLAKE384:
+ case LIBHASHSUM_BLAKE512:
+ return BSUM;
+ default:
+ eprintf("algorithm not recognised");
+ }
+}
diff --git a/common.h b/common.h
index af153b9..a228fbd 100644
--- a/common.h
+++ b/common.h
@@ -1,11 +1,24 @@
/* See LICENSE file for copyright and license details. */
-#include <libsimple.h>
#ifndef SINGLE_THREADED
# include <pthread.h>
#else
# define pthread_barrier_t PhonyBarrier
#endif
#include <libhashsum.h>
+#include <libsimple.h>
+#include <libsimple-arg.h>
+LIBSIMPLE_NORETURN__ void usage(void);
+
+
+#if defined(__clang__)
+# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
+# pragma clang diagnostic ignored "-Wcovered-switch-default"
+# pragma clang diagnostic ignored "-Wpadded"
+# pragma clang diagnostic ignored "-Wcomma"
+# pragma clang diagnostic ignored "-Wassign-enum"
+#elif defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
+#endif
struct thread_data;
@@ -19,6 +32,14 @@ typedef struct {
#endif
+enum command {
+ SPECIALISED,
+ ANYSUM,
+ SHA3SUM,
+ BSUM
+};
+
+
enum format {
BINARY = 0,
LOWERCASE_HEX = 1,
@@ -31,9 +52,23 @@ enum format {
};
+struct config {
+ enum format format;
+ int verify;
+ int warn_improper_format;
+ int hexinput;
+ int recursive;
+ struct algorithm *algorithms;
+ size_t nalgorithms;
+ size_t threads;
+};
+
+
struct buffer {
char *buf;
- size_t length;
+ size_t ready;
+ size_t procoff;
+ size_t offset;
size_t size;
};
@@ -51,6 +86,7 @@ struct algorithm {
struct global_data {
void (*action)(struct algorithm *, struct global_data *);
enum format format;
+ int hexinput;
const char *file;
struct buffer *buffer;
struct algorithm *algorithms;
@@ -75,17 +111,62 @@ struct thread_data {
};
-int patheq(const char *have, const char *want, const char **end_out);
-int openfile(const char *path, int *is_new_fd_out, const char **fname_out);
-char *hex(char *out, const unsigned char *in, size_t n, const char *xdigits);
-void writeall(int fd, const void *data, size_t n, const char *fname);
+/* get.c */
+int calculate_and_print_each(char **files, struct algorithm *algorithms, size_t nalgorithms,
+ size_t nthreads, enum format format, int hexinput, int recursive);
+
+/* check.c */
+int verify_checksums(char **files, struct algorithm *algorithms, size_t nalgorithms, size_t nthreads,
+ enum format format, int warn_improper_format, int hexinput);
+
+/* barrier.c */
void barrierwait(pthread_barrier_t *barrier);
-void barriersend(struct barrier_group *group, struct global_data *global, void (*action)(struct algorithm *, struct global_data *));
-void format_result(struct algorithm *algorithm, const char *file, enum format format);
-int feedbuffer(int fd, struct buffer *buffer, const char *fname);
+void barriersend(struct barrier_group *group, struct global_data *global,
+ void (*action)(struct algorithm *, struct global_data *));
void createbarriergroup(struct barrier_group *group_out, size_t count, struct global_data *global);
void killbarriergroup(struct barrier_group *group, struct global_data *global);
+
+/* hash.c */
size_t inithashers(struct algorithm *algorithms, size_t nalgorithms);
void destroyhashers(struct algorithm *algorithms, size_t nalgorithms);
-void shiftbuffer(struct algorithm *algorithms, size_t nalgorithms, struct buffer *buffer);
int calculate(const char *file, struct barrier_group *group, struct global_data *global);
+
+/* write.c */
+void writeall(int fd, const void *data, size_t n, const char *fname);
+char *hex(char *out, const unsigned char *in, size_t n, const char *xdigits);
+void format_result(struct algorithm *algorithm, const char *file, enum format format, int hexinput);
+
+/* open.c */
+int patheq(const char *have, const char *want, const char **end_out);
+int openfile(const char *path, int *is_new_fd_out, const char **fname_out);
+
+/* read.c */
+int feedbuffer(int fd, struct buffer *buffer, const char *fname);
+void shiftbuffer(struct algorithm *algorithms, size_t nalgorithms, struct buffer *buffer);
+int unhex(struct buffer *buffer);
+
+/* proc.c */
+size_t getnproc(size_t default_count);
+size_t getautonthreads(void);
+
+/* command.c */
+enum command getcommand(const char **name_out, enum libhashsum_algorithm *algorithm_out);
+enum command getsupercommand(enum command cmd, enum libhashsum_algorithm algo);
+
+/* opts.c */
+int parseopt_vendor(void /* (struct config) */ *config, char *opt, char *val);
+char *parseopts(void *config, char *string, int (*parseopt)(void *, char *opt, char *val));
+
+/* cmdline_bsum.c */
+int cmdline_bsum(int argc, char **argv, enum command command, struct config *config,
+ const char **algostr, enum libhashsum_algorithm *algorithm, char **algostrbuf);
+
+/* cmdline_sha3sum.c */
+int cmdline_sha3sum(int argc, char **argv, enum command command, struct config *config,
+ const char **algostr, enum libhashsum_algorithm *algorithm, char **algostrbuf);
+
+/* cmdline_other.c */
+int cmdline_other(int argc, char **argv, enum command command, struct config *config);
+
+/* cmdline.c */
+void cmdline(int *argcp, char ***argvp, struct config *config);
diff --git a/config.mk b/config.mk
index d746c19..a234217 100644
--- a/config.mk
+++ b/config.mk
@@ -72,3 +72,7 @@ SUPPORT_BLAKE384 = $(DEFAULT_SUPPORT)
SUPPORT_BLAKE512 = $(DEFAULT_SUPPORT)
# Requires libblake>=1.1
+
+
+# Uncomment if you don't want the aliases to anysum
+#ALIASES=
diff --git a/destroyhashers.c b/destroyhashers.c
deleted file mode 100644
index 0f05c03..0000000
--- a/destroyhashers.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-void
-destroyhashers(struct algorithm *algorithms, size_t nalgorithms)
-{
- size_t i;
- for (i = 0; i < nalgorithms; i++)
- if (algorithms[i].hasher.destroy)
- algorithms[i].hasher.destroy(&algorithms[i].hasher);
-}
diff --git a/feedbuffer.c b/feedbuffer.c
deleted file mode 100644
index 59ecae0..0000000
--- a/feedbuffer.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-int
-feedbuffer(int fd, struct buffer *buffer, const char *fname)
-{
- ssize_t r;
- if (buffer->length == buffer->size)
- buffer->buf = erealloc(buffer->buf, buffer->size += 8096);
-again:
- r = read(fd, &buffer->buf[buffer->length], buffer->size - buffer->length);
- if (r <= 0) {
- if (!r)
- return 1;
- if (errno == EINTR)
- goto again;
- weprintf("%s:", fname);
- return -1;
- }
- buffer->length += (size_t)r;
- return 0;
-}
diff --git a/get.c b/get.c
new file mode 100644
index 0000000..5758388
--- /dev/null
+++ b/get.c
@@ -0,0 +1,99 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+struct recursion_buffer {
+ char *buf;
+ size_t size;
+ size_t len;
+};
+
+
+static int
+calculate_and_print(const char *file, struct barrier_group *group, struct global_data *global, struct recursion_buffer *recbuf)
+{
+ struct dirent *f;
+ DIR *dir;
+ size_t i, len, old_len;
+
+ if (!recbuf)
+ goto as_file;
+ dir = opendir(file);
+ if (!dir)
+ goto as_file;
+ if (recbuf->size - recbuf->len < strlen(file) + 1U) {
+ recbuf->size = recbuf->len + strlen(file) + 1U;
+ recbuf->buf = erealloc(recbuf->buf, recbuf->size);
+ }
+ old_len = recbuf->len;
+ stpcpy(&recbuf->buf[recbuf->len], file);
+ recbuf->len += strlen(file);
+ if (recbuf->buf[recbuf->len - 1U] != '/')
+ recbuf->buf[recbuf->len++] = '/';
+ len = recbuf->len;
+ while ((errno = 0, f = readdir(dir))) {
+ if (recbuf->size - len < strlen(f->d_name) + 1U) {
+ recbuf->size = len + strlen(f->d_name) + 1U;
+ recbuf->buf = erealloc(recbuf->buf, recbuf->size);
+ }
+ stpcpy(&recbuf->buf[len], f->d_name);
+ if (calculate_and_print(recbuf->buf, group, global, recbuf))
+ goto recusion_error;
+ }
+ recbuf->len = old_len;
+ recbuf->buf[recbuf->len] = '\0';
+ if (errno) {
+ weprintf("%s:", file);
+ recusion_error:
+ closedir(dir);
+ return -1;
+ }
+ closedir(dir);
+ return 0;
+
+as_file:
+ global->file = file;
+ if (calculate(global->file, group, global))
+ return -1;
+ for (i = 0; i < global->nalgorithms; i++)
+ writeall(STDOUT_FILENO, global->algorithms[i].result, global->algorithms[i].result_length, "<stdout>");
+ return 0;
+}
+
+
+int
+calculate_and_print_each(char **files, struct algorithm *algorithms, size_t nalgorithms,
+ size_t nthreads, enum format format, int hexinput, int recursive)
+{
+ struct recursion_buffer recbuf = {NULL, 0, 0};
+ size_t wanted_nalgorithms = nalgorithms;
+ struct buffer buffer = {0};
+ struct barrier_group group;
+ struct global_data global;
+ int ret = 0;
+
+ global.format = format;
+ global.hexinput = hexinput;
+ global.buffer = &buffer;
+ global.algorithms = algorithms;
+ global.nalgorithms = nalgorithms;
+
+ if (!nthreads)
+ nthreads = getautonthreads();
+ nthreads = MAX(MIN(nalgorithms, nthreads), 1U);
+
+ createbarriergroup(&group, nthreads, &global);
+
+ for (; *files; files++)
+ if (calculate_and_print(*files, &group, &global, recursive ? &recbuf : NULL))
+ ret = 2;
+
+ if (global.nalgorithms != wanted_nalgorithms)
+ ret = 2;
+
+ killbarriergroup(&group, &global);
+
+ free(buffer.buf);
+ free(recbuf.buf);
+ return ret;
+}
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..0784c78
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,98 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+size_t
+inithashers(struct algorithm *algorithms, size_t nalgorithms)
+{
+ size_t i;
+ for (i = 0; i < nalgorithms;) {
+ if (libhashsum_init_hasher_from_string(&algorithms[i].hasher, algorithms[i].algostr)) {
+ weprintf("%s:", algorithms[i].algostr);
+ free(algorithms[i].result);
+ /* keep order */
+ memmove(&algorithms[i], &algorithms[i + 1U], (--nalgorithms - i) * sizeof(*algorithms));
+ } else {
+ algorithms[i].offset = 0;
+ i++;
+ }
+ }
+ return nalgorithms;
+}
+
+
+void
+destroyhashers(struct algorithm *algorithms, size_t nalgorithms)
+{
+ size_t i;
+ for (i = 0; i < nalgorithms; i++)
+ if (algorithms[i].hasher.destroy)
+ algorithms[i].hasher.destroy(&algorithms[i].hasher);
+}
+
+
+static void
+process(struct algorithm *algorithm, struct global_data *global)
+{
+ size_t r;
+ r = algorithm->hasher.process(&algorithm->hasher,
+ &global->buffer->buf[algorithm->offset],
+ global->buffer->ready - algorithm->offset);
+ algorithm->offset += r;
+}
+
+
+static void
+finalise(struct algorithm *algorithm, struct global_data *global)
+{
+ if (algorithm->hasher.finalise_const(&algorithm->hasher, &global->buffer->buf[algorithm->offset],
+ global->buffer->ready - algorithm->offset, 0))
+ abort();
+ format_result(algorithm, global->file, global->format, global->hexinput);
+}
+
+
+int
+calculate(const char *file, struct barrier_group *group, struct global_data *global)
+{
+ int fd, is_new_fd, r, ret = -1, saved_errno;
+ const char *fname;
+
+ global->nalgorithms = inithashers(global->algorithms, global->nalgorithms);
+ if (!global->nalgorithms)
+ return 0;
+
+ fd = openfile(file, &is_new_fd, &fname);
+ if (fd < 0)
+ return -1;
+
+ global->buffer->ready = 0;
+ global->buffer->procoff = 0;
+ global->buffer->offset = 0;
+ while (!(r = feedbuffer(fd, global->buffer, fname))) {
+ if (!global->hexinput) {
+ global->buffer->ready = global->buffer->offset;
+ global->buffer->procoff = global->buffer->offset;
+ } else {
+ if (unhex(global->buffer)) {
+ weprintf("%s: not a hexadecimal file", fname);
+ errno = 0;
+ goto fail;
+ }
+ }
+ barriersend(group, global, &process);
+ shiftbuffer(global->algorithms, global->nalgorithms, global->buffer);
+ }
+ if (r < 0)
+ goto fail;
+
+ barriersend(group, global, &finalise);
+ ret = 0;
+fail:
+ saved_errno = errno;
+ destroyhashers(global->algorithms, global->nalgorithms);
+ if (is_new_fd)
+ close(fd);
+ errno = saved_errno;
+ return ret;
+}
diff --git a/hex.c b/hex.c
deleted file mode 100644
index abb2ede..0000000
--- a/hex.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-char *
-hex(char *out, const unsigned char *in, size_t n, const char *xdigits)
-{
- for (; n--; in++) {
- *out++ = xdigits[(*in >> 4) & 15];
- *out++ = xdigits[(*in >> 0) & 15];
- }
- return out;
-}
diff --git a/inithashers.c b/inithashers.c
deleted file mode 100644
index ff2dbfd..0000000
--- a/inithashers.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-size_t
-inithashers(struct algorithm *algorithms, size_t nalgorithms)
-{
- size_t i;
- for (i = 0; i < nalgorithms;) {
- if (libhashsum_init_hasher_from_string(&algorithms[i].hasher, algorithms[i].algostr)) {
- weprintf("%s:", algorithms[i].algostr);
- free(algorithms[i].result);
- /* keep order */
- memmove(&algorithms[i], &algorithms[i + 1U], (--nalgorithms - i) * sizeof(*algorithms));
- } else {
- algorithms[i].offset = 0;
- i++;
- }
- }
- return nalgorithms;
-}
diff --git a/keccak224sum.1 b/keccak224sum.1
new file mode 100644
index 0000000..f1761e3
--- /dev/null
+++ b/keccak224sum.1
@@ -0,0 +1,209 @@
+.TH KECCAK224SUM 1 anysum
+.SH NAME
+keccak224sum - compute or verify against multiple Keccak-224 hashes
+
+.SH SYNOPSIS
+.B keccak224sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B keccak224sum
+utility calculates and prints or checks Keccak-224
+(Keccak[r=1152,c=448,n=224]) checksums.
+.PP
+The
+.B keccak224sum
+utility can also check a file against multiple Keccak-224
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The keccak224sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/keccak256sum.1 b/keccak256sum.1
new file mode 100644
index 0000000..e39bf56
--- /dev/null
+++ b/keccak256sum.1
@@ -0,0 +1,209 @@
+.TH KECCAK256SUM 1 anysum
+.SH NAME
+keccak256sum - compute or verify against multiple Keccak-256 hashes
+
+.SH SYNOPSIS
+.B keccak256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B keccak256sum
+utility calculates and prints or checks Keccak-256
+(Keccak[r=1088,c=512,n=256]) checksums.
+.PP
+The
+.B keccak256sum
+utility can also check a file against multiple Keccak-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The keccak256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/keccak384sum.1 b/keccak384sum.1
new file mode 100644
index 0000000..774ca03
--- /dev/null
+++ b/keccak384sum.1
@@ -0,0 +1,209 @@
+.TH KECCAK384SUM 1 anysum
+.SH NAME
+keccak384sum - compute or verify against multiple Keccak-384 hashes
+
+.SH SYNOPSIS
+.B keccak384sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B keccak384sum
+utility calculates and prints or checks Keccak-384
+(Keccak[r=832,c=768,n=384]) checksums.
+.PP
+The
+.B keccak384sum
+utility can also check a file against multiple Keccak-384
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The keccak384sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/keccak512sum.1 b/keccak512sum.1
new file mode 100644
index 0000000..4858004
--- /dev/null
+++ b/keccak512sum.1
@@ -0,0 +1,209 @@
+.TH KECCAK512SUM 1 anysum
+.SH NAME
+keccak512sum - compute or verify against multiple Keccak-512 hashes
+
+.SH SYNOPSIS
+.B keccak512sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B keccak512sum
+utility calculates and prints or checks Keccak-512
+(Keccak[r=576,c=1024,n=512]) checksums.
+.PP
+The
+.B keccak512sum
+utility can also check a file against multiple Keccak-512
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The keccak512sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/keccaksum.1 b/keccaksum.1
new file mode 100644
index 0000000..8b27314
--- /dev/null
+++ b/keccaksum.1
@@ -0,0 +1,241 @@
+.TH KECCAKSUM 1 anysum
+.SH NAME
+keccaksum - compute or verify against multiple Keccak hashes
+
+.SH SYNOPSIS
+.B keccaksum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -R
+.IR bitrate ]
+.RB [ -C
+.IR capacity ]
+.RB [ -N
+.IR hashsize ]
+.RB [ -S
+.IR statesize ]
+.RB [ -W
+.IR statesize ]
+.RB [ -Z
+.IR squeezes ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B keccaksum
+utility calculates and prints or checks Keccak
+(Keccak[r=1152,c=448,n=224]) checksums.
+.PP
+The
+.B keccaksum
+utility can also check a file against multiple Keccak
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The keccaksum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.BR -C \ \fIcapacity\fP
+The capacity, in bits, for the Keccak function.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N , -O \ \fIhashsize\fP
+The output size in bits.
+.TP
+.BR -R \ \fIbitrate\fP
+The bitrate for the Keccak function.
+.TP
+.BR -S , -B \ \fIstatesize\fP
+The state-size, in bits, for the Keccak function.
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIwordsize\fP
+The word-size, in bits, for the Keccak function.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.BR -Z \ \fIsqueeze\fP
+The number of squeezes to perform on at the end phase
+of the Keccak function (this changes the hash but not
+the length of the hash).
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/killbarriergroup.c b/killbarriergroup.c
deleted file mode 100644
index f83317e..0000000
--- a/killbarriergroup.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-void
-killbarriergroup(struct barrier_group *group, struct global_data *global)
-{
-#ifndef SINGLE_THREADED
- size_t i;
-
- if (!group->nthreads)
- return;
-
- global->action = NULL;
- for (i = 0; i < group->nthreads; i++)
- group->threads[i].global = global;
- barrierwait(&group->barrier);
-
- for (i = 0; i < group->nthreads; i++)
- if ((errno = pthread_join(group->threads[i].thread, NULL)))
- weprintf("pthread_join:");
- pthread_barrier_destroy(&group->barrier);
-
- free(group->threads);
-#else
- (void) group;
- (void) global;
-#endif
-}
diff --git a/md2sum.1 b/md2sum.1
new file mode 100644
index 0000000..6460c53
--- /dev/null
+++ b/md2sum.1
@@ -0,0 +1,203 @@
+.TH MD2SUM 1 anysum
+.SH NAME
+md2sum - compute or verify against multiple MD2 hashes
+
+.SH SYNOPSIS
+.B md2sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B md2sum
+utility calculates and prints or checks MD2 checksums.
+.PP
+The
+.B md2sum
+utility can also check a file against multiple MD2
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The md2sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+.PP
+Be advised that MD2 is partially compromised.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/md4sum.1 b/md4sum.1
new file mode 100644
index 0000000..7fb1ddb
--- /dev/null
+++ b/md4sum.1
@@ -0,0 +1,203 @@
+.TH MD4SUM 1 anysum
+.SH NAME
+md4sum - compute or verify against multiple MD4 hashes
+
+.SH SYNOPSIS
+.B md4sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B md4sum
+utility calculates and prints or checks MD4 checksums.
+.PP
+The
+.B md4sum
+utility can also check a file against multiple MD4
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The md4sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+.PP
+Be advised that MD4 is compromised.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/md5sum.1 b/md5sum.1
new file mode 100644
index 0000000..e342b7d
--- /dev/null
+++ b/md5sum.1
@@ -0,0 +1,203 @@
+.TH MD5SUM 1 anysum
+.SH NAME
+md5sum - compute or verify against multiple MD5 hashes
+
+.SH SYNOPSIS
+.B md5sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B md5sum
+utility calculates and prints or checks MD5 checksums.
+.PP
+The
+.B md5sum
+utility can also check a file against multiple MD5
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The md5sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+.PP
+Be advised that MD5 is compromised.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/mk/before-config.mk b/mk/before-config.mk
index c77dd47..cf000f5 100644
--- a/mk/before-config.mk
+++ b/mk/before-config.mk
@@ -19,3 +19,24 @@ SUPPORT_BLAKE224 = $(DEFAULT_SUPPORT)
SUPPORT_BLAKE256 = $(DEFAULT_SUPPORT)
SUPPORT_BLAKE384 = $(DEFAULT_SUPPORT)
SUPPORT_BLAKE512 = $(DEFAULT_SUPPORT)
+
+ALIASES =\
+ $(ALIASES_MD2)\
+ $(ALIASES_MD4)\
+ $(ALIASES_MD5)\
+ $(ALIASES_RIPEMD_128)\
+ $(ALIASES_RIPEMD_160)\
+ $(ALIASES_RIPEMD_256)\
+ $(ALIASES_RIPEMD_320)\
+ $(ALIASES_SHA0)\
+ $(ALIASES_SHA1)\
+ $(ALIASES_SHA2)\
+ $(ALIASES_SHA3)\
+ $(ALIASES_KECCAK)\
+ $(ALIASES_SHAKE)\
+ $(ALIASES_RAWSHAKE)\
+ $(ALIASES_BLAKE)\
+ $(ALIASES_BLAKE224)\
+ $(ALIASES_BLAKE256)\
+ $(ALIASES_BLAKE384)\
+ $(ALIASES_BLAKE512)
diff --git a/mk/blake224=yes.mk b/mk/blake224=yes.mk
index 765741c..246dda2 100644
--- a/mk/blake224=yes.mk
+++ b/mk/blake224=yes.mk
@@ -2,3 +2,6 @@ CPPFLAGS_BLAKE224 = -DSUPPORT_BLAKE224
CPPFLAGS_LIBBLAKE_IF_SUPPORTED = $(CPPFLAGS_LIBBLAKE)
LDFLAGS_LIBBLAKE_IF_SUPPORTED = $(LDFLAGS_LIBBLAKE)
+
+ALIASES_BLAKE = bsum
+ALIASES_BLAKE224 = b224sum
diff --git a/mk/blake256=yes.mk b/mk/blake256=yes.mk
index 6098067..9a054dc 100644
--- a/mk/blake256=yes.mk
+++ b/mk/blake256=yes.mk
@@ -2,3 +2,6 @@ CPPFLAGS_BLAKE256 = -DSUPPORT_BLAKE256
CPPFLAGS_LIBBLAKE_IF_SUPPORTED = $(CPPFLAGS_LIBBLAKE)
LDFLAGS_LIBBLAKE_IF_SUPPORTED = $(LDFLAGS_LIBBLAKE)
+
+ALIASES_BLAKE = bsum
+ALIASES_BLAKE256 = b256sum
diff --git a/mk/blake384=yes.mk b/mk/blake384=yes.mk
index fb66021..82d7e1b 100644
--- a/mk/blake384=yes.mk
+++ b/mk/blake384=yes.mk
@@ -2,3 +2,6 @@ CPPFLAGS_BLAKE384 = -DSUPPORT_BLAKE384
CPPFLAGS_LIBBLAKE_IF_SUPPORTED = $(CPPFLAGS_LIBBLAKE)
LDFLAGS_LIBBLAKE_IF_SUPPORTED = $(LDFLAGS_LIBBLAKE)
+
+ALIASES_BLAKE = bsum
+ALIASES_BLAKE384 = b384sum
diff --git a/mk/blake512=yes.mk b/mk/blake512=yes.mk
index df46eb7..33d1b6c 100644
--- a/mk/blake512=yes.mk
+++ b/mk/blake512=yes.mk
@@ -2,3 +2,6 @@ CPPFLAGS_BLAKE512 = -DSUPPORT_BLAKE512
CPPFLAGS_LIBBLAKE_IF_SUPPORTED = $(CPPFLAGS_LIBBLAKE)
LDFLAGS_LIBBLAKE_IF_SUPPORTED = $(LDFLAGS_LIBBLAKE)
+
+ALIASES_BLAKE = bsum
+ALIASES_BLAKE512 = b512sum
diff --git a/mk/keccak=yes.mk b/mk/keccak=yes.mk
index d35f3e2..8219267 100644
--- a/mk/keccak=yes.mk
+++ b/mk/keccak=yes.mk
@@ -2,3 +2,5 @@ CPPFLAGS_KECCAK = -DSUPPORT_KECCAK
CPPFLAGS_LIBKECCAK_IF_SUPPORTED = $(CPPFLAGS_LIBKECCAK)
LDFLAGS_LIBKECCAK_IF_SUPPORTED = $(LDFLAGS_LIBKECCAK)
+
+ALIASES_KECCAK = keccaksum keccak224sum keccak256sum keccak384sum keccak512sum
diff --git a/mk/md2=yes.mk b/mk/md2=yes.mk
index b387519..a19a5b9 100644
--- a/mk/md2=yes.mk
+++ b/mk/md2=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_MD2 = -DSUPPORT_MD2
+
+ALIASES_MD2 = md2sum
diff --git a/mk/md4=yes.mk b/mk/md4=yes.mk
index 71ea9db..7aead6b 100644
--- a/mk/md4=yes.mk
+++ b/mk/md4=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_MD4 = -DSUPPORT_MD4
+
+ALIASES_MD4 = md4sum
diff --git a/mk/md5=yes.mk b/mk/md5=yes.mk
index 4a537e7..4032545 100644
--- a/mk/md5=yes.mk
+++ b/mk/md5=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_MD5 = -DSUPPORT_MD5
+
+ALIASES_MD5 = md5sum
diff --git a/mk/rawshake=yes.mk b/mk/rawshake=yes.mk
index d41ab71..b863014 100644
--- a/mk/rawshake=yes.mk
+++ b/mk/rawshake=yes.mk
@@ -2,3 +2,5 @@ CPPFLAGS_RAWSHAKE = -DSUPPORT_RAWSHAKE
CPPFLAGS_LIBKECCAK_IF_SUPPORTED = $(CPPFLAGS_LIBKECCAK)
LDFLAGS_LIBKECCAK_IF_SUPPORTED = $(LDFLAGS_LIBKECCAK)
+
+ALIASES_RAWSHAKE = rawshake128sum rawshake256sum rawshake512sum
diff --git a/mk/ripemd-128=yes.mk b/mk/ripemd-128=yes.mk
index 20ccc01..4e9816d 100644
--- a/mk/ripemd-128=yes.mk
+++ b/mk/ripemd-128=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_RIPEMD_128 = -DSUPPORT_RIPEMD_128
+
+ALIASES_RIPEMD_128 = rmd128sum
diff --git a/mk/ripemd-160=yes.mk b/mk/ripemd-160=yes.mk
index a7bdaef..142e040 100644
--- a/mk/ripemd-160=yes.mk
+++ b/mk/ripemd-160=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_RIPEMD_160 = -DSUPPORT_RIPEMD_160
+
+ALIASES_RIPEMD_160 = rmd160sum
diff --git a/mk/ripemd-256=yes.mk b/mk/ripemd-256=yes.mk
index 5ad2c42..720e7f2 100644
--- a/mk/ripemd-256=yes.mk
+++ b/mk/ripemd-256=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_RIPEMD_256 = -DSUPPORT_RIPEMD_256
+
+ALIASES_RIPEMD_256 = rmd256sum
diff --git a/mk/ripemd-320=yes.mk b/mk/ripemd-320=yes.mk
index fefe259..51b51d5 100644
--- a/mk/ripemd-320=yes.mk
+++ b/mk/ripemd-320=yes.mk
@@ -1 +1,3 @@
CPPFLAGS_RIPEMD_320 = -DSUPPORT_RIPEMD_320
+
+ALIASES_RIPEMD_320 = rmd320sum
diff --git a/mk/sha1=yes.mk b/mk/sha1=yes.mk
index c15ebc3..88106b6 100644
--- a/mk/sha1=yes.mk
+++ b/mk/sha1=yes.mk
@@ -1,2 +1,5 @@
CPPFLAGS_SHA1 = $(CPPFLAGS_LIBSHA1) -DSUPPORT_SHA0 -DSUPPORT_SHA1
LDFLAGS_SHA1 = $(LDFLAGS_LIBSHA1)
+
+ALIASES_SHA0 = sha0sum
+ALIASES_SHA1 = sha1sum
diff --git a/mk/sha2=yes.mk b/mk/sha2=yes.mk
index cb26c08..c7e677b 100644
--- a/mk/sha2=yes.mk
+++ b/mk/sha2=yes.mk
@@ -1,2 +1,4 @@
CPPFLAGS_SHA2 = $(CPPFLAGS_LIBSHA2) -DSUPPORT_SHA2
LDFLAGS_SHA2 = $(LDFLAGS_LIBSHA2)
+
+ALIASES_SHA2 = sha224sum sha256sum sha384sum sha512sum sha512-224sum sha512-256sum
diff --git a/mk/sha3=yes.mk b/mk/sha3=yes.mk
index 3d255f5..c01fade 100644
--- a/mk/sha3=yes.mk
+++ b/mk/sha3=yes.mk
@@ -2,3 +2,5 @@ CPPFLAGS_SHA3 = -DSUPPORT_SHA3
CPPFLAGS_LIBKECCAK_IF_SUPPORTED = $(CPPFLAGS_LIBKECCAK)
LDFLAGS_LIBKECCAK_IF_SUPPORTED = $(LDFLAGS_LIBKECCAK)
+
+ALIASES_SHA3 = sha3sum sha3-224sum sha3-256sum sha3-384sum sha3-512sum
diff --git a/mk/shake=yes.mk b/mk/shake=yes.mk
index b3f1fbc..5bea3ff 100644
--- a/mk/shake=yes.mk
+++ b/mk/shake=yes.mk
@@ -2,3 +2,5 @@ CPPFLAGS_SHAKE = -DSUPPORT_SHAKE
CPPFLAGS_LIBKECCAK_IF_SUPPORTED = $(CPPFLAGS_LIBKECCAK)
LDFLAGS_LIBKECCAK_IF_SUPPORTED = $(LDFLAGS_LIBKECCAK)
+
+ALIASES_SHAKE = shake128sum shake256sum shake512sum
diff --git a/openfile.c b/open.c
index e019d05..8d1a4c5 100644
--- a/openfile.c
+++ b/open.c
@@ -3,6 +3,24 @@
int
+patheq(const char *have, const char *want, const char **end_out)
+{
+ while (*want) {
+ if (*have != *want)
+ return 0;
+ if (*have == '/') {
+ while (*++have == '/');
+ while (*++want == '/');
+ }
+ }
+ if (!end_out)
+ return !*have;
+ *end_out = have;
+ return 1;
+}
+
+
+int
openfile(const char *path, int *is_new_fd_out, const char **fname_out)
{
const char *p;
diff --git a/opts.c b/opts.c
new file mode 100644
index 0000000..5c264dd
--- /dev/null
+++ b/opts.c
@@ -0,0 +1,130 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static int
+sizeopt(size_t *valp, const char *s)
+{
+ if (isdigit(*s))
+ return 0;
+ *valp = 0;
+ for (; isdigit(*s); s++) {
+ if (*valp * 10U + (size_t)(*s & 15) > SIZE_MAX)
+ *valp = SIZE_MAX;
+ else
+ *valp = *valp * 10U + (size_t)(*s & 15);
+ }
+ return !*s;
+}
+
+
+int
+parseopt_vendor(void *config_, char *opt, char *val)
+{
+ struct config *config = config_;
+ if (!strcmp(opt, "output")) {
+ if (!val)
+ eprintf("-W option \"%s\" should have an associated value", opt);
+ config->format &= (enum format)~FORMAT_MASK;
+ if (!strcmp(val, "lowercase"))
+ config->format |= LOWERCASE_HEX;
+ else if (!strcmp(val, "uppercase"))
+ config->format |= UPPERCASE_HEX;
+ else if (!strcmp(val, "binary"))
+ config->format |= BINARY;
+ else
+ eprintf("-W option \"%s\" expected value \"lowercase\", \"uppercase\", or \"binary\"", opt);
+
+ } else if (!strcmp(opt, "input")) {
+ if (!val)
+ eprintf("-W option \"%s\" should have an associated value", opt);
+ config->format &= (enum format)~FORMAT_MASK;
+ if (!strcmp(val, "binary") || !strcmp(val, "text"))
+ config->hexinput = 0;
+ else if (!strcmp(val, "hexadecimal"))
+ config->hexinput = 1;
+ else
+ eprintf("-W option \"%s\" expected value \"binary\", \"text\", or \"hexadecimal\"", opt);
+
+ } else if (!strcmp(opt, "threads")) {
+ if (!val)
+ eprintf("-W option \"%s\" should have an associated value", opt);
+ if (!strcmp(val, "auto"))
+ config->threads = 0;
+ else if (!sizeopt(&config->threads, val) || !config->threads)
+ eprintf("-W option \"%s\" expected positive integer value or \"auto\"", opt);
+
+ } else if (!strcmp(opt, "recursive")) {
+ /* TODO the default behaviour should be to not traverse across mount points,
+ * not to not follow symbolic links, however this should be tweakable */
+ if (!val)
+ eprintf("-W option \"%s\" should not have an associated value", opt);
+ config->recursive = 1;
+
+ } else if (!strcmp(opt, "no-recursive")) {
+ if (!val)
+ eprintf("-W option \"%s\" should not have an associated value", opt);
+ config->recursive = 0;
+
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
+char *
+parseopts(void *config, char *string, int (*parseopt)(void *, char *opt, char *val))
+{
+ char *opt, *r = string, c, *val;
+ char *w = string;
+ size_t brackets = 0;
+
+ for (;;) {
+ opt = r;
+ while (*r && *r != ',' && *r != '=')
+ r++;
+ for (; *r; r++) {
+ if (*r == '[' || *r == '(' || *r == '{')
+ brackets++;
+ else if (brackets && (*r == ']' || *r == ')' || *r == '}'))
+ brackets--;
+ else if (!brackets && (*r == ',' || *r == '='))
+ break;
+ }
+ c = *r;
+ *r++ = '\0';
+ val = NULL;
+ if (c == '=') {
+ val = r;
+ for (; *r; r++) {
+ if (*r == '[' || *r == '(' || *r == '{')
+ brackets++;
+ else if (brackets && (*r == ']' || *r == ')' || *r == '}'))
+ brackets--;
+ else if (!brackets && *r == ',')
+ break;
+ }
+ c = *r;
+ *r++ = '\0';
+ }
+
+ if (!(*parseopt)(config, opt, val)) {
+ if (*opt || val) {
+ if (w != string)
+ *w++ = ',';
+ w = stpcpy(w, opt);
+ if (val) {
+ *w++ = '=';
+ w = stpcpy(w, val);
+ }
+ }
+ }
+
+ if (!c)
+ break;
+ }
+
+ *w = '\0';
+ return string;
+}
diff --git a/patheq.c b/patheq.c
deleted file mode 100644
index a23388d..0000000
--- a/patheq.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-int
-patheq(const char *have, const char *want, const char **end_out)
-{
- while (*want) {
- if (*have != *want)
- return 0;
- if (*have == '/') {
- while (*++have == '/');
- while (*++want == '/');
- }
- }
- if (!end_out)
- return !*have;
- *end_out = have;
- return 1;
-}
diff --git a/proc.c b/proc.c
new file mode 100644
index 0000000..08e9252
--- /dev/null
+++ b/proc.c
@@ -0,0 +1,73 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+size_t
+getnproc(size_t default_count)
+{
+ char buf[128];
+ int fd, num = 0;
+ size_t n = 0, off = 0, len = 0;
+ size_t nums[] = {0, 0};
+ ssize_t r;
+ size_t last = 0;
+
+ fd = open("/sys/devices/system/cpu/online", O_RDONLY);
+ if (fd < 0)
+ return default_count;
+
+ for (;; off++) {
+ if (off == len) {
+ r = read(fd, buf, sizeof(buf));
+ if (r <= 0) {
+ if (!r)
+ break;
+ if (errno == EINTR)
+ continue;
+ error:
+ n = default_count;
+ goto out;
+ }
+ len = (size_t)r;
+ off = 0;
+ }
+
+ if (buf[off] == '-') {
+ if (num++ == 1)
+ goto error;
+ } else if (buf[off] == ',' || buf[off] == '\n') {
+ if (num == 0) {
+ nums[1] = nums[0];
+ } else {
+ num = 0;
+ if (nums[1] < nums[0])
+ goto error;
+ }
+ if (nums[0] < last)
+ goto error;
+ last = nums[0];
+ if (nums[1] - nums[0] + 1U > SIZE_MAX - n)
+ goto error;
+ n += nums[1] - nums[0] + 1U;
+ } else if (isdigit(buf[off])) {
+ if (nums[num] > (SIZE_MAX - (size_t)(buf[off] & 15)) / 10U)
+ goto error;
+ nums[num] = nums[num] * 10U + (size_t)(buf[off] & 15);
+ } else {
+ goto error;
+ }
+ }
+
+ n = n ? n : default_count;
+out:
+ close(fd);
+ return n;
+}
+
+
+size_t
+getautonthreads(void)
+{
+ size_t n = getnproc(8U);
+ return n < 3U ? 1U : n - 2U;
+}
diff --git a/rawshake128sum.1 b/rawshake128sum.1
new file mode 100644
index 0000000..d3fa614
--- /dev/null
+++ b/rawshake128sum.1
@@ -0,0 +1,214 @@
+.TH RAWSHAKE128SUM 1 anysum
+.SH NAME
+rawshake128sum - compute or verify against multiple RawSHAKE-128 hashes
+
+.SH SYNOPSIS
+.B rawshake128sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -N
+.IR length ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rawshake128sum
+utility calculates and prints or checks RawSHAKE-128
+checksums.
+.PP
+The
+.B rawshake128sum
+utility can also check a file against multiple RawSHAKE-128
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rawshake128sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N \ \fIlength\fP
+The hash output size in bits. (Default is 128.)
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/rawshake256sum.1 b/rawshake256sum.1
new file mode 100644
index 0000000..5932407
--- /dev/null
+++ b/rawshake256sum.1
@@ -0,0 +1,214 @@
+.TH RAWSHAKE256SUM 1 anysum
+.SH NAME
+rawshake256sum - compute or verify against multiple RawSHAKE-256 hashes
+
+.SH SYNOPSIS
+.B rawshake256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -N
+.IR length ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rawshake256sum
+utility calculates and prints or checks RawSHAKE-256
+checksums.
+.PP
+The
+.B rawshake256sum
+utility can also check a file against multiple RawSHAKE-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rawshake256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N \ \fIlength\fP
+The hash output size in bits. (Default is 256.)
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/rawshake512sum.1 b/rawshake512sum.1
new file mode 100644
index 0000000..81df55c
--- /dev/null
+++ b/rawshake512sum.1
@@ -0,0 +1,214 @@
+.TH RAWSHAKE512SUM 1 anysum
+.SH NAME
+rawshake512sum - compute or verify against multiple RawSHAKE-512 hashes
+
+.SH SYNOPSIS
+.B rawshake512sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -N
+.IR length ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rawshake512sum
+utility calculates and prints or checks RawSHAKE-512
+checksums.
+.PP
+The
+.B rawshake512sum
+utility can also check a file against multiple RawSHAKE-512
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rawshake512sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N \ \fIlength\fP
+The hash output size in bits. (Default is 512.)
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/read.c b/read.c
new file mode 100644
index 0000000..07cf893
--- /dev/null
+++ b/read.c
@@ -0,0 +1,78 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+feedbuffer(int fd, struct buffer *buffer, const char *fname)
+{
+ ssize_t r;
+ if (buffer->offset == buffer->size)
+ buffer->buf = erealloc(buffer->buf, buffer->size += 8096);
+again:
+ r = read(fd, &buffer->buf[buffer->offset], buffer->size - buffer->offset);
+ if (r <= 0) {
+ if (!r)
+ return 1;
+ if (errno == EINTR)
+ goto again;
+ weprintf("%s:", fname);
+ return -1;
+ }
+ buffer->offset += (size_t)r;
+ return 0;
+}
+
+
+void
+shiftbuffer(struct algorithm *algorithms, size_t nalgorithms, struct buffer *buffer)
+{
+ size_t i, consumed = SIZE_MAX;
+ for (i = 0; i < nalgorithms; i++)
+ consumed = MIN(consumed, algorithms[i].offset);
+ if (!consumed)
+ return;
+ for (i = 0; i < nalgorithms; i++)
+ algorithms[i].offset -= consumed;
+ memmove(&buffer->buf[0], &buffer->buf[consumed], buffer->ready -= consumed);
+ memmove(&buffer->buf[buffer->ready], &buffer->buf[buffer->procoff], buffer->offset - buffer->procoff);
+ buffer->offset -= buffer->procoff - buffer->ready;
+ buffer->procoff = buffer->ready;
+}
+
+
+int
+unhex(struct buffer *buffer)
+{
+ size_t i = buffer->procoff;
+ char a, b;
+
+ for (;;) {
+ while (i < buffer->offset && isspace(buffer->buf[i]))
+ i++;
+ if (i == buffer->offset)
+ break;
+
+ buffer->procoff = i;
+ if (!isxdigit(buffer->buf[i]))
+ return -1;
+ a = buffer->buf[i++];
+
+ while (i < buffer->offset && isspace(buffer->buf[i]))
+ i++;
+ if (i == buffer->offset)
+ break;
+
+ if (!isxdigit(buffer->buf[i]))
+ return -1;
+ b = buffer->buf[i++];
+ buffer->procoff = i;
+
+ a = (char)((a & 15) + (a > '9' ? 9 : 0));
+ b = (char)((b & 15) + (b > '9' ? 9 : 0));
+ a <<= 4;
+ a |= b;
+ buffer->buf[buffer->ready++] = a;
+ }
+
+ return 0;
+}
diff --git a/rmd128sum.1 b/rmd128sum.1
new file mode 100644
index 0000000..c19de2d
--- /dev/null
+++ b/rmd128sum.1
@@ -0,0 +1,201 @@
+.TH RMD128SUM 1 anysum
+.SH NAME
+rmd128sum - compute or verify against multiple RIPEMD-128 hashes
+
+.SH SYNOPSIS
+.B rmd128sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rmd128sum
+utility calculates and prints or checks RIPEMD-128 checksums.
+.PP
+The
+.B rmd128sum
+utility can also check a file against multiple RIPEMD-128
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rmd128sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/rmd160sum.1 b/rmd160sum.1
new file mode 100644
index 0000000..e470631
--- /dev/null
+++ b/rmd160sum.1
@@ -0,0 +1,201 @@
+.TH RMD160SUM 1 anysum
+.SH NAME
+rmd160sum - compute or verify against multiple RIPEMD-160 hashes
+
+.SH SYNOPSIS
+.B rmd160sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rmd160sum
+utility calculates and prints or checks RIPEMD-160 checksums.
+.PP
+The
+.B rmd160sum
+utility can also check a file against multiple RIPEMD-160
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rmd160sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/rmd256sum.1 b/rmd256sum.1
new file mode 100644
index 0000000..125dc68
--- /dev/null
+++ b/rmd256sum.1
@@ -0,0 +1,201 @@
+.TH RMD256SUM 1 anysum
+.SH NAME
+rmd256sum - compute or verify against multiple RIPEMD-256 hashes
+
+.SH SYNOPSIS
+.B rmd256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rmd256sum
+utility calculates and prints or checks RIPEMD-256 checksums.
+.PP
+The
+.B rmd256sum
+utility can also check a file against multiple RIPEMD-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rmd256sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/rmd320sum.1 b/rmd320sum.1
new file mode 100644
index 0000000..463ef3b
--- /dev/null
+++ b/rmd320sum.1
@@ -0,0 +1,201 @@
+.TH RMD320SUM 1 anysum
+.SH NAME
+rmd320sum - compute or verify against multiple RIPEMD-320 hashes
+
+.SH SYNOPSIS
+.B rmd320sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B rmd320sum
+utility calculates and prints or checks RIPEMD-320 checksums.
+.PP
+The
+.B rmd320sum
+utility can also check a file against multiple RIPEMD-320
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The rmd320sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha0sum.1 b/sha0sum.1
new file mode 100644
index 0000000..b909e7c
--- /dev/null
+++ b/sha0sum.1
@@ -0,0 +1,203 @@
+.TH SHA0SUM 1 anysum
+.SH NAME
+sha0sum - compute or verify against multiple SHA-0 hashes
+
+.SH SYNOPSIS
+.B sha0sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha0sum
+utility calculates and prints or checks SHA-0 checksums.
+.PP
+The
+.B sha0sum
+utility can also check a file against multiple SHA-0
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha0sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+.PP
+Be advised that SHA-0 is compromised.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha1sum.1 b/sha1sum.1
new file mode 100644
index 0000000..f54dbe7
--- /dev/null
+++ b/sha1sum.1
@@ -0,0 +1,203 @@
+.TH SHA1SUM 1 anysum
+.SH NAME
+sha1sum - compute or verify against multiple SHA-1 hashes
+
+.SH SYNOPSIS
+.B sha1sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha1sum
+utility calculates and prints or checks SHA-1 checksums.
+.PP
+The
+.B sha1sum
+utility can also check a file against multiple SHA-1
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha1sum utility conforms to the Base Definitions volume of
+POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+.PP
+Be advised that SHA-1 is compromised.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha224sum.1 b/sha224sum.1
new file mode 100644
index 0000000..5894ef8
--- /dev/null
+++ b/sha224sum.1
@@ -0,0 +1,202 @@
+.TH SHA224SUM 1 anysum
+.SH NAME
+sha224sum - compute or verify against multiple SHA-224 hashes
+
+.SH SYNOPSIS
+.B sha224sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha224sum
+utility calculates and prints or checks SHA-224 (SHA-2)
+checksums.
+.PP
+The
+.B sha224sum
+utility can also check a file against multiple SHA-224
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha224sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha256sum.1 b/sha256sum.1
new file mode 100644
index 0000000..eb23644
--- /dev/null
+++ b/sha256sum.1
@@ -0,0 +1,202 @@
+.TH SHA256SUM 1 anysum
+.SH NAME
+sha256sum - compute or verify against multiple SHA-256 hashes
+
+.SH SYNOPSIS
+.B sha256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha256sum
+utility calculates and prints or checks SHA-256 (SHA-2)
+checksums.
+.PP
+The
+.B sha256sum
+utility can also check a file against multiple SHA-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha3-224sum.1 b/sha3-224sum.1
new file mode 100644
index 0000000..f1c59a2
--- /dev/null
+++ b/sha3-224sum.1
@@ -0,0 +1,209 @@
+.TH SHA3-224SUM 1 anysum
+.SH NAME
+sha3-224sum - compute or verify against multiple SHA3-224 hashes
+
+.SH SYNOPSIS
+.B sha3-224sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha3-224sum
+utility calculates and prints or checks SHA3-224
+checksums.
+.PP
+The
+.B sha3-224sum
+utility can also check a file against multiple SHA3-224
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha3-224sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha3-256sum.1 b/sha3-256sum.1
new file mode 100644
index 0000000..17c64f1
--- /dev/null
+++ b/sha3-256sum.1
@@ -0,0 +1,209 @@
+.TH SHA3-256SUM 1 anysum
+.SH NAME
+sha3-256sum - compute or verify against multiple SHA3-256 hashes
+
+.SH SYNOPSIS
+.B sha3-256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha3-256sum
+utility calculates and prints or checks SHA3-256
+checksums.
+.PP
+The
+.B sha3-256sum
+utility can also check a file against multiple SHA3-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha3-256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha3-384sum.1 b/sha3-384sum.1
new file mode 100644
index 0000000..6dadf8d
--- /dev/null
+++ b/sha3-384sum.1
@@ -0,0 +1,209 @@
+.TH SHA3-384SUM 1 anysum
+.SH NAME
+sha3-384sum - compute or verify against multiple SHA3-384 hashes
+
+.SH SYNOPSIS
+.B sha3-384sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha3-384sum
+utility calculates and prints or checks SHA3-384
+checksums.
+.PP
+The
+.B sha3-384sum
+utility can also check a file against multiple SHA3-384
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha3-384sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha3-512sum.1 b/sha3-512sum.1
new file mode 100644
index 0000000..a3faaae
--- /dev/null
+++ b/sha3-512sum.1
@@ -0,0 +1,209 @@
+.TH SHA3-512SUM 1 anysum
+.SH NAME
+sha3-512sum - compute or verify against multiple SHA3-512 hashes
+
+.SH SYNOPSIS
+.B sha3-512sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha3-512sum
+utility calculates and prints or checks SHA3-512
+checksums.
+.PP
+The
+.B sha3-512sum
+utility can also check a file against multiple SHA3-512
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha3-512sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha384sum.1 b/sha384sum.1
new file mode 100644
index 0000000..085c22c
--- /dev/null
+++ b/sha384sum.1
@@ -0,0 +1,202 @@
+.TH SHA384SUM 1 anysum
+.SH NAME
+sha384sum - compute or verify against multiple SHA-384 hashes
+
+.SH SYNOPSIS
+.B sha384sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha384sum
+utility calculates and prints or checks SHA-384 (SHA-2)
+checksums.
+.PP
+The
+.B sha384sum
+utility can also check a file against multiple SHA-384
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha384sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha3sum.1 b/sha3sum.1
new file mode 100644
index 0000000..182d36e
--- /dev/null
+++ b/sha3sum.1
@@ -0,0 +1,218 @@
+.TH SHA3SUM 1 anysum
+.SH NAME
+sha3sum - compute or verify against multiple SHA-3 hashes
+
+.SH SYNOPSIS
+.B sha3sum
+.BR [ -a
+.IR bits ]
+.RB [ -c
+.RB [ -w ]]
+.BR [ -S
+.IR salt ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha3sum
+utility calculates and prints or checks SHA-3
+checksums.
+.PP
+The
+.B sha3sum
+utility can also check a file against multiple SHA-3
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha3sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.BR -a \ \fIbits\fP
+Version select: 224, 256, 384, or 512 for
+SHA3-224 (default), SHA3-256, SHA3-384, or
+SHA3-512, respectively.
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha512-224sum.1 b/sha512-224sum.1
new file mode 100644
index 0000000..f19a592
--- /dev/null
+++ b/sha512-224sum.1
@@ -0,0 +1,202 @@
+.TH SHA512-224SUM 1 anysum
+.SH NAME
+sha512-224sum - compute or verify against multiple SHA-512/224 hashes
+
+.SH SYNOPSIS
+.B sha512-224sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha512-224sum
+utility calculates and prints or checks SHA-512/224 (SHA-2)
+checksums.
+.PP
+The
+.B sha512-224sum
+utility can also check a file against multiple SHA-512/224
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha512-224sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha512-256sum.1 b/sha512-256sum.1
new file mode 100644
index 0000000..8ff46ca
--- /dev/null
+++ b/sha512-256sum.1
@@ -0,0 +1,202 @@
+.TH SHA512-256SUM 1 anysum
+.SH NAME
+sha512-256sum - compute or verify against multiple SHA-512/256 hashes
+
+.SH SYNOPSIS
+.B sha512-256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha512-256sum
+utility calculates and prints or checks SHA-512/256 (SHA-2)
+checksums.
+.PP
+The
+.B sha512-256sum
+utility can also check a file against multiple SHA-512/256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha512-256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/sha512sum.1 b/sha512sum.1
new file mode 100644
index 0000000..7f0fec8
--- /dev/null
+++ b/sha512sum.1
@@ -0,0 +1,202 @@
+.TH SHA512SUM 1 anysum
+.SH NAME
+sha512sum - compute or verify against multiple SHA-512 hashes
+
+.SH SYNOPSIS
+.B sha512sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B sha512sum
+utility calculates and prints or checks SHA-512 (SHA-2)
+checksums.
+.PP
+The
+.B sha512sum
+utility can also check a file against multiple SHA-512
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The sha512sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Read in binary mode when computing hashes.
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -t
+Read in text mode when computing hashes.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode,
+so the
+.B -b
+and
+.B -t
+options are ignored, except that they undo
+.BR "-W input=hexadecimal" .
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/shake128sum.1 b/shake128sum.1
new file mode 100644
index 0000000..59f0669
--- /dev/null
+++ b/shake128sum.1
@@ -0,0 +1,214 @@
+.TH SHAKE128SUM 1 anysum
+.SH NAME
+shake128sum - compute or verify against multiple SHAKE-128 hashes
+
+.SH SYNOPSIS
+.B shake128sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -N
+.IR length ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B shake128sum
+utility calculates and prints or checks SHAKE-128
+checksums.
+.PP
+The
+.B shake128sum
+utility can also check a file against multiple SHAKE-128
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The shake128sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N \ \fIlength\fP
+The hash output size in bits. (Default is 128.)
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/shake256sum.1 b/shake256sum.1
new file mode 100644
index 0000000..a870510
--- /dev/null
+++ b/shake256sum.1
@@ -0,0 +1,214 @@
+.TH SHAKE256SUM 1 anysum
+.SH NAME
+shake256sum - compute or verify against multiple SHAKE-256 hashes
+
+.SH SYNOPSIS
+.B shake256sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -N
+.IR length ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B shake256sum
+utility calculates and prints or checks SHAKE-256
+checksums.
+.PP
+The
+.B shake256sum
+utility can also check a file against multiple SHAKE-256
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The shake256sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N \ \fIlength\fP
+The hash output size in bits. (Default is 256.)
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/shake512sum.1 b/shake512sum.1
new file mode 100644
index 0000000..0f34822
--- /dev/null
+++ b/shake512sum.1
@@ -0,0 +1,214 @@
+.TH SHAKE512SUM 1 anysum
+.SH NAME
+shake512sum - compute or verify against multiple SHAKE-512 hashes
+
+.SH SYNOPSIS
+.B shake512sum
+.RB [ -c
+.RB [ -w ]]
+.RB [ -N
+.IR length ]
+.RB [ -W
+.IR options ]\ ...
+.RB [ -z ]
+.RI [ file ]\ ...
+
+.SH DESCRIPTION
+The
+.B shake512sum
+utility calculates and prints or checks SHAKE-512
+checksums.
+.PP
+The
+.B shake512sum
+utility can also check a file against multiple SHAKE-512
+checksums, and check that the file matches at least one
+of the listed checksums.
+
+.SH OPTIONS
+The shake512sum utility conforms to the Base Definitions
+volume of POSIX.1-2017,
+.IR "Section 12.2" ,
+.IR "Utility Syntax Guidelines" .
+.PP
+The following options are supported:
+.TP
+.B -b
+Equivalent to
+.BR "-W output=binary" .
+.TP
+.B -c
+Verify the the files listed in file against the
+checksums listed on the same lines. The file
+shall be formatted as the output of the utility
+when this option is not used. See the
+.B STDOUT
+section for more information. If a file is listed
+multiple times, it need only match one of the
+checksums listed for the file.
+
+The length of the listed checksums need not match
+the length output by this utility; before the
+checksums are compared, they are truncated to the
+shorter of the two checksums.
+.TP
+.B -l
+Equivalent to
+.BR "-W output=lowercase" .
+.TP
+.BR -N \ \fIlength\fP
+The hash output size in bits. (Default is 512.)
+.TP
+.B -u
+Equivalent to
+.BR "-W output=uppercase" .
+.TP
+.B -v
+Print Keccak parameters to standard error.
+.TP
+.BR -W \ \fIoptions\fP
+Comma-sepearated list of implementation-specific
+options. The following options are supported:
+.RS
+.TP
+.BI output= format
+.I format
+shall be
+.RB \(dq lowercase \(dq
+if the checksums shall be printed in lowercase
+hexadecimal format (default),
+.RB \(dq uppercase \(dq
+for uppercase hexadecimal format, or
+.RB \(dq binary \(dq
+for binary format without anything but the
+checksum printed to standard output. This
+option is ignored if the
+.B -c
+option is used.
+.TP
+.BI input= format
+.I format
+shall be
+.RB \(dq binary \(dq
+if the files are be read in binary mode,
+.RB \(dq text \(dq
+if the files shall be read in text mode, or
+.RB \(dq hexadecimal \(dq
+they shall be decoded from hexadecimal to
+binary. If the
+.B -c
+option is used, the mode specification
+associated with a file is overrides this
+behaviour for that file if the line
+specifies hexadecimal mode.
+.TP
+.B recursive
+If a
+.I file
+operand is a directory, the checksum is computed for
+all files recursively. This option is ignored if the
+.B -c
+option is used.
+.TP
+.B no-recursive
+The utility shall traverse directories.
+(This is the default behaviour).
+.RE
+.TP
+.B -w
+Warn about, but skip, lines that are not properly
+formatted.
+.TP
+.B -x
+Equivalent to
+.BR "-W input=hexadeximal" .
+.TP
+.B -z
+Use NUL byte as line ending instead of LF.
+.PP
+There is no difference between binary mode and text mode.
+
+.SH OPERANDS
+The following operand is supported:
+.TP
+.I file
+The file to read and compute the checksum for, or if the
+.B -c
+option is used, use as the listing of files and checksums
+to verify the files against. If dash
+.RB (' - ')
+is used or if no file operand is specified, standard input
+will be used.
+
+.SH STDOUT
+If the
+.B -c
+option is not used, the utility shall print the following
+line for each calculated checksum, however there are options
+that modify the format; see the
+.B OPTIONS
+section for more information:
+.PP
+.RS
+.B \(dq%s %c%s\en\(dq,
+.RI < hash >\fB,\fP
+.RI < mode >\fB,\fP
+.RI < file >
+.RE
+.PP
+where
+.I mode
+is SP (' ') for text mode, an asterisk
+.RB (' * ')
+for binary mode, or a pound sign
+.RB (' # ')
+for hexadecimal mode; however if there is no difference
+between binary mode and text mode and either is selected,
+SP (' ') (text mode) is used.
+.PP
+If the
+.B -c
+option the output shall be on the format:
+.PP
+.RS
+.B \(dq%s: %s\en\(dq,
+.RI < file >\fB,\fP
+.RI < validity >
+.RE
+.PP
+where
+.I validity
+is an implementation specified string
+that describes whether the checksum was valid (possibly
+with remarks), the file did not exist, the file could
+not be read (possibly with error information), or if
+the checksum was invalid or could not be compared
+(possibly with remarks). The
+.B -z
+option does not modify the line ending.
+
+.SH EXIT STATUS
+The following exit values are returned:
+.TP
+0
+Successful completion.
+.TP
+1
+Checksums did not match or a file did not exist.
+.TP
+2
+An error occurred.
+
+.SH NOTES
+Other implementations do not necessarily recognise the
+hexadecimal mode specifier
+.RB (' # ')
+in checksum list files.
+.PP
+The
+.B -c
+option accepting truncated checksums is an
+implementation-specific behaviour.
+
+.SH SEE ALSO
+.BR anysum (1)
diff --git a/shiftbuffer.c b/shiftbuffer.c
deleted file mode 100644
index 6a1213e..0000000
--- a/shiftbuffer.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-void
-shiftbuffer(struct algorithm *algorithms, size_t nalgorithms, struct buffer *buffer)
-{
- size_t i, consumed = SIZE_MAX;
- for (i = 0; i < nalgorithms; i++)
- consumed = MIN(consumed, algorithms[i].offset);
- if (!consumed)
- return;
- for (i = 0; i < nalgorithms; i++)
- algorithms[i].offset -= consumed;
- memmove(&buffer->buf[0], &buffer->buf[consumed], buffer->length -= consumed);
-}
diff --git a/format_result.c b/write.c
index bb0bd29..b3eaa56 100644
--- a/format_result.c
+++ b/write.c
@@ -3,7 +3,36 @@
void
-format_result(struct algorithm *algorithm, const char *file, enum format format)
+writeall(int fd, const void *data, size_t n, const char *fname)
+{
+ const char *text = data;
+ ssize_t r;
+ while (n) {
+ r = write(fd, text, n);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ eprintf("write %s:", fname);
+ }
+ n -= (size_t)r;
+ text = &text[r];
+ }
+}
+
+
+char *
+hex(char *out, const unsigned char *in, size_t n, const char *xdigits)
+{
+ for (; n--; in++) {
+ *out++ = xdigits[(*in >> 4) & 15];
+ *out++ = xdigits[(*in >> 0) & 15];
+ }
+ return out;
+}
+
+
+void
+format_result(struct algorithm *algorithm, const char *file, enum format format, int hexinput)
{
char *p;
size_t size = algorithm->hasher.hash_size + 1U;
@@ -34,7 +63,7 @@ format_result(struct algorithm *algorithm, const char *file, enum format format)
abort();
}
if (format & WITH_FILENAME)
- p = stpcpy(stpcpy(p, " "), file);
+ p = stpcpy(stpcpy(p, hexinput ? " #" : " "), file);
if (format & WITH_NUL)
*p++ = '\0';
if (format & WITH_LF)
diff --git a/writeall.c b/writeall.c
deleted file mode 100644
index 2e3d1ad..0000000
--- a/writeall.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include "common.h"
-
-
-void
-writeall(int fd, const void *data, size_t n, const char *fname)
-{
- const char *text = data;
- ssize_t r;
-
- while (n) {
- r = write(fd, text, n);
- if (r < 0) {
- if (errno == EINTR)
- continue;
- eprintf("write %s:", fname);
- }
- n -= (size_t)r;
- text = &text[r];
- }
-}