#!/usr/bin/perl

=begin metadata

Name: uudecode
Description: decode a binary file
Author: Nick Ing-Simmons, nick@ni-s.u-net.com
Author: Tom Christiansen, tchrist@perl.com
Author: brian d foy, brian.d.foy@gmail.com
License: perl

=end metadata

=cut


use strict;

use File::Basename qw(basename);
use Getopt::Std qw(getopts);

use constant EX_SUCCESS => 0;
use constant EX_FAILURE => 1;

my $Program = basename($0);

my %opt;
getopts('io:', \%opt) or usage();
my $output_file = $opt{'o'};

FILESPEC :
while (<>) {
    my( $mode, $header_name );
    next FILESPEC unless ($mode, $header_name) = /^begin\s+(\d+)\s+(\S+)/;
	$output_file = $header_name unless defined $output_file;

    my $out;
    if ($output_file eq '-') {
    	$out = *STDOUT;
    }
    else               {
    	if ($opt{'i'} && -e $output_file) {
		warn "$Program: won't clobber file '$output_file'\n";
		exit EX_FAILURE;
    	}
    	unless (open $out, '>', $output_file) {
		warn "$Program: can't create '$output_file': $!\n";
		exit EX_FAILURE;
    	}
		# Quickly protect file before data is written.
		# XXX: Does this break on sub-Unix systems, like if
		#      it's a mode 400 or 000 file? If so, then we must
		#      wait until after the close.
    	unless (chmod oct($mode), $output_file) {
		warn "$Program: can't chmod '$output_file' to mode '$mode': $!\n";
		exit EX_FAILURE;
    	}
    }

    binmode($out);	# winsop
    my $ended = 0;

LINE:
    while (<>) {
	if (/^end$/) {
	    $ended = 1;
	    last LINE;
	}
	next LINE if /[a-z]/;
	next LINE unless int((((ord() - 32) & 077) + 2) / 3)
		      == int(length() / 4);
	unless (print $out unpack("u", $_)) {
	    warn "$Program: can't write '$output_file': $!\n";
	    exit EX_FAILURE;
	}
    }
    unless (close $out) {
	warn "$Program: can't close '$output_file': $!\n";
	exit EX_FAILURE;
    }
    unless ($ended) {
	warn "$Program: missing end; '$output_file' may be truncated\n";
	exit EX_FAILURE;
    }
}
exit EX_SUCCESS;

sub usage {
    require Pod::Usage;
    Pod::Usage::pod2usage({ -exitval => 1, -verbose => 0 });
}

__END__

=encoding utf8

=head1 NAME

uudecode - decode a binary file

=head1 SYNOPSIS

	# decode to the name in the header
	% uudecode [-i] file.uu

	# decode to the name on the command line
	% uudecode -o output.txt file.uu

	# decode to standard output despite the header
	% uudecode -o - file.uu

=head1 DESCRIPTION

This program decodes a uuencoded file and saves the results to the file
denoted in the header line.

=head1 OPTIONS

The following options are available:

=over 4

=item -i

Do not overwrite files.

=item -o FILE

Write output to specified FILE, ignoring filename in uuencode header line.
If FILE is '-', standard output will be used.

=back

=head1 AUTHOR

Originally by Nick Ing-Simmons but since irrecognizably hacked on
by Tom Christiansen. brian d foy further packaged, improved, and tested
it.

