Update Digest-SHA to CPAN version 5.49
[perl.git] / cpan / Digest-SHA / shasum
index 3c01858..c024ff2 100644 (file)
@@ -1,11 +1,11 @@
 #!perl -w
 
-       # shasum: filter for computing SHA digests (analogous to sha1sum)
-       #
-       # Copyright (C) 2003-2010 Mark Shelor, All Rights Reserved
-       #
-       # Version: 5.48
-       # Mon Jan  4 16:32:52 MST 2010
+       ## shasum: filter for computing SHA digests (ref. sha1sum/md5sum)
+       ##
+       ## Copyright (C) 2003-2010 Mark Shelor, All Rights Reserved
+       ##
+       ## Version: 5.49
+       ## Sun Dec 12 07:22:04 MST 2010
 
 =head1 NAME
 
@@ -74,11 +74,11 @@ use strict;
 use FileHandle;
 use Getopt::Long;
 
-my $VERSION = "5.48";
+my $VERSION = "5.49";
 
 
-       # Try to use Digest::SHA, since it's faster.  If not installed,
-       # use Digest::SHA::PurePerl instead.
+       ## Try to use Digest::SHA, since it's faster.  If not installed,
+       ## use Digest::SHA::PurePerl instead.
 
 my $MOD_PREFER = "Digest::SHA";
 my $MOD_SECOND = "Digest::SHA::PurePerl";
@@ -92,9 +92,9 @@ if ($@) {
 }
 
 
-       # Usage statement adapted from Ulrich Drepper's md5sum.
-       # Include an "-a" option for algorithm selection,
-       # and a "-p" option for portable digest computation.
+       ## Usage statement adapted from Ulrich Drepper's md5sum.
+       ## Include an "-a" option for algorithm selection,
+       ## and a "-p" option for portable digest computation.
 
 sub usage {
        my($err, $msg) = @_;
@@ -135,7 +135,13 @@ END_OF_USAGE
 }
 
 
-       # Collect options from command line
+       ## Sync stdout and stderr by forcing a flush after every write
+
+autoflush STDOUT 1;
+autoflush STDERR 1;
+
+
+       ## Collect options from command line
 
 my ($alg, $binary, $check, $text, $status, $warn, $help, $version);
 my ($portable);
@@ -150,7 +156,7 @@ GetOptions(
 ) or usage(1, "");
 
 
-       # Deal with help requests and incorrect uses
+       ## Deal with help requests and incorrect uses
 
 usage(0)
        if $help;
@@ -162,14 +168,14 @@ usage(1, "shasum: --status option used only when verifying checksums\n")
        if $status && !$check;
 
 
-       # Default to SHA-1 unless overriden by command line option
+       ## Default to SHA-1 unless overriden by command line option
 
 $alg = 1 unless defined $alg;
 grep { $_ == $alg } (1, 224, 256, 384, 512)
        or usage(1, "shasum: Unrecognized algorithm\n");
 
 
-       # Display version information if requested
+       ## Display version information if requested
 
 if ($version) {
        print "$VERSION\n";
@@ -177,10 +183,10 @@ if ($version) {
 }
 
 
-       # 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.
+       ## 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.
 
 my $isDOSish = ($^O =~ /^(MSWin\d\d|os2|dos|mint|cygwin)$/);
 if ($isDOSish) { $binary = 1 unless $text || $portable }
@@ -188,53 +194,73 @@ if ($isDOSish) { $binary = 1 unless $text || $portable }
 my $modesym = $binary ? '*' : ($portable ? '?' : ' ');
 
 
-       # Read from STDIN (-) if no files listed on command line
+       ## Read from STDIN (-) if no files listed on command line
 
 @ARGV = ("-") unless @ARGV;
 
 
-       # sumfile($file): computes SHA digest of $file
+       ## sumfile($file): computes SHA digest of $file
 
 sub sumfile {
        my $file = shift;
 
        my $mode = $portable ? 'p' : ($binary ? 'b' : '');
        my $digest = eval { $module->new($alg)->addfile($file, $mode) };
-       if ($@) {
-               warn "shasum: $file: $!\n";
-               return;
-       }
-
+       if ($@) { warn "shasum: $file: $!\n"; return }
        $digest->hexdigest;
 }
 
 
-       # %len2alg: maps hex digest length to SHA algorithm
+       ## %len2alg: maps hex digest length to SHA algorithm
 
 my %len2alg = (40 => 1, 56 => 224, 64 => 256, 96 => 384, 128 => 512);
 
 
-       # Verify checksums if requested
+       ## unescape: convert backslashed filename to plain filename
 
-if ($check) {
-       my $checkfile = shift(@ARGV);
-       my ($err, $read_errs, $match_errs) = (0, 0, 0);
-       my ($num_files, $num_checksums) = (0, 0);
-       my ($fh, $sum, $fname, $rsp, $digest);
+sub unescape {
+       $_ = shift;
+       s/\\\\/\0/g;
+       s/\\n/\n/g;
+       return if /\\/;
+       s/\0/\\/g;
+       return $_;
+}
 
-       die "shasum: $checkfile: $!\n"
-               unless $fh = FileHandle->new($checkfile, "r");
-       while (<$fh>) {
-               s/\s+$//;
-               ($sum, $modesym, $fname) = /^(\S+) (.)(.*)$/;
-               ($binary, $portable, $text) =
-                       map { $_ eq $modesym } ('*', '?', ' ');
-               unless ($alg = $len2alg{length($sum)}) {
+
+       ## verify: confirm the digest values in a checksum file
+
+sub verify {
+       my $checkfile = shift;
+       my ($err, $fmt_errs, $read_errs, $match_errs) = (0, 0, 0, 0);
+       my ($num_lines, $num_files, $num_checksums) = (0, 0, 0);
+       my ($bslash, $sum, $fname, $rsp, $digest);
+
+       local *FH;
+       unless (sysopen(FH, $checkfile, O_RDONLY)) {
+               unless ($checkfile eq '-' && open(FH, '<&STDIN')) {
+                       _bail("Open failed");
+               }
+               $checkfile = 'standard input';
+       }
+       while (<FH>) {
+               next if /^#/; s/\n$//; s/^[ \t]+//; $num_lines++;
+               $bslash = s/^\\//;
+               ($sum, $modesym, $fname) =
+                       /^([\da-fA-F]+)[ \t]([ *?])([^\0]*)/;
+               $alg = defined $sum ? $len2alg{length($sum)} : undef;
+               $fname = unescape($fname) if defined $fname && $bslash;
+               if (grep { ! defined $_ } ($alg, $sum, $modesym, $fname)) {
+                       $alg = 1 unless defined $alg;
                        warn("shasum: $checkfile: $.: improperly " .
-                               "formatted SHA checksum line\n") if $warn;
+                               "formatted SHA$alg checksum line\n") if $warn;
+                       $fmt_errs++;
                        next;
                }
+               $fname =~ s/\r$// unless -e $fname;
                $rsp = "$fname: "; $num_files++;
+               ($binary, $portable, $text) =
+                       map { $_ eq $modesym } ('*', '?', ' ');
                unless ($digest = sumfile($fname)) {
                        $rsp .= "FAILED open or read\n";
                        $err = 1; $read_errs++;
@@ -246,23 +272,39 @@ if ($check) {
                }
                print $rsp unless $status;
        }
-       $fh->close;
-       unless ($status) {
-               warn("shasum: WARNING: $read_errs of $num_files listed " .
-                       "files could not be read\n") if $read_errs;
-               warn("shasum: WARNING: $match_errs of $num_checksums " .
-                       "computed checksums did NOT match\n") if $match_errs;
+       close(FH);
+       unless ($num_files) {
+               $alg = 1 unless defined $alg;
+               warn("shasum: $checkfile: no properly formatted " .
+                       "SHA$alg checksum lines found\n");
+               $err = 1;
        }
-       exit($err);
+       elsif (! $status) {
+               warn("shasum: WARNING: $fmt_errs line" . ($fmt_errs>1?
+               's are':' is') . " improperly formatted\n") if $fmt_errs;
+               warn("shasum: WARNING: $read_errs listed file" .
+               ($read_errs>1?'s':'') . " could not be read\n") if $read_errs;
+               warn("shasum: WARNING: $match_errs computed checksum" .
+               ($match_errs>1?'s':'') . " did NOT match\n") if $match_errs;
+       }
+       return($err == 0);
 }
 
 
-       # Compute and display SHA checksums of requested files
+       ## Verify or compute SHA checksums of requested files
 
 my($file, $digest);
 
+my $STATUS = 0;
 for $file (@ARGV) {
-       if ($digest = sumfile($file)) {
+       if ($check) { $STATUS = 1 unless verify($file) }
+       elsif ($digest = sumfile($file)) {
+               if ($file =~ /[\n\\]/) {
+                       $file =~ s/\\/\\\\/g; $file =~ s/\n/\\n/g;
+                       $digest = "\\$digest";
+               }
                print "$digest $modesym", "$file\n";
        }
+       else { $STATUS = 1 }
 }
+exit($STATUS)