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