This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add Configure probe for strtold_l
[metaconfig.git] / bin / patsend
CommitLineData
459d3fb5
MBT
1#!/usr/bin/perl
2 eval "exec perl -S $0 $*"
3 if $running_under_some_shell;
4
5# $Id: patsend.SH 1 2006-08-24 12:32:52Z rmanfredi $
6#
7# Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi
8#
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.
14#
15# Original Author: Larry Wall <lwall@netlabs.com>
16#
17# $Log: patsend.SH,v $
18# Revision 3.0.1.6 1995/09/25 09:22:02 ram
19# patch59: new -i option to add more instructions for end-users
20#
21# Revision 3.0.1.5 1994/01/24 14:32:46 ram
22# patch16: now prefix error messages with program's name
23# patch16: don't feed mailer with more than 50 addresses at a time
24# patch16: added ~/.dist_profile awareness
25#
26# Revision 3.0.1.4 1993/08/25 14:08:01 ram
27# patch6: now asks for recipient list edition by default
28# patch6: new -q option to suppress that
29#
30# Revision 3.0.1.3 1993/08/24 12:21:59 ram
31# patch3: new -u option
32# patch3: added Precedence and X-Mailer headers in mail message
33# patch3: added ~name expansion for orgname
34#
35# Revision 3.0.1.2 1993/08/19 07:10:19 ram
36# patch3: was not correctly writing the To: header field
37#
38# Revision 3.0.1.1 1993/08/19 06:42:42 ram
39# patch1: leading config.sh searching was not aborting properly
40#
41# Revision 3.0 1993/08/18 12:10:49 ram
42# Baseline for dist 3.0 netwide release.
43#
44
45$orgname='PROCURA B.V.';
46$mailer='/usr/sbin/sendmail';
47$version = '3.5';
48$patchlevel = '0';
49
50$progname = &profile; # Read ~/.dist_profile
51require 'getopts.pl';
52&usage unless &Getopts("hiquV");
53
54if ($opt_V) {
55 print STDERR "$progname $version PL$patchlevel\n";
56 exit 0;
57} elsif ($opt_h) {
58 &usage;
59}
60
61chdir '..' if -d '../bugs';
62
63&readpackage;
64&readusers if $opt_u;
65
66$orgname = &tilda_expand($orgname);
67chop($orgname = `cat $orgname`) if $orgname =~ m|^/|;
68
69while ($_ = shift) {
70 if (/^(patch)?[1-9][\d,-]*$/) {
71 s/^patch//;
72 push(@argv,$_);
73 } else {
74 push(@dest,$_);
75 }
76}
77$dest = join(' ',@dest);
78$dest .= " $recipients" if $opt_u;
79&usage unless $dest;
80
81# Offer to edit the address list unless -q
82unless ($opt_q) {
83 select((select(STDOUT), $| = 1)[0]);
84 print "Do you wish to edit the address list? [y] ";
85 $ans = <STDIN>;
86 unless ($ans =~ /^n/i) {
87 @to = split(' ', $dest);
88 &listedit(*to);
89 $dest = join(' ', @to);
90 }
91}
92
93$to = join(', ', split(' ', $dest));
94@ARGV = @argv;
95
96open(PL,"patchlevel.h") || die "$progname: can't open patchlevel.h: $!\n";
97while (<PL>) {
98 $maxnum = $1 if /^#define\s+PATCHLEVEL\s+(\d+)/;
99}
100close PL;
101die "$progname: malformed patchlevel.h file.\n" if $maxnum eq '';
102
103if ($#ARGV < 0) {
104 @patseq = &patseq($maxnum);
105 $lastpat = pop(@patseq);
106 $argv = &rangeargs("$lastpat-$maxnum");
107} else {
108 $argv = &rangeargs(@ARGV);
109}
110
111@ARGV = split(' ',$argv);
112$argv =~ s/ $//;
113
114if ($#ARGV < 0) {
115 print STDERR "$progname: no patches specified.\n";
116 &usage;
117} elsif ($#ARGV) {
118 print "$progname: sending $package $baserev patches $argv to $dest...\n";
119} else {
120 print "$progname: sending $package $baserev patch $argv to $dest...\n";
121}
122
123chdir 'bugs' || die "$progname: can't cd to bugs: $!\n";
124
125fork && exit;
126
127$opt = '-odq' if $mailer =~ /sendmail/;
128
129until ($#ARGV < 0) {
130 $patnum = shift;
131
132 # I hate broken mailers! Bust it up into smaller groups of people...
133 @dest = split(' ', $dest);
134 while (@smalldest = splice(@dest, 0, 50)) {
135 $to = join(', ', @smalldest); # Sensible To: for sendmail
136 $smalldest = join(' ', @smalldest);
137
138 open(MAILER, "|$mailer $opt $smalldest") ||
139 die "$progname: can't fork $mailer: $!\n";
140 print MAILER
141"To: $to
142Subject: $package $baserev patch #$patnum
143Precedence: bulk
144X-Mailer: dist [version $version PL$patchlevel]
145Organization: $orgname
146
147";
148 print MAILER
149"$package version $baserev has been recently upgraded with the following patch,
150which is being mailed directly to you as you requested when running Configure.
151
152If you are not interested in having future patches mailed directly to you,
153please send me the following mail:
154
155 Subject: Command
156 \@SH package - $package $baserev
157
158-- $progname speaking for $maintname <$maintloc>.
159
160" if ($opt_i || $opt_u);
161 print MAILER
162"[The latest patch for $package version $baserev is #$maxnum.]
163
164";
165 open(PATCH,"patch$patnum") ||
166 die "$progname: can't open patch$patnum: $!\n";
167 while (<PATCH>) {
168 print MAILER;
169 }
170 close PATCH;
171 close MAILER;
172 die "$progname: could not mail patch$patnum.\n" if $?;
173 }
174}
175
176sub usage {
177 print STDERR <<EOM;
178Usage: $progname [-hiquV] [patchlist] [recipients]
179 -h : print this message and exit
180 -i : include information on how to stop receiving future patches
181 -q : quick mode, do not offer to edit recipient list
182 -u : add all to-be-mailed users
183 -V : print version number and exit
184EOM
185 exit 1;
186}
187
188sub readpackage {
189 if (! -f '.package') {
190 if (
191 -f '../.package' ||
192 -f '../../.package' ||
193 -f '../../../.package' ||
194 -f '../../../../.package'
195 ) {
196 die "Run in top level directory only.\n";
197 } else {
198 die "No .package file! Run packinit.\n";
199 }
200 }
201 open(PACKAGE,'.package');
202 while (<PACKAGE>) {
203 next if /^:/;
204 next if /^#/;
205 if (($var,$val) = /^\s*(\w+)=(.*)/) {
206 $val = "\"$val\"" unless $val =~ /^['"]/;
207 eval "\$$var = $val;";
208 }
209 }
210 close PACKAGE;
211}
212
213sub rangeargs {
214 local($result) = '';
215 local($min,$max,$_);
216 open(PL,"patchlevel.h") || die "Can't open patchlevel.h\n";
217 while (<PL>) {
218 $maxspec = $1 if /^#define\s+PATCHLEVEL\s+(\d+)/;
219 }
220 close PL;
221 die "Malformed patchlevel.h file.\n" if $maxspec eq '';
222 while ($#_ >= 0) {
223 $_ = shift(@_);
224 while (/^\s*\d/) {
225 s/^\s*(\d+)//;
226 $min = $1;
227 if (s/^,//) {
228 $max = $min;
229 } elsif (s/^-(\d*)//) {
230 $max = $1;
231 if ($max == 0 && $maxspec) {
232 $max = $maxspec;
233 }
234 s/^[^,],?//;
235 } else {
236 $max = $min;
237 }
238 for ($i = $min; $i <= $max; ++$i) {
239 $result .= $i . ' ';
240 }
241 }
242 }
243 $result;
244}
245
246sub readusers {
247 return unless open(USERS, 'users');
248 local($_);
249 local($status, $name, $pl);
250 while (<USERS>) {
251 next if /^#/;
252 chop if /\n$/; # Emacs may leave final line without \n
253 ($status, $pl, $name) = split;
254 # Handle oldstyle two-field user file format (PL13 and before)
255 $name = $pl unless defined $name;
256 if ($status eq 'M') {
257 $recipients = $recipients ? "$recipients $name" : $name;
258 } elsif ($status eq 'N') {
259 $notify = $notify ? "$notify $name" : $name;
260 }
261 }
262 close USERS;
263}
264
265# Compute patch sequence by scanning the bugs directory and looking for
266# .logs and/or .mods files to determine what was the last issued patch series.
267sub patseq {
268 local($cur) = @_; # Current patch level
269 local(@seq); # Issued patch sequence
270 local($i);
271 for ($i = 1; $i <= $cur; $i++) {
272 push(@seq, $i) if -f "bugs/.logs$i" || -f "bugs/.mods$i";
273 }
274 @seq;
275}
276
277# Perform ~name expansion ala ksh...
278# (banish csh from your vocabulary ;-)
279sub tilda_expand {
280 local($path) = @_;
281 return $path unless $path =~ /^~/;
282 $path =~ s:^~([^/]+):(getpwnam($1))[$[+7]:e; # ~name
283 $path =~ s:^~:$ENV{'HOME'} || (getpwuid($<))[$[+7]:e; # ~
284 $path;
285}
286
287# Compute suitable editor name
288sub geteditor {
289 local($editor) = $ENV{'VISUAL'};
290 $editor = $ENV{'EDITOR'} unless $editor;
291 $editor = $defeditor unless $editor;
292 $editor = 'vi' unless $editor;
293 $editor;
294}
295
296# Allow user to inplace-edit a list of items held in an array
297sub listedit {
298 local(*list) = @_;
299 local($tmp) = "/tmp/dist.$$";
300 local($editor) = &geteditor;
301 open(TMP, ">$tmp") || die "Can't create $tmp: $!\n";
302 foreach $item (@list) {
303 print TMP $item, "\n";
304 }
305 close TMP;
306 system "$editor $tmp";
307 open(TMP, "$tmp") || die "Can't reopen $tmp: $!\n";
308 chop(@list = <TMP>);
309 close TMP;
310 unlink $tmp;
311}
312
313# Set up profile components into %Profile, add any profile-supplied options
314# into @ARGV and return the command invocation name.
315sub profile {
316 local($profile) = &tilda_expand($ENV{'DIST'} || '~/.dist_profile');
317 local($me) = $0; # Command name
318 $me =~ s|.*/(.*)|$1|; # Keep only base name
319 return $me unless -s $profile;
320 local(*PROFILE); # Local file descriptor
321 local($options) = ''; # Options we get back from profile
322 unless (open(PROFILE, $profile)) {
323 warn "$me: cannot open $profile: $!\n";
324 return;
325 }
326 local($_);
327 local($component);
328 while (<PROFILE>) {
329 next if /^\s*#/; # Skip comments
330 next unless /^$me/o;
331 if (s/^$me://o) { # progname: options
332 chop;
333 $options .= $_; # Merge options if more than one line
334 }
335 elsif (s/^$me-([^:]+)://o) { # progname-component: value
336 $component = $1;
337 chop;
338 s/^\s+//; # Trim leading and trailing spaces
339 s/\s+$//;
340 $Profile{$component} = $_;
341 }
342 }
343 close PROFILE;
344 return unless $options;
345 require 'shellwords.pl';
346 local(@opts);
347 eval '@opts = &shellwords($options)'; # Protect against mismatched quotes
348 unshift(@ARGV, @opts);
349 return $me; # Return our invocation name
350}
351