2 eval "exec perl -S $0 $*"
3 if $running_under_some_shell;
5 # $Id: patdiff.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.
15 # Original Author: Larry Wall <lwall@netlabs.com>
17 # $Log: patdiff.SH,v $
18 # Revision 3.0.1.2 1994/01/24 14:30:36 ram
19 # patch16: now prefix error messages with program's name
20 # patch16: added ~/.dist_profile awareness
22 # Revision 3.0.1.1 1993/08/19 06:42:35 ram
23 # patch1: leading config.sh searching was not aborting properly
25 # Revision 3.0 1993/08/18 12:10:43 ram
26 # Baseline for dist 3.0 netwide release.
32 $RCSEXT = ',v' unless $RCSEXT;
33 $TOPDIR = ''; # We are at top-level directory
35 $progname = &profile; # Read ~/.dist_profile
37 &usage unless $#ARGV >= 0;
38 &usage unless &Getopts("ahnV");
41 print STDERR "$progname $version PL$patchlevel\n";
48 ©right'init($copyright) if -f $copyright;
50 system 'mkdir', 'bugs' unless -d 'bugs';
52 if (-f 'patchlevel.h') {
53 open(PL,"patchlevel.h") || die "$progname: can't open patchlevel.h: $!\n";
55 $bnum = $1 if /^#define\s+PATCHLEVEL\s+(\d+)/;
57 die "$progname: malformed patchlevel.h file.\n" if $bnum eq '';
64 open(MANI,"MANIFEST.new") || die "$progname: can't read MANIFEST.new: $!\n";
75 foreach $file (@ARGV) {
76 next if ($file =~ /^patchlevel.h$/); # Skip patchlevel.h
78 print "$progname: $file not found.\n";
81 $files = &rcsargs($file);
82 @files = split(' ',$files);
85 $rlog = `rlog -rlastpat- $files 2>&1`;
86 ($lastpat) = ($rlog =~ /lastpat: ([\d.]+)/);
87 ($revs) = ($rlog =~ /selected revisions: (\d+)/);
89 print "$progname: no cil has been done on $file.\n" ;;
90 } elsif ($revs == 1) {
91 ($base) = ($rlog =~ /.*\nrevision\s+(\S+)/);
92 ($a,$b,$c,$d) = split(/\./,$base);
96 "$progname: no changes in $file since last patch. (Did you cil it?)\n";
97 next; # Skip file with no changes
103 $rlog = `rlog -r$revbranch- $files 2>&1`;
104 ($revs) = ($rlog =~ /selected revisions: (\d+)/);
107 "$progname: no changes in $file since base version. (Did you cil it?)\n";
108 next; # Skip file with no changes
110 ($new) = ($rlog =~ /\nrevision\s*(\d+\.\d+\.\d+\.\d+)/);
114 ($new) = ($rlog =~ /\nrevision\s*(\d+\.\d+\.\d+\.\d+)/);
117 ($fname = $file) =~ s|.*/||;
118 $fname = substr($fname, 0, 11); # For filsystems with short names
119 open(PATCH,">>bugs/$fname.$bnum") || die "Can't make patch";
120 print PATCH "\nIndex: $file\n";
121 open(CO,"co -p -rlastpat $files 2>/dev/null |");
123 if (/\$Header/ || /\$Id/) {
124 print PATCH "Prereq: $lastpat\n";
131 open(DIFF,"rcsdiff -c -rlastpat -r$new $files |") ||
132 die "$progname: can't fork rcsdiff: $!\n";
134 if ($. == 1) {s|\*\*\* \S+ |*** $file.old |;}
135 if ($. == 2) {s|--- \S+ |--- $file |;}
136 s|Lock[e]r:.*\$|\$|; # Use [e] to make it safe on itself
140 system 'rcs', "-Nlastpat:$new", @files;
142 ©right'expand("co -p -rlastpat $file", "/tmp/pdo$$");
143 ©right'expand("co -p -r$new $file", "/tmp/pdn$$");
144 open(DIFF, "$mydiff /tmp/pdo$$ /tmp/pdn$$ |") ||
145 die "Can't run $mydiff";
146 while (<DIFF>) { # Contextual or unified diff
148 s|\*\*\* \S+ |*** $file.old | ||
149 s|--- \S+ |--- $file.old |;
152 s|--- \S+ |--- $file | ||
153 s|\+\+\+ \S+ |+++ $file |;
155 s|Lock[e]r:.*\$|\$|; # Remove locker mark
159 system 'rcs', "-Nlastpat:$new", @files;
160 unlink "/tmp/pdn$$", "/tmp/pdo$$";
164 open(DIFF,"rcsdiff -c -rlastpat $files |") ||
165 die "Can't run rcsdiff";
167 if ($. == 1) {s|\*\*\* \S+ |*** $file.old |;}
168 if ($. == 2) {s|--- \S+ |--- $file |;}
169 s|Lock[e]r:.*\$|\$|; # Remove locker mark
174 system "co -p -rlastpat $files >/tmp/pdo$$";
175 system "cp $file /tmp/pdn$$";
176 open(DIFF, "$mydiff /tmp/pdo$$ /tmp/pdn$$ |") ||
177 die "$progname: can't fork $mydiff: $!\n";
179 # Contextual or unified diff
181 s|\*\*\* \S+ |*** $file.old |;
182 s|--- \S+ |--- $file.old |;
185 s|--- \S+ |--- $file |;
186 s|\+\+\+ \S+ |+++ $file |;
188 s|Lock[e]r:.*\$|\$|; # Remove locker mark
192 unlink "/tmp/pdn$$", "/tmp/pdo$$";
200 Usage: $progname [-ahnV] [filelist]
201 -a : all the files in MANIFEST.new
202 -h : print this message and exit
204 -V : print version number and exit
210 if (! -f '.package') {
213 -f '../../.package' ||
214 -f '../../../.package' ||
215 -f '../../../../.package'
217 die "Run in top level directory only.\n";
219 die "No .package file! Run packinit.\n";
222 open(PACKAGE,'.package');
226 if (($var,$val) = /^\s*(\w+)=(.*)/) {
227 $val = "\"$val\"" unless $val =~ /^['"]/;
228 eval "\$$var = $val;";
237 while ($_ = shift(@_)) {
240 } elsif ($#_ >= 0 && do equiv($_,$_[0])) {
241 $result .= $_ . ' ' . $_[0] . ' ';
244 $result .= $_ . ' ' . do other($_) . ' ';
251 local($s1, $s2) = @_;
256 } elsif ($s1 =~ s/$RCSEXT$// || $s2 =~ s/$RCSEXT$//) {
265 ($dir,$file) = ('./',$s1) unless local($dir,$file) = ($s1 =~ m|(.*/)(.*)|);
266 $dir = $TOPDIR . $dir if -d $TOPDIR . "$dir/RCS";
267 local($wasrcs) = ($file =~ s/$RCSEXT$//);
269 `mkdir $dir` unless -d $dir;
273 `mkdir $dir` unless -d $dir;
281 # Read in copyright file
283 local($file) = @_; # Copyright file
285 open(COPYRIGHT, $file) || die "Can't open $file: $!\n";
286 chop(@copyright = <COPYRIGHT>);
290 # Reset the automaton for a new file.
292 $copyright_seen = @copyright ? 0 : 1;
296 # Filter file, line by line, and expand the copyright string. The @COPYRIGHT@
297 # symbol may be preceded by some random comment. A leader can be defined and
298 # will be pre-pended to all the input lines.
300 local($line, $leader) = @_; # Leader is optional
301 return $leader . $line if $copyright_seen || $marker_seen;
302 $marker_seen = 1 if $line =~ /\$Log[:\$]/;
303 $copyright_seen = 1 if $line =~ /\@COPYRIGHT\@/;
304 return $leader . $line unless $copyright_seen;
305 local($comment, $trailer) = $line =~ /^(.*)\@COPYRIGHT\@\s*(.*)/;
306 $comment = $leader . $comment;
307 $comment . join("\n$comment", @copyright) . "\n";
310 # Filter output of $cmd redirected into $file by expanding copyright, if any.
312 local($cmd, $file) = @_;
314 open(CMD,"$cmd|") || die "Can't start '$cmd': $!\n";
315 open(OUT, ">$file") || die "Can't create $file: $!\n";
319 print OUT &filter($_);
324 system "$cmd > $file";
325 die "Command '$cmd' failed!" if $?;
331 # Perform ~name expansion ala ksh...
332 # (banish csh from your vocabulary ;-)
335 return $path unless $path =~ /^~/;
336 $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
337 $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~
341 # Set up profile components into %Profile, add any profile-supplied options
342 # into @ARGV and return the command invocation name.
344 local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile');
345 local($me) = $0; # Command name
346 $me =~ s|.*/(.*)|$1|; # Keep only base name
347 return $me unless -s $profile;
348 local(*PROFILE); # Local file descriptor
349 local($options) = ''; # Options we get back from profile
350 unless (open(PROFILE, $profile)) {
351 warn "$me: cannot open $profile: $!\n";
357 next if /^\s*#/; # Skip comments
359 if (s/^$me://o) { # progname: options
361 $options .= $_; # Merge options if more than one line
363 elsif (s/^$me-([^:]+)://o) { # progname-component: value
366 s/^\s+//; # Trim leading and trailing spaces
368 $Profile{$component} = $_;
372 return unless $options;
373 require 'shellwords.pl';
375 eval '@opts = &shellwords($options)'; # Protect against mismatched quotes
376 unshift(@ARGV, @opts);
377 return $me; # Return our invocation name