-#!perl -w
+#!perl
## shasum: filter for computing SHA digests (ref. sha1sum/md5sum)
##
- ## Copyright (C) 2003-2011 Mark Shelor, All Rights Reserved
+ ## Copyright (C) 2003-2017 Mark Shelor, All Rights Reserved
##
- ## Version: 5.70
- ## Wed Dec 14 02:32:10 MST 2011
+ ## Version: 5.97
+ ## Wed Sep 6 02:23:02 MST 2017
- ## shasum SYNOPSIS adapted from GNU Coreutils sha1sum.
- ## Include an "-a" option for algorithm selection, and a
- ## "-p" option for portable digest computation.
+ ## shasum SYNOPSIS adapted from GNU Coreutils sha1sum. Add
+ ## "-a" option for algorithm selection,
+ ## "-U" option for Universal Newlines support,
+ ## "-0" option for reading bit strings, and
+ ## "-p" option for portable digests (to be deprecated).
+
+BEGIN { pop @INC if $INC[-1] eq '.' }
+
+use strict;
+use warnings;
+use Fcntl;
+use Getopt::Long;
my $POD = <<'END_OF_POD';
-a, --algorithm 1 (default), 224, 256, 384, 512, 512224, 512256
-b, --binary read in binary mode
-c, --check read SHA sums from the FILEs and check them
- -p, --portable read in portable mode
+ -t, --text read in text mode (default)
+ -U, --UNIVERSAL read in Universal Newlines mode
produces same digest on Windows/Unix/Mac
-0, --01 read in BITS mode
ASCII '0' interpreted as 0-bit,
ASCII '1' interpreted as 1-bit,
all other characters ignored
- -t, --text read in text mode (default)
+ -p, --portable read in portable mode (to be deprecated)
- The following two options are useful only when verifying checksums:
+ The following three options are useful only when verifying checksums:
-s, --status don't output anything, status code shows success
+ -q, --quiet don't print OK for each successfully verified file
-w, --warn warn about improperly formatted checksum lines
-h, --help display this help and exit
shasum -a 512224 -c checksumfile
- The sums are computed as described in FIPS-180-4. When checking, the
- input should be a former output of this program. The default mode is to
- print a line with checksum, a character indicating type (`*' for binary,
- ` ' for text, `?' for portable, `^' for BITS), and name for each FILE.
+ The sums are computed as described in FIPS PUB 180-4. When checking,
+ the input should be a former output of this program. The default
+ mode is to print a line with checksum, a character indicating type
+ (`*' for binary, ` ' for text, `U' for UNIVERSAL, `^' for BITS, `?'
+ for portable), and name for each FILE. The line starts with a `\'
+ character if the FILE name contains either newlines or backslashes,
+ which are then replaced by the two-character sequences `\n' and `\\'
+ respectively.
Report shasum bugs to mshelor@cpan.org
I<sha224sum>, I<sha256sum>, I<sha384sum>, and I<sha512sum> programs,
you can install this script as a convenient drop-in replacement.
+Unlike the GNU programs, I<shasum> encompasses the full SHA standard by
+allowing partial-byte inputs. This is accomplished through the BITS
+option (I<-0>). The following example computes the SHA-224 digest of
+the 7-bit message I<0001100>:
+
+ perl -e "print qq(0001100)" | shasum -0 -a 224
+
=head1 AUTHOR
-Copyright (c) 2003-2011 Mark Shelor <mshelor@cpan.org>.
+Copyright (c) 2003-2017 Mark Shelor <mshelor@cpan.org>.
=head1 SEE ALSO
END_OF_POD
-use strict;
-use Fcntl;
-use Getopt::Long;
-
-my $VERSION = "5.70";
-
-
- ## Try to use Digest::SHA. If not installed, use the slower
- ## but functionally equivalent Digest::SHA::PurePerl instead.
-
-my $MOD_PREFER = "Digest::SHA";
-my $MOD_SECOND = "Digest::SHA::PurePerl";
-
-my $module = $MOD_PREFER;
-eval "require $module";
-if ($@) {
- $module = $MOD_SECOND;
- eval "require $module";
- die "Unable to find $MOD_PREFER or $MOD_SECOND\n" if $@;
-}
-
+my $VERSION = "5.97";
sub usage {
my($err, $msg) = @_;
warn($msg . "Type shasum -h for help\n");
exit($err);
}
- my($USAGE) = $POD =~ /SYNOPSIS\n\n(.+)\n=head1 DESCRIPTION\n/sm;
+ my($USAGE) = $POD =~ /SYNOPSIS(.+?)^=/sm;
+ $USAGE =~ s/^\s*//;
+ $USAGE =~ s/\s*$//;
$USAGE =~ s/^ //gm;
- print $USAGE;
+ print $USAGE, "\n";
exit($err);
}
## Collect options from command line
-my ($alg, $binary, $check, $text, $status, $warn, $help, $version);
-my ($portable, $BITS);
+my ($alg, $binary, $check, $text, $status, $quiet, $warn, $help, $version);
+my ($portable, $BITS, $reverse, $UNIVERSAL, $versions);
eval { Getopt::Long::Configure ("bundling") };
GetOptions(
'b|binary' => \$binary, 'c|check' => \$check,
't|text' => \$text, 'a|algorithm=i' => \$alg,
's|status' => \$status, 'w|warn' => \$warn,
+ 'q|quiet' => \$quiet,
'h|help' => \$help, 'v|version' => \$version,
'p|portable' => \$portable,
- '0|01' => \$BITS
+ '0|01' => \$BITS,
+ 'R|REVERSE' => \$reverse,
+ 'U|UNIVERSAL' => \$UNIVERSAL,
+ 'V|VERSIONS' => \$versions,
) or usage(1, "");
usage(0)
if $help;
usage(1, "shasum: Ambiguous file mode\n")
- if scalar(grep {defined $_} ($binary, $portable, $text, $BITS)) > 1;
+ if scalar(grep {defined $_}
+ ($binary, $portable, $text, $BITS, $UNIVERSAL)) > 1;
usage(1, "shasum: --warn option used only when verifying checksums\n")
if $warn && !$check;
usage(1, "shasum: --status option used only when verifying checksums\n")
if $status && !$check;
+usage(1, "shasum: --quiet option used only when verifying checksums\n")
+ if $quiet && !$check;
+
+
+ ## Try to use Digest::SHA. If not installed, use the slower
+ ## but functionally equivalent Digest::SHA::PurePerl instead.
+ ## If option -R is invoked, reverse the module preference,
+ ## i.e. try Digest::SHA::PurePerl first, then Digest::SHA.
- ## Default to SHA-1 unless overriden by command line option
+my @MODS = qw(Digest::SHA Digest::SHA::PurePerl);
+@MODS[0, 1] = @MODS[1, 0] if $reverse;
+
+my $module;
+for (@MODS) {
+ my $mod = $_;
+ if (eval "require $mod") {
+ $module = $mod;
+ last;
+ }
+}
+die "shasum: Unable to find " . join(" or ", @MODS) . "\n"
+ unless defined $module;
+
+
+ ## Default to SHA-1 unless overridden by command line option
$alg = 1 unless defined $alg;
grep { $_ == $alg } (1, 224, 256, 384, 512, 512224, 512256)
exit(0);
}
+if ($versions) {
+ print "shasum $VERSION\n";
+ print "$module ", eval "\$${module}::VERSION", "\n";
+ print "perl ", defined $^V ? sprintf("%vd", $^V) : $], "\n";
+ exit(0);
+}
+
## Try to figure out if the OS is DOS-like. If it is,
## default to binary mode when reading files, unless
- ## explicitly overriden by command line "--text" or
- ## "--portable" options.
+ ## explicitly overridden by command line "--text" or
+ ## "--UNIVERSAL" or "--portable" options.
my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/);
-if ($isDOSish) { $binary = 1 unless $text || $portable }
+if ($isDOSish) { $binary = 1 unless $text || $UNIVERSAL || $portable }
-my $modesym = $binary ? '*' : ($portable ? '?' : ($BITS ? '^' : ' '));
+my $modesym = $binary ? '*' : ($UNIVERSAL ? 'U' :
+ ($BITS ? '^' : ($portable ? '?' : ' ')));
## Read from STDIN (-) if no files listed on command line
sub sumfile {
my $file = shift;
- my $mode = $portable ? 'p' : ($binary ? 'b' : ($BITS ? '0' : ''));
+ my $mode = $binary ? 'b' : ($UNIVERSAL ? 'U' :
+ ($BITS ? '0' : ($portable ? 'p' : '')));
my $digest = eval { $module->new($alg)->addfile($file, $mode) };
if ($@) { warn "shasum: $file: $!\n"; return }
$digest->hexdigest;
my $checkfile = shift;
my ($err, $fmt_errs, $read_errs, $match_errs) = (0, 0, 0, 0);
my ($num_lines, $num_files) = (0, 0);
- my ($bslash, $sum, $fname, $rsp, $digest);
+ my ($bslash, $sum, $fname, $rsp, $digest, $isOK);
local *FH;
$checkfile eq '-' and open(FH, '< -')
next if /^#/; s/\n$//; s/^[ \t]+//; $num_lines++;
$bslash = s/^\\//;
($sum, $modesym, $fname) =
- /^([\da-fA-F]+)[ \t]([ *?^])([^\0]*)/;
+ /^([\da-fA-F]+)[ \t]([ *?^U])([^\0]*)/;
$alg = defined $sum ? $len2alg{length($sum)} : undef;
$fname = unescape($fname) if defined $fname && $bslash;
if (grep { ! defined $_ } ($alg, $sum, $modesym, $fname)) {
}
$fname =~ s/\r$// unless -e $fname;
$rsp = "$fname: "; $num_files++;
- ($binary, $portable, $text, $BITS) =
- map { $_ eq $modesym } ('*', '?', ' ', '^');
+ ($binary, $text, $UNIVERSAL, $BITS, $portable) =
+ map { $_ eq $modesym } ('*', ' ', 'U', '^', 'p');
+ $isOK = 0;
unless ($digest = sumfile($fname)) {
$rsp .= "FAILED open or read\n";
$err = 1; $read_errs++;
}
else {
- if (lc($sum) eq $digest) { $rsp .= "OK\n" }
+ if (lc($sum) eq $digest) { $rsp .= "OK\n"; $isOK = 1 }
else { $rsp .= "FAILED\n"; $err = 1; $match_errs++ }
}
- print $rsp unless $status;
+ print $rsp unless ($status || ($quiet && $isOK));
}
close(FH);
unless ($num_files) {