#!/usr/bin/perl

=begin metadata

Name: shar
Description: create a shell archive of files
Author: Rich Salz, salzr@certo.com, rsalz@osf.org, rsalz@bbn.com
License: public domain

=end metadata

=cut


# public domain code by salzr@certo.com
# (formerly rsalz@osf.org, rsalz@bbn.com, mirror!rs)

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);

sub usage {
    warn "usage: $Program file...\n";
    exit EX_FAILURE;
}

getopts('') or usage();
@ARGV or usage();
binmode STDOUT;

print '# --cut here--
# To extract, remove everything before the "cut here" line
# and run the command "sh file".
';

my $done = 0;
ARGUMENT: for my $f ( @ARGV ) {
    if (-d $f) {
	print "echo x - $f/\n";
	print "mkdir -p $f\n";
	$done++;
	next ARGUMENT;
    }
    unless (open FH, '<', $f) {
	warn "$Program: can't open '$f': $!\n";
	next ARGUMENT;
    }
    binmode FH;

    print "echo x - $f\n";
    if (-B $f) {
	my $mode = (stat $f)[2];
	$mode = (join '', 0, ($mode&0700)>>6, ($mode&0070)>>3, ($mode&0007));
	print "sed -e 's/^X//' | uudecode <<'FUNKY_STUFF'\n";
	print "begin $mode $f\n";
	my $block;
	print pack 'u', $block while read FH, $block, 45;
	print "end\n";
    } else {
	print "sed -e 's/^X//' >$f <<'FUNKY_STUFF'\n";
	print 'X', $_ while ( <FH> );
    }
    print "FUNKY_STUFF\n";
    close(FH);
    $done++;
}
if ($done == 0) {
    warn "$Program: no input files were processed\n";
    exit EX_FAILURE;
}
exit EX_SUCCESS;

__END__

=head1 NAME

shar - create a shell archive of files

=head1 SYNOPSIS

B<shar> file...

=head1 DESCRIPTION

B<shar> reads input files and writes a shell archive to standard output.
The shell archive is a shell script, and executing it will recreate the I<files>.
File permissions are not preserved for archived files.
Extracted files are created with the default file permissions and owner.
Directories will be recreated, but directory arguments must be provided before
the files they contain.

=head1 SEE ALSO

B<unshar>

=head1 AUTHOR

Rich Salz | salzr@certo.com | rsalz@osf.org | rsalz@bbn.com

=head1 COPYRIGHT

This code is released to the public domain.

=cut
