11 require VMS::Filespec;
16 Getopt::Long::Configure('no_ignore_case');
18 our $LastUpdate = -M $0;
22 my $file = shift or die "Need file\n". usage();
23 my $outfile = shift || '';
24 $file = vms_check_name($file) if $^O eq 'VMS';
25 my $mode = (stat($file))[2] & 07777;
27 open my $fh, "<", $file
28 or do { warn "Could not open input file $file: $!"; exit 0 };
29 my $str = do { local $/; <$fh> };
36 $outfile =~ s/\.packed\z//;
38 my ($head, $body) = split /__UU__\n/, $str;
39 die "Can't unpack malformed data in '$file'\n"
41 $outstr = unpack 'u', $body;
44 $outfile ||= $file . '.packed';
46 my $me = basename($0);
48 $outstr = <<"EOFBLURB" . pack 'u', $str;
49 #########################################################################
50 This is a binary file that was packed with the 'uupacktool.pl' which
51 is included in the Perl distribution.
53 To unpack this file use the following command:
57 To recreate it use the following command:
61 Created at @{[scalar localtime]}
62 #########################################################################
71 $outfile = VMS::Filespec::vmsify($outfile) if $^O eq 'VMS';
72 print "Writing $file into $outfile\n" if $opts->{'v'};
73 open my $outfh, ">", $outfile
74 or do { warn "Could not open $outfile for writing: $!"; exit 0 };
76 ### $outstr might be empty, if the file was empty
77 print $outfh $outstr if $outstr;
80 chmod $mode, $outfile;
83 ### delete source file?
84 if( $opts->{'D'} and $file ne $outfile ) {
91 my $Manifest = $opts->{'m'};
93 open my $fh, "<", $Manifest or die "Could not open '$Manifest':$!";
95 print "Reading $Manifest\n"
100 while( my $line = <$fh> ) {
102 my ($file) = split /\s+/, $line;
106 next unless $file =~ /\.packed/;
111 $out =~ s/\.packed\z//;
112 $out = vms_check_name($out) if $^O eq 'VMS';
115 if( !$opts->{'c'} ) {
116 ( $out, $file ) = ( $file, $out ) if $opts->{'p'};
119 if ($changed < $LastUpdate and $changed < -M $file) {
120 print "Skipping '$file' as '$out' is up-to-date.\n"
125 handle_file($opts, $file, $out);
126 print "Converted '$file' to '$out'\n"
134 print "File '$file' was not unpacked into '$out'. Can not remove.\n";
138 print "Removing '$out'\n";
143 print "Found $count files to process out of $lines in '$Manifest'\n"
149 Usage: $^X $0 [-d dir] [-v] [-c] [-D] -p|-u [orig [packed|-s] | -m [manifest]]
151 Handle binary files in source tree. Can be used to pack or
152 unpack files individiually or as specified by a manifest file.
155 -u Unpack files (defaults to -u unless -p is specified)
157 -c Clean up all unpacked files. Implies -m
159 -D Delete source file after encoding/decoding
161 -s Output to STDOUT rather than OUTPUT_FILE
162 -m Use manifest file, if none is explicitly provided defaults to 'MANIFEST'
164 -d Change directory to dir before processing
167 -h Display this help message
173 # Packed files tend to have multiple dots, which the CRTL may or may not handle
174 # properly, so convert to native format. And depending on how the archive was
175 # unpacked, foo.bar.baz may be foo_bar.baz or foo.bar_baz. N.B. This checks for
176 # existence, so is not suitable as-is to generate ODS-2-safe names in preparation
181 $file = VMS::Filespec::vmsify($file);
182 return $file if -e $file;
184 my ($vol,$dirs,$base) = File::Spec->splitpath($file);
186 1 while $tmp =~ s/([^\.]+)\.(.+\..+)/$1_$2/;
187 my $try = File::Spec->catpath($vol, $dirs, $tmp);
188 return $try if -e $try;
191 1 while $tmp =~ s/(.+\..+)\.([^\.]+)/$1_$2/;
192 $try = File::Spec->catpath($vol, $dirs, $tmp);
193 return $try if -e $try;
199 GetOptions($opts,'u','p','c', 'D', 'm:s','s','d=s','v','h');
201 die "Can't pack and unpack at the same time!\n", usage()
202 if $opts->{'u'} && $opts->{'p'};
203 die usage() if $opts->{'h'};
205 if ( $opts->{'d'} ) {
207 or die "Failed to chdir to '$opts->{'d'}':$!";
209 $opts->{'u'} = 1 if !$opts->{'p'};
210 binmode STDOUT if $opts->{'s'};
211 if ( exists $opts->{'m'} or exists $opts->{'c'} ) {
212 $opts->{'m'} ||= "MANIFEST";
217 handle_file($opts, @ARGV);
219 die "No file to process specified!\n", usage();