This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix two podchecker errors on perlunicode.pod
[perl5.git] / pod / buildtoc
... / ...
CommitLineData
1#!/usr/bin/perl -w
2
3use strict;
4use vars qw($masterpodfile %Build %Targets $Verbose $Quiet %Ignore
5 @Master %Readmes %Pods %Aux %Readmepods %Pragmata %Modules
6 %Copies %Generated $Test);
7use File::Spec;
8use File::Find;
9use FindBin;
10use Text::Tabs;
11use Text::Wrap;
12use Getopt::Long;
13use Carp;
14
15no locale;
16require 5.010;
17
18{
19 my $Top = File::Spec->catdir($FindBin::Bin, File::Spec->updir);
20
21 sub abs_from_top {
22 my $path = shift;
23 return File::Spec->catdir($Top, split /\//, $path) if $path =~ s!/\z!!;
24 return File::Spec->catfile($Top, split /\//, $path);
25 }
26}
27
28# make it clearer when we haven't run to completion, as we can be quite
29# noisy when things are working ok
30
31sub my_die {
32 print STDERR "$0: ", @_;
33 print STDERR "\n" unless $_[-1] =~ /\n\z/;
34 print STDERR "ABORTED\n";
35 exit 255;
36}
37
38
39$masterpodfile = abs_from_top('pod.lst');
40
41# Generate any/all of these files
42# --verbose gives slightly more output
43# --quiet suppresses routine warnings
44# --build-all tries to build everything
45# --build-foo updates foo as follows
46# --showfiles shows the files to be changed
47# --test exit if perl.pod, pod.lst, MANIFEST are consistent, and regenerated
48# files are up to date, die otherwise.
49
50%Targets
51 = (
52 toc => 'pod/perltoc.pod',
53 manifest => 'MANIFEST',
54 perlpod => 'pod/perl.pod',
55 vms => 'vms/descrip_mms.template',
56 nmake => 'win32/Makefile',
57 dmake => 'win32/makefile.mk',
58 podmak => 'win32/pod.mak',
59 # plan9 => 'plan9/mkfile'),
60 unix => 'Makefile.SH',
61 # TODO: add roffitall
62 );
63
64foreach (values %Targets) {
65 $_ = abs_from_top($_);
66}
67
68# process command-line switches
69
70{
71 my @files = keys %Targets;
72 my $filesopts = join(" | ", map { "--build-$_" } "all", sort @files);
73 my $showfiles;
74 my %build_these;
75 die <<__USAGE__
76$0: Usage: $0 [--verbose] [--showfiles] $filesopts
77__USAGE__
78 unless @ARGV
79 && GetOptions (verbose => \$Verbose,
80 quiet => \$Quiet,
81 showfiles => \$showfiles,
82 test => \$Test,
83 map {+"build-$_", \$build_these{$_}} @files, 'all');
84 if ($build_these{all}) {
85 %Build = %Targets;
86 } else {
87 while (my ($file, $want) = each %build_these) {
88 $Build{$file} = $Targets{$file} if $want;
89 }
90 }
91 if ($showfiles) {
92 print
93 join(" ",
94 sort { lc $a cmp lc $b }
95 map {
96 my ($v, $d, $f) = File::Spec->splitpath($_);
97 my @d;
98 @d = defined $d ? File::Spec->splitdir($d) : ();
99 shift @d if @d;
100 File::Spec->catfile(@d ?
101 (@d == 1 && $d[0] eq '' ? () : @d)
102 : "pod", $f);
103 } @Targets{@files}),
104 "\n";
105 exit(0);
106 }
107}
108
109# Don't copy these top level READMEs
110%Ignore
111 = (
112 micro => 1,
113# vms => 1,
114 );
115
116if ($Verbose) {
117 print "I will be building $_\n" foreach keys %Build;
118}
119
120my $delta_target;
121
122{
123 my $source = 'perldelta.pod';
124 my $filename = abs_from_top("pod/$source");
125 open my $fh, '<', $filename or my_die "Can't open $filename: $!";
126 local $/;
127 my $contents = <$fh>;
128 my @want =
129 $contents =~ /perldelta - what is new for perl v5\.(\d+)\.(\d+)\n/;
130 die "Can't extract version from $filename" unless @want;
131 $delta_target = "perl5$want[0]$want[1]delta.pod";
132
133 # This way round so that keys can act as a MANIFEST skip list
134 # Targets will always be in the pod directory. Currently we can only cope
135 # with sources being in the same directory.
136 $Copies{$delta_target} = $source;
137}
138
139# process pod.lst
140
141open my $master, '<', $masterpodfile or my_die "Can't open $masterpodfile: $!";
142
143foreach (<$master>) {
144 next if /^\#/;
145
146 # At least one upper case letter somewhere in the first group
147 if (/^(\S+)\s(.*)/ && $1 =~ tr/h//) {
148 # it's a heading
149 my $flags = $1;
150 $flags =~ tr/h//d;
151 my %flags = (header => 1);
152 $flags{toc_omit} = 1 if $flags =~ tr/o//d;
153 $flags{aux} = 1 if $flags =~ tr/a//d;
154 my_die "Unknown flag found in heading line: $_" if length $flags;
155 push @Master, [\%flags, $2];
156
157 } elsif (/^(\S*)\s+(\S+)\s+(.*)/) {
158 # it's a section
159 my ($flags, $filename, $desc) = ($1, $2, $3);
160
161 my %flags = (indent => 0);
162 $flags{indent} = $1 if $flags =~ s/(\d+)//;
163 $flags{toc_omit} = 1 if $flags =~ tr/o//d;
164 $flags{aux} = 1 if $flags =~ tr/a//d;
165 $flags{perlpod_omit} = "$filename.pod" eq $delta_target;
166
167 $Generated{"$filename.pod"}++ if $flags =~ tr/g//d;
168
169 if ($flags =~ tr/r//d) {
170 my $readme = $filename;
171 $readme =~ s/^perl//;
172 $Readmepods{$filename} = $Readmes{$readme} = $desc;
173 $flags{readme} = 1;
174 } elsif ($flags{aux}) {
175 $Aux{$filename} = $desc;
176 } else {
177 $Pods{$filename} = $desc;
178 }
179 my_die "Unknown flag found in section line: $_" if length $flags;
180 push @Master, [\%flags, $filename, $desc];
181 } elsif (/^$/) {
182 push @Master, undef;
183 } else {
184 my_die "Malformed line: $_" if $1 =~ tr/A-Z//;
185 }
186}
187
188close $master;
189
190# Sanity cross check
191{
192 my (%disk_pods, @disk_pods);
193 my (@manipods, %manipods);
194 my (@manireadmes, %manireadmes);
195 my (@perlpods, %perlpods);
196 my (%our_pods);
197
198 # Convert these to a list of filenames.
199 foreach (keys %Pods, keys %Readmepods) {
200 $our_pods{"$_.pod"}++;
201 }
202
203 opendir my $dh, abs_from_top('pod/');
204 while (defined ($_ = readdir $dh)) {
205 next unless /\.pod\z/;
206 push @disk_pods, $_;
207 ++$disk_pods{$_};
208 }
209
210 # Things we copy from won't be in perl.pod
211 # Things we copy to won't be in MANIFEST
212
213 my $filename = abs_from_top('MANIFEST');
214 open my $mani, '<', $filename or my_die "opening $filename failed: $!";
215 while (<$mani>) {
216 if (m!^pod/([^.]+\.pod)\s+!i) {
217 push @manipods, $1;
218 } elsif (m!^README\.(\S+)\s+!i) {
219 next if $Ignore{$1};
220 push @manireadmes, "perl$1.pod";
221 }
222 }
223 close $mani or my_die "close MANIFEST: $!\n";
224 @manipods{@manipods} = @manipods;
225 @manireadmes{@manireadmes} = @manireadmes;
226
227 $filename = abs_from_top('pod/perl.pod');
228 open my $perlpod, '<', $filename or my_die "opening $filename failed: $!\n";
229 while (<$perlpod>) {
230 if (/^For ease of access, /../^\(If you're intending /) {
231 if (/^\s+(perl\S*)\s+\w/) {
232 push @perlpods, "$1.pod";
233 }
234 }
235 }
236 close $perlpod or my_die "close perlpod: $!\n";
237 my_die "could not find the pod listing of perl.pod\n"
238 unless @perlpods;
239 @perlpods{@perlpods} = @perlpods;
240
241 my @inconsistent;
242 foreach my $i (sort keys %disk_pods) {
243 push @inconsistent, "$0: $i exists but is unknown by buildtoc\n"
244 unless $our_pods{$i};
245 push @inconsistent, "$0: $i exists but is unknown by ../MANIFEST\n"
246 if !$manipods{$i} && !$manireadmes{$i} && !$Copies{$i} && !$Generated{$i};
247 push @inconsistent, "$0: $i exists but is unknown by perl.pod\n"
248 if !$perlpods{$i} && !exists $Copies{$i};
249 }
250 my %BuildFiles;
251 foreach my $path (values %Build) {
252 (undef, undef, my $file) = File::Spec->splitpath($path);
253 ++$BuildFiles{$file}
254 }
255
256 foreach my $i (sort keys %our_pods) {
257 push @inconsistent, "$0: $i is known by buildtoc but does not exist\n"
258 unless $disk_pods{$i} or $BuildFiles{$i};
259 }
260 foreach my $i (sort keys %manipods) {
261 push @inconsistent, "$0: $i is known by ../MANIFEST but does not exist\n"
262 unless $disk_pods{$i};
263 push @inconsistent, "$0: $i is known by ../MANIFEST but is marked as generated\n"
264 if $Generated{$i};
265 }
266 foreach my $i (sort keys %perlpods) {
267 push @inconsistent, "$0: $i is known by perl.pod but does not exist\n"
268 unless $disk_pods{$i} or $BuildFiles{$i};
269 }
270 if ($Test) {
271 delete $Build{toc};
272 printf "1..%d\n", 1 + scalar keys %Build;
273 if (@inconsistent) {
274 print "not ok 1\n";
275 die @inconsistent
276 }
277 print "ok 1\n";
278 }
279 else {
280 warn @inconsistent if @inconsistent;
281 }
282}
283
284# Find all the modules
285if ($Build{toc}) {
286 my @modpods;
287 find \&getpods => abs_from_top('lib/');
288
289 sub getpods {
290 if (/\.p(od|m)$/) {
291 my $file = $File::Find::name;
292 return if $file =~ qr!/lib/Pod/Functions.pm\z!; # Used only by pod itself
293 return if $file =~ m!(?:^|/)t/!;
294 return if $file =~ m!lib/Attribute/Handlers/demo/!;
295 return if $file =~ m!lib/Net/FTP/.+\.pm!; # Hi, Graham! :-)
296 return if $file =~ m!lib/Math/BigInt/t/!;
297 return if $file =~ m!/Devel/PPPort/[Hh]arness|lib/Devel/Harness!i;
298 return if $file =~ m!XS/(?:APItest|Typemap)!;
299 my $pod = $file;
300 return if $pod =~ s/pm$/pod/ && -e $pod;
301 unless (open my $f, '<', $_) {
302 warn "$0: bogus <$file>: $!";
303 system "ls", "-l", $file;
304 }
305 else {
306 my $line;
307 while ($line = <$f>) {
308 if ($line =~ /^=head1\s+NAME\b/) {
309 push @modpods, $file;
310 return;
311 }
312 }
313 warn "$0: NOTE: cannot find '=head1 NAME' in:\n $file\n" unless $Quiet;
314 }
315 }
316 }
317
318 my_die "Can't find any pods!\n" unless @modpods;
319
320 my %done;
321 for (@modpods) {
322 my $name = $_;
323 $name =~ s/\.p(m|od)$//;
324 $name =~ s-.*?/lib/--;
325 $name =~ s-/-::-g;
326 next if $done{$name}++;
327
328 if ($name =~ /^[a-z]/) {
329 $Pragmata{$name} = $_;
330 } else {
331 $Modules{$name} = $_;
332 }
333 }
334}
335
336# OK. Now a lot of ancillary function definitions follow
337# Main program returns at "Do stuff"
338
339my $OUT;
340
341sub do_toc {
342 my $filename = shift;
343
344 ($_= <<"EOPOD2B") =~ s/^\t//gm and $OUT .= $_;
345
346 # !!!!!!! DO NOT EDIT THIS FILE !!!!!!!
347 # This file is autogenerated by buildtoc from all the other pods.
348 # Edit those files and run buildtoc --build-toc to effect changes.
349
350 =head1 NAME
351
352 perltoc - perl documentation table of contents
353
354 =head1 DESCRIPTION
355
356 This page provides a brief table of contents for the rest of the Perl
357 documentation set. It is meant to be scanned quickly or grepped
358 through to locate the proper section you're looking for.
359
360 =head1 BASIC DOCUMENTATION
361
362EOPOD2B
363#' make emacs happy
364
365 # All the things in the master list that happen to be pod filenames
366 foreach (grep {defined $_ && @$_ == 3 && !$_->[0]{toc_omit}} @Master) {
367 podset($_->[1], abs_from_top("pod/$_->[1].pod"));
368 }
369
370
371 ($_= <<"EOPOD2B") =~ s/^\t//gm and $OUT .= $_;
372
373
374
375 =head1 PRAGMA DOCUMENTATION
376
377EOPOD2B
378
379 foreach (sort keys %Pragmata) {
380 podset($_, $Pragmata{$_});
381 }
382
383 ($_= <<"EOPOD2B") =~ s/^\t//gm and $OUT .= $_;
384
385
386
387 =head1 MODULE DOCUMENTATION
388
389EOPOD2B
390
391 foreach (sort keys %Modules) {
392 podset($_, $Modules{$_});
393 }
394
395 $_= <<"EOPOD2B";
396
397
398 =head1 AUXILIARY DOCUMENTATION
399
400 Here should be listed all the extra programs' documentation, but they
401 don't all have manual pages yet:
402
403 =over 4
404
405EOPOD2B
406
407 $_ .= join "\n", map {"\t=item $_\n"} sort keys %Aux;
408 $_ .= <<"EOPOD2B" ;
409
410 =back
411
412 =head1 AUTHOR
413
414 Larry Wall <F<larry\@wall.org>>, with the help of oodles
415 of other folks.
416
417
418EOPOD2B
419
420 s/^\t//gm;
421 $OUT .= "$_\n";
422
423 $OUT =~ s/\n\s+\n/\n\n/gs;
424 $OUT =~ s/\n{3,}/\n\n/g;
425
426 $OUT =~ s/([^\n]+)/wrap('', '', $1)/ge;
427
428 return $OUT;
429}
430
431# Below are all the auxiliary routines for generating perltoc.pod
432
433my ($inhead1, $inhead2, $initem);
434
435sub podset {
436 my ($pod, $file) = @_;
437
438 local $/ = '';
439
440 open my $fh, '<', $file or my_die "Can't open file '$file' for $pod: $!";
441
442 while(<$fh>) {
443 tr/\015//d;
444 if (s/^=head1 (NAME)\s*/=head2 /) {
445 unhead1();
446 $OUT .= "\n\n=head2 ";
447 $_ = <$fh>;
448 # Remove svn keyword expansions from the Perl FAQ
449 s/ \(\$Revision: \d+ \$\)//g;
450 if ( /^\s*\Q$pod\E\b/ ) {
451 s/$pod\.pm/$pod/; # '.pm' in NAME !?
452 } else {
453 s/^/$pod, /;
454 }
455 }
456 elsif (s/^=head1 (.*)/=item $1/) {
457 unhead2();
458 $OUT .= "=over 4\n\n" unless $inhead1;
459 $inhead1 = 1;
460 $_ .= "\n";
461 }
462 elsif (s/^=head2 (.*)/=item $1/) {
463 unitem();
464 $OUT .= "=over 4\n\n" unless $inhead2;
465 $inhead2 = 1;
466 $_ .= "\n";
467 }
468 elsif (s/^=item ([^=].*)/$1/) {
469 next if $pod eq 'perldiag';
470 s/^\s*\*\s*$// && next;
471 s/^\s*\*\s*//;
472 s/\n/ /g;
473 s/\s+$//;
474 next if /^[\d.]+$/;
475 next if $pod eq 'perlmodlib' && /^ftp:/;
476 $OUT .= ", " if $initem;
477 $initem = 1;
478 s/\.$//;
479 s/^-X\b/-I<X>/;
480 }
481 else {
482 unhead1() if /^=cut\s*\n/;
483 next;
484 }
485 $OUT .= $_;
486 }
487}
488
489sub unhead1 {
490 unhead2();
491 if ($inhead1) {
492 $OUT .= "\n\n=back\n\n";
493 }
494 $inhead1 = 0;
495}
496
497sub unhead2 {
498 unitem();
499 if ($inhead2) {
500 $OUT .= "\n\n=back\n\n";
501 }
502 $inhead2 = 0;
503}
504
505sub unitem {
506 if ($initem) {
507 $OUT .= "\n\n";
508 }
509 $initem = 0;
510}
511
512# End of original buildtoc. From here on are routines to generate new sections
513# for and inplace edit other files
514
515sub generate_perlpod {
516 my @output;
517 my $maxlength = 0;
518 foreach (@Master) {
519 my $flags = $_->[0];
520 next if $flags->{aux};
521 next if $flags->{perlpod_omit};
522
523 if (@$_ == 2) {
524 # Heading
525 push @output, "=head2 $_->[1]\n";
526 } elsif (@$_ == 3) {
527 # Section
528 my $start = " " x (4 + $flags->{indent}) . $_->[1];
529 $maxlength = length $start if length ($start) > $maxlength;
530 push @output, [$start, $_->[2]];
531 } elsif (@$_ == 0) {
532 # blank line
533 push @output, "\n";
534 } else {
535 my_die "Illegal length " . scalar @$_;
536 }
537 }
538 # want at least 2 spaces padding
539 $maxlength += 2;
540 $maxlength = ($maxlength + 3) & ~3;
541 # sprintf gives $1.....$2 where ... are spaces:
542 return unexpand (map {ref $_ ? sprintf "%-${maxlength}s%s\n", @$_ : $_}
543 @output);
544}
545
546
547sub generate_manifest {
548 # Annoyingly, unexpand doesn't consider it good form to replace a single
549 # space before a tab with a tab
550 # Annoyingly (2) it returns read only values.
551 my @temp = unexpand (map {sprintf "%-32s%s", @$_} @_);
552 map {s/ \t/\t\t/g; $_} @temp;
553}
554sub generate_manifest_pod {
555 generate_manifest map {["pod/$_.pod", $Pods{$_}]}
556 sort grep {!$Copies{"$_.pod"}} grep {!$Generated{"$_.pod"}} keys %Pods;
557}
558sub generate_manifest_readme {
559 generate_manifest sort {$a->[0] cmp $b->[0]}
560 ["README.vms", "Notes about installing the VMS port"],
561 map {["README.$_", $Readmes{$_}]} keys %Readmes;
562}
563
564sub generate_roffitall {
565 (map ({"\t\$maindir/$_.1\t\\"}sort keys %Pods),
566 "\t\t\\",
567 map ({"\t\$maindir/$_.1\t\\"}sort keys %Aux),
568 "\t\t\\",
569 map ({"\t\$libdir/$_.3\t\\"}sort keys %Pragmata),
570 "\t\t\\",
571 map ({"\t\$libdir/$_.3\t\\"}sort keys %Modules),
572 )
573}
574
575sub generate_descrip_mms_1 {
576 local $Text::Wrap::columns = 150;
577 my $count = 0;
578 my @lines = map {"pod" . $count++ . " = $_"}
579 split /\n/, wrap('', '', join " ", map "[.lib.pods]$_.pod",
580 sort keys %Pods, keys %Readmepods);
581 @lines, "pod = " . join ' ', map {"\$(pod$_)"} 0 .. $count - 1;
582}
583
584sub generate_descrip_mms_2 {
585 map {<<"SNIP"}
586[.lib.pods]$_.pod : [.pod]$_.pod
587 \@ If F\$Search("[.lib]pods.dir").eqs."" Then Create/Directory [.lib.pods]
588 Copy/NoConfirm/Log \$(MMS\$SOURCE) [.lib.pods]
589SNIP
590 sort keys %Pods, keys %Readmepods;
591}
592
593sub generate_nmake_1 {
594 # XXX Fix this with File::Spec
595 (map {sprintf "\tcopy ..\\README.%-8s ..\\pod\\perl$_.pod\n", $_}
596 sort keys %Readmes),
597 (map {"\tcopy ..\\pod\\$Copies{$_} ..\\pod\\$_\n"} sort keys %Copies);
598}
599
600# This doesn't have a trailing newline
601sub generate_nmake_2 {
602 # Spot the special case
603 local $Text::Wrap::columns = 76;
604 my $line = wrap ("\t ", "\t ",
605 join " ", sort keys %Copies, keys %Generated,
606 map {"perl$_.pod"} keys %Readmes);
607 $line =~ s/$/ \\/mg;
608 $line =~ s/ \\$//;
609 $line;
610}
611
612sub generate_pod_mak {
613 my $variable = shift;
614 my @lines;
615 my $line = join "\\\n", "\U$variable = ",
616 map {"\t$_.$variable\t"} sort keys %Pods;
617 # Special case
618 $line =~ s/.*perltoc.html.*\n//m;
619 $line;
620}
621
622sub verify_contiguous {
623 my ($name, $content, $what) = @_;
624 my $sections = () = $content =~ m/\0+/g;
625 croak("$0: $name contains no $what") if $sections < 1;
626 croak("$0: $name contains discontiguous $what") if $sections > 1;
627}
628
629sub do_manifest {
630 my ($name, $prev) = @_;
631 my @manifest =
632 grep {! m!^pod/[^.]+\.pod.*!}
633 grep {! m!^README\.(\S+)! || $Ignore{$1}} split "\n", $prev;
634 join "\n", (
635 # Dictionary order - fold and handle non-word chars as nothing
636 map { $_->[0] }
637 sort { $a->[1] cmp $b->[1] || $a->[0] cmp $b->[0] }
638 map { my $f = lc $_; $f =~ s/[^a-z0-9\s]//g; [ $_, $f ] }
639 @manifest,
640 &generate_manifest_pod(),
641 &generate_manifest_readme()), '';
642}
643
644sub do_nmake {
645 my ($name, $makefile) = @_;
646 $makefile =~ s/^\tcopy \.\.\\README.*\n/\0/gm;
647 verify_contiguous($name, $makefile, 'README copies');
648 # Now remove the other copies that follow
649 1 while $makefile =~ s/\0\tcopy .*\n/\0/gm;
650 $makefile =~ s/\0+/join ("", &generate_nmake_1)/se;
651
652 $makefile =~ s{(-cd \$\(PODDIR\) && del /f[^\n]+).*?(-cd \.\.\\utils && del /f)}
653 {"$1\n" . &generate_nmake_2."\n\t$2"}se;
654 $makefile;
655}
656
657# shut up used only once warning
658*do_dmake = *do_dmake = \&do_nmake;
659
660sub do_perlpod {
661 my ($name, $pod) = @_;
662
663 unless ($pod =~ s{(For\ ease\ of\ access,\ .*\n)
664 (?:\s+[a-z]{4,}.*\n # fooo
665 |=head.*\n # =head foo
666 |\s*\n # blank line
667 )+
668 }
669 {$1 . join "", &generate_perlpod}mxe) {
670 my_die "Failed to insert amendments in do_perlpod";
671 }
672 $pod;
673}
674
675sub do_podmak {
676 my ($name, $body) = @_;
677 foreach my $variable (qw(pod man html tex)) {
678 my_die "could not find $variable in $name"
679 unless $body =~ s{\n\U$variable\E = (?:[^\n]*\\\n)*[^\n]*}
680 {"\n" . generate_pod_mak ($variable)}se;
681 }
682 $body;
683}
684
685sub do_vms {
686 my ($name, $makefile) = @_;
687 $makefile =~ s/\npod\d* =[^\n]*/\0/gs;
688 verify_contiguous($name, $makefile, 'pod assignments');
689 $makefile =~ s/\0+/join "\n", '', &generate_descrip_mms_1/se;
690
691 my_die "$name contains NUL bytes" if $makefile =~ /\0/;
692
693# Looking for the macro defining the current perldelta:
694#PERLDELTA_CURRENT = [.pod]perl5139delta.pod
695
696 $makefile =~ s/\nPERLDELTA_CURRENT\s+=\s+\Q[.pod]perl\E\d+delta\.pod\n
697 /\0/sx;
698 verify_contiguous($name, $makefile, 'current perldelta macro');
699 $makefile =~ s/\0+/join "\n", '', "PERLDELTA_CURRENT = [.pod]$delta_target", ''/se;
700
701# Looking for rules like this
702# [.lib.pods]perl.pod : [.pod]perl.pod
703# @ If F$Search("[.lib]pods.dir").eqs."" Then Create/Directory [.lib.pods]
704# Copy/NoConfirm/Log $(MMS$SOURCE) [.lib.pods]
705
706 $makefile =~ s/\n\Q[.lib.pods]\Eperl[^\n\.]*\.pod[^\n]+\n
707 [^\n]+\n # Another line
708 [^\n]+\Q[.lib.pods]\E\n # ends [.lib.pods]
709 /\0/gsx;
710 verify_contiguous($name, $makefile, 'copy rules');
711 $makefile =~ s/\0+/join "\n", '', &generate_descrip_mms_2/se;
712
713 $makefile;
714}
715
716sub do_unix {
717 my ($name, $makefile_SH) = @_;
718
719 $makefile_SH =~ s{^(perltoc_pod_prereqs = extra.pods).*}
720 {join ' ', $1, map "pod/$_",
721 sort keys %Copies, grep {!/perltoc/} keys %Generated
722 }mge;
723
724# pod/perl511delta.pod: pod/perldelta.pod
725# cd pod && $(LNS) perldelta.pod perl511delta.pod
726
727 $makefile_SH =~ s!(
728pod/perl[a-z0-9_]+\.pod: pod/perl[a-z0-9_]+\.pod
729 \$\(LNS\) perl[a-z0-9_]+\.pod pod/perl[a-z0-9_]+\.pod
730)+!\0!gm;
731
732 verify_contiguous($name, $makefile_SH, 'copy rules');
733
734 my @copy_rules = map "
735pod/$_: pod/$Copies{$_}
736 \$(LNS) $Copies{$_} pod/$_
737", keys %Copies;
738
739 $makefile_SH =~ s/\0+/join '', @copy_rules/se;
740 $makefile_SH;
741
742}
743
744# Do stuff
745
746my $built;
747while (my ($target, $name) = each %Targets) {
748 print "Working on target $target\n" if $Verbose;
749 next unless $Build{$target};
750 $built++;
751 my ($orig, $mode);
752 print "Now processing $name\n" if $Verbose;
753 if ($target ne "toc") {
754 local $/;
755 open my $thing, '<', $name or my_die "Can't open $name: $!";
756 binmode $thing;
757 $orig = <$thing>;
758 my_die "$name contains NUL bytes" if $orig =~ /\0/;
759 }
760
761 my $new = do {
762 no strict 'refs';
763 &{"do_$target"}($target, $orig);
764 };
765
766 if (defined $orig) {
767 if ($new eq $orig) {
768 if ($Test) {
769 printf "ok %d # $name is up to date\n", $built + 1;
770 } elsif ($Verbose) {
771 print "Was not modified\n";
772 }
773 next;
774 } elsif ($Test) {
775 printf "not ok %d # $name is up to date\n", $built + 1;
776 next;
777 }
778 $mode = (stat $name)[2] // my_die "Can't stat $name: $!";
779 rename $name, "$name.old" or my_die "Can't rename $name to $name.old: $!";
780 }
781
782 open my $thing, '>', $name or my_die "Can't open $name for writing: $!";
783 binmode $thing;
784 print $thing $new or my_die "print to $name failed: $!";
785 close $thing or my_die "close $name failed: $!";
786 if (defined $mode) {
787 chmod $mode & 0777, $name or my_die "can't chmod $mode $name: $!";
788 }
789}
790
791warn "$0: was not instructed to build anything\n" unless $built || $Test;