2 eval "exec perl -S $0 $*"
3 if $running_under_some_shell;
5 # $Id: patcol.SH 1 2006-08-24 12:32:52Z rmanfredi $
7 # Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi
9 # You may redistribute only under the terms of the Artistic Licence,
10 # as specified in the README file that comes with the distribution.
11 # You may reuse parts of this distribution only within the terms of
12 # that same Artistic Licence; a copy of which may be found at the root
13 # of the source tree for dist 4.0.
16 # Revision 3.0.1.3 1994/01/24 14:30:25 ram
17 # patch16: now prefix error messages with program's name
18 # patch16: added ~/.dist_profile awareness
20 # Revision 3.0.1.2 1993/08/24 12:16:30 ram
21 # patch3: new -S option for snapshot check-outs
23 # Revision 3.0.1.1 1993/08/19 06:42:34 ram
24 # patch1: leading config.sh searching was not aborting properly
26 # Revision 3.0 1993/08/18 12:10:42 ram
27 # Baseline for dist 3.0 netwide release.
33 $progname = &profile; # Read ~/.dist_profile
35 &usage unless $#ARGV >= 0;
36 &usage unless &Getopts("acd:f:hnmsCRS:V");
39 print STDERR "$progname $version PL$patchlevel\n";
45 $RCSEXT = ',v' unless $RCSEXT;
46 $NEWMANI = 'MANIFEST.new' unless $NEWMANI = $opt_f;
48 chop($pwd = `pwd`) unless -f '.package';
49 until (-f '.package') {
50 die "$progname: no .package file! Run packinit.\n" unless $pwd;
51 chdir '..' || die "$progname: can't cd ..: $!";
52 $pwd =~ s|(.*)/(.*)|$1|;
53 $prefix = $2 . '/' . $prefix;
57 s/^/$prefix/ unless m|^[-/]|;
61 # We now are at the top level
64 undef $opt_C unless -f $copyright;
65 ©right'init($copyright) if $opt_C;
66 &makedir($opt_d) if $opt_d;
68 undef $opt_c unless $opt_d; # Disable -c if not -d
69 undef $opt_R unless $opt_d; # Disable -R if not -d
70 push(@sw, '-q') if $opt_s; # Let RCS work quietly
73 &newer; # Look for files newer than patchlevel.h
75 open(MANI, $NEWMANI) || die "No $NEWMANI found.\n";
79 next if m|^patchlevel.h| && !$opt_d; # This file is built by hand
87 open(MODS,"bugs/.mods$bnum") || die "$progname: no modification found.\n";
90 next if m|^patchlevel.h$|; # This file is built by hand
98 &readsnapshot($opt_S);
99 foreach $file (sort keys %Snap) {
104 # Now loop over each file specified, doing a 'co -l'
105 foreach $file (@ARGV) {
106 if ($opt_c && -f $file) {
107 ©_file($file, $opt_d);
110 # Continue only if file does not exist or option -d was used.
111 if (! -f $file || $opt_d) {
112 $files = &rcsargs($file);
113 @files = split(' ', $files);
114 if ($opt_S && ($rev = $Snap{$file}) ne '') { # Use snapshot file
118 $rlog = `rlog -rlastpat- $files 2>&1`;
119 ($revs) = ($rlog =~ /selected revisions: (\d+)/);
122 ©_file($file, $opt_d);
124 print STDERR "$progname: $file has never been checked in\n";
127 # Look whether there is a branch
129 $rlog = `rlog -r$revbranch $files 2>&1`;
130 ($revs) = ($rlog =~ /selected revisions: (\d+)/);
131 $revs++; # add the base revision (trunk)
143 # Run co -l on @files, unlock file if it fails and retry.
144 # If '-d' option was used, we check out in the specified
145 # directory, after having made all the necessary directories
146 # in the path name (which should be relative to the top).
148 local($rev) = shift; # Revision to be checked out.
150 if (system 'co', "-l$rev", @sw, @files) {
151 print "$progname: unlocking and trying again...\n" unless $opt_s;
152 system 'rcs', '-u', @sw, @files;
153 system 'co', "-l$rev", @sw, @files unless $?;
156 local($name) = $files[0]; # First element is file name
158 s|(.*)/.*|\1| && &makedir("$opt_d/$_");
160 ©right'expand("co -p @sw -r$rev $files[1]", "$opt_d/$name");
162 system "co -p -r$rev @sw $files[1] > $opt_d/$name";
164 system 'perl', '-pi', '-e', 's|Lock[e]r:.*\$|\$|;', "$opt_d/$name"
166 # If RCS file has x bits set, add them on new file
167 -x $files[1] && chmod(0755, "$opt_d/$name");
171 # Copy file into directory, eventually performing copyright expansion...
173 local($file, $dir) = @_;
174 local($base) = $file =~ m|^(.*)/.*|;
175 &makedir("$dir/$base");
177 ©right'expand("cat $file", "$dir/$file");
179 system 'cp', "$file", "$dir/$file";
181 system 'perl', '-pi', '-e', 's|Lock[e]r:.*\$|\$|;', "$dir/$file" if $opt_R;
182 -x $file && chmod(0755, "$dir/$file");
183 print "$progname: $file has been copied\n" unless $opt_s;
188 Usage: $progname [-achnmsCRV] [-d directory] [-f mani] [-S snap] [filelist]
189 -a : all the files in MANIFEST.new (see also -f)
190 -c : copy files if checked-out copy exists (only when -d)
191 -d : check out (or copy) in the specified directory
192 -f : use supplied file instead of MANIFEST.new
193 -h : print this message and exit
194 -n : all the files newer than patchlevel.h
195 -m : all the modified files (which have been patciled)
197 -C : perform copyright expansion on checked out (or copied) file
198 -R : strip out RCS \$Locker marker from checked-out file (only when -d)
199 -S : use snapshot file to determine file list and RCS revisions
200 -V : print version number and exit
206 open(FIND, "find . -type f -newer patchlevel.h -print | sort |") ||
207 die "Can't run find.\n";
208 open(NEWER,">.newer") || die "Can't create .newer.\n";
209 open(MANI,"MANIFEST.new");
211 ($name,$foo) = split;
218 next if m|^MANIFEST|;
219 next if m|^PACKLIST$|;
221 next if m|^MANIFEST.new$|;
222 next if m|^Changes$|;
224 next if m|^.package$|;
230 next if m|^config.sh$|;
231 next if m|/config.sh$|;
232 next if m|^make.out$|;
233 next if m|/make.out$|;
246 next if $mani{$_ . ".SH"};
247 next if m|(.*)\.c$| && $mani{$1 . ".y"};
248 next if m|(.*)\.c$| && $mani{$1 . ".l"};
249 next if (-x $_ && !m|^Configure$|);
255 print "Please remove unwanted files...\n";
257 system '${EDITOR-vi} .newer';
258 die "Aborted.\n" unless -s '.newer' > 1;
259 @ARGV = split(' ',`cat .newer`);
263 if (! -f '.package') {
266 -f '../../.package' ||
267 -f '../../../.package' ||
268 -f '../../../../.package'
270 die "Run in top level directory only.\n";
272 die "No .package file! Run packinit.\n";
275 open(PACKAGE,'.package');
279 if (($var,$val) = /^\s*(\w+)=(.*)/) {
280 $val = "\"$val\"" unless $val =~ /^['"]/;
281 eval "\$$var = $val;";
290 while ($_ = shift(@_)) {
293 } elsif ($#_ >= 0 && do equiv($_,$_[0])) {
294 $result .= $_ . ' ' . $_[0] . ' ';
297 $result .= $_ . ' ' . do other($_) . ' ';
304 local($s1, $s2) = @_;
309 } elsif ($s1 =~ s/$RCSEXT$// || $s2 =~ s/$RCSEXT$//) {
318 ($dir,$file) = ('./',$s1) unless local($dir,$file) = ($s1 =~ m|(.*/)(.*)|);
319 $dir = $TOPDIR . $dir if -d $TOPDIR . "$dir/RCS";
320 local($wasrcs) = ($file =~ s/$RCSEXT$//);
322 `mkdir $dir` unless -d $dir;
326 `mkdir $dir` unless -d $dir;
334 # Read in copyright file
336 local($file) = @_; # Copyright file
338 open(COPYRIGHT, $file) || die "Can't open $file: $!\n";
339 chop(@copyright = <COPYRIGHT>);
343 # Reset the automaton for a new file.
345 $copyright_seen = @copyright ? 0 : 1;
349 # Filter file, line by line, and expand the copyright string. The @COPYRIGHT@
350 # symbol may be preceded by some random comment. A leader can be defined and
351 # will be pre-pended to all the input lines.
353 local($line, $leader) = @_; # Leader is optional
354 return $leader . $line if $copyright_seen || $marker_seen;
355 $marker_seen = 1 if $line =~ /\$Log[:\$]/;
356 $copyright_seen = 1 if $line =~ /\@COPYRIGHT\@/;
357 return $leader . $line unless $copyright_seen;
358 local($comment, $trailer) = $line =~ /^(.*)\@COPYRIGHT\@\s*(.*)/;
359 $comment = $leader . $comment;
360 $comment . join("\n$comment", @copyright) . "\n";
363 # Filter output of $cmd redirected into $file by expanding copyright, if any.
365 local($cmd, $file) = @_;
367 open(CMD,"$cmd|") || die "Can't start '$cmd': $!\n";
368 open(OUT, ">$file") || die "Can't create $file: $!\n";
372 print OUT &filter($_);
377 system "$cmd > $file";
378 die "Command '$cmd' failed!" if $?;
384 # Make directories for files
385 # E.g, for /usr/lib/perl/foo, it will check for all the
386 # directories /usr, /usr/lib, /usr/lib/perl and make
387 # them if they do not exist.
391 if (!-d && $_ ne '') {
393 do makedir($_) if s|(.*)/.*|\1|;
394 mkdir($dir, 0700) if ! -d $dir;
398 # Read snapshot file and build %Snap, indexed by file name -> RCS revision
401 open(SNAP, $snap) || warn "Can't open $snap: $!\n";
406 ($file, $rev) = split;
407 $Snap{$file} = "$rev";
412 # Perform ~name expansion ala ksh...
413 # (banish csh from your vocabulary ;-)
416 return $path unless $path =~ /^~/;
417 $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
418 $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~
422 # Set up profile components into %Profile, add any profile-supplied options
423 # into @ARGV and return the command invocation name.
425 local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile');
426 local($me) = $0; # Command name
427 $me =~ s|.*/(.*)|$1|; # Keep only base name
428 return $me unless -s $profile;
429 local(*PROFILE); # Local file descriptor
430 local($options) = ''; # Options we get back from profile
431 unless (open(PROFILE, $profile)) {
432 warn "$me: cannot open $profile: $!\n";
438 next if /^\s*#/; # Skip comments
440 if (s/^$me://o) { # progname: options
442 $options .= $_; # Merge options if more than one line
444 elsif (s/^$me-([^:]+)://o) { # progname-component: value
447 s/^\s+//; # Trim leading and trailing spaces
449 $Profile{$component} = $_;
453 return unless $options;
454 require 'shellwords.pl';
456 eval '@opts = &shellwords($options)'; # Protect against mismatched quotes
457 unshift(@ARGV, @opts);
458 return $me; # Return our invocation name