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
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
159 my ($flags, $filename, $desc) = ($1, $2, $3);
160
161 my %flags = (indent => 0);
162 $flags{indent} = $1 if $flags =~ s/(\d+)//;
b0b6bf2b 163 $flags{toc_omit} = 1 if $flags =~ tr/o//d;
41630250 164 $flags{aux} = 1 if $flags =~ tr/a//d;
88fb56ec 165 $flags{perlpod_omit} = "$filename.pod" eq $delta_target;
b0b6bf2b 166
344af494 167 $Generated{"$filename.pod"}++ if $flags =~ tr/g//d;
b0b6bf2b 168
41630250
JH
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 }
ce9f0d31 179 my_die "Unknown flag found in section line: $_" if length $flags;
41630250
JH
180 push @Master, [\%flags, $filename, $desc];
181 } elsif (/^$/) {
182 push @Master, undef;
183 } else {
ce9f0d31 184 my_die "Malformed line: $_" if $1 =~ tr/A-Z//;
41630250
JH
185 }
186}
187
bac61051 188close $master;
41630250
JH
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
d5e2eea9 203 opendir my $dh, abs_from_top('pod/');
d0f3b1ad 204 while (defined ($_ = readdir $dh)) {
d5e2eea9
NC
205 next unless /\.pod\z/;
206 push @disk_pods, $_;
207 ++$disk_pods{$_};
208 }
41630250 209
b0b6bf2b
AT
210 # Things we copy from won't be in perl.pod
211 # Things we copy to won't be in MANIFEST
b0b6bf2b 212
d5e2eea9 213 my $filename = abs_from_top('MANIFEST');
ce9f0d31 214 open my $mani, '<', $filename or my_die "opening $filename failed: $!";
d5e2eea9 215 while (<$mani>) {
41630250
JH
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 }
ce9f0d31 223 close $mani or my_die "close MANIFEST: $!\n";
41630250
JH
224 @manipods{@manipods} = @manipods;
225 @manireadmes{@manireadmes} = @manireadmes;
226
d5e2eea9 227 $filename = abs_from_top('pod/perl.pod');
ce9f0d31 228 open my $perlpod, '<', $filename or my_die "opening $filename failed: $!\n";
d5e2eea9 229 while (<$perlpod>) {
41630250
JH
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 }
ce9f0d31
DM
236 close $perlpod or my_die "close perlpod: $!\n";
237 my_die "could not find the pod listing of perl.pod\n"
41630250
JH
238 unless @perlpods;
239 @perlpods{@perlpods} = @perlpods;
240
d89d11bb 241 my @inconsistent;
41630250 242 foreach my $i (sort keys %disk_pods) {
d89d11bb 243 push @inconsistent, "$0: $i exists but is unknown by buildtoc\n"
41630250 244 unless $our_pods{$i};
d89d11bb 245 push @inconsistent, "$0: $i exists but is unknown by ../MANIFEST\n"
344af494 246 if !$manipods{$i} && !$manireadmes{$i} && !$Copies{$i} && !$Generated{$i};
d89d11bb 247 push @inconsistent, "$0: $i exists but is unknown by perl.pod\n"
81e1aac7 248 if !$perlpods{$i} && !exists $Copies{$i};
41630250 249 }
78fb583c 250 my %BuildFiles;
b5f0cad0
RB
251 foreach my $path (values %Build) {
252 (undef, undef, my $file) = File::Spec->splitpath($path);
253 ++$BuildFiles{$file}
254 }
81e1aac7 255
41630250 256 foreach my $i (sort keys %our_pods) {
d89d11bb 257 push @inconsistent, "$0: $i is known by buildtoc but does not exist\n"
78fb583c 258 unless $disk_pods{$i} or $BuildFiles{$i};
41630250
JH
259 }
260 foreach my $i (sort keys %manipods) {
d89d11bb 261 push @inconsistent, "$0: $i is known by ../MANIFEST but does not exist\n"
41630250 262 unless $disk_pods{$i};
d89d11bb 263 push @inconsistent, "$0: $i is known by ../MANIFEST but is marked as generated\n"
344af494 264 if $Generated{$i};
41630250
JH
265 }
266 foreach my $i (sort keys %perlpods) {
d89d11bb 267 push @inconsistent, "$0: $i is known by perl.pod but does not exist\n"
78fb583c 268 unless $disk_pods{$i} or $BuildFiles{$i};
41630250 269 }
d89d11bb 270 if ($Test) {
5733ee18
NC
271 delete $Build{toc};
272 printf "1..%d\n", 1 + scalar keys %Build;
d89d11bb
TC
273 if (@inconsistent) {
274 print "not ok 1\n";
275 die @inconsistent
276 }
277 print "ok 1\n";
d89d11bb
TC
278 }
279 else {
280 warn @inconsistent if @inconsistent;
281 }
41630250
JH
282}
283
0b01631d 284# Find all the modules
15e75242 285if ($Build{toc}) {
41630250 286 my @modpods;
9a8cc8a4 287 find \&getpods => abs_from_top('lib/');
41630250
JH
288
289 sub getpods {
290 if (/\.p(od|m)$/) {
291 my $file = $File::Find::name;
d5e2eea9 292 return if $file =~ qr!/lib/Pod/Functions.pm\z!; # Used only by pod itself
41630250
JH
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)!;
be6d6286
HS
299 my $pod = $file;
300 return if $pod =~ s/pm$/pod/ && -e $pod;
bac61051 301 unless (open my $f, '<', $_) {
41630250
JH
302 warn "$0: bogus <$file>: $!";
303 system "ls", "-l", $file;
304 }
305 else {
306 my $line;
bac61051 307 while ($line = <$f>) {
41630250
JH
308 if ($line =~ /^=head1\s+NAME\b/) {
309 push @modpods, $file;
41630250
JH
310 return;
311 }
312 }
3533364a 313 warn "$0: NOTE: cannot find '=head1 NAME' in:\n $file\n" unless $Quiet;
41630250
JH
314 }
315 }
316 }
317
ce9f0d31 318 my_die "Can't find any pods!\n" unless @modpods;
41630250
JH
319
320 my %done;
321 for (@modpods) {
11eb54fe
NC
322 my $name = $_;
323 $name =~ s/\.p(m|od)$//;
324 $name =~ s-.*?/lib/--;
325 $name =~ s-/-::-g;
3eb77e4b
NC
326 next if $done{$name}++;
327
41630250
JH
328 if ($name =~ /^[a-z]/) {
329 $Pragmata{$name} = $_;
330 } else {
41630250
JH
331 $Modules{$name} = $_;
332 }
333 }
334}
335
8537f021 336# OK. Now a lot of ancillary function definitions follow
41630250
JH
337# Main program returns at "Do stuff"
338
d871876a
NC
339my $OUT;
340
02cc404a 341sub do_toc {
d5e2eea9 342 my $filename = shift;
41630250 343
c0f8aaaa 344 ($_= <<"EOPOD2B") =~ s/^\t//gm and $OUT .= $_;
41630250 345
97f32038
JH
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.
97f32038 349
41630250
JH
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
84f07fb2 366 foreach (grep {defined $_ && @$_ == 3 && !$_->[0]{toc_omit}} @Master) {
d5e2eea9 367 podset($_->[1], abs_from_top("pod/$_->[1].pod"));
84f07fb2 368 }
41630250
JH
369
370
c0f8aaaa 371 ($_= <<"EOPOD2B") =~ s/^\t//gm and $OUT .= $_;
41630250
JH
372
373
374
375 =head1 PRAGMA DOCUMENTATION
376
377EOPOD2B
378
84f07fb2
NC
379 foreach (sort keys %Pragmata) {
380 podset($_, $Pragmata{$_});
381 }
41630250 382
c0f8aaaa 383 ($_= <<"EOPOD2B") =~ s/^\t//gm and $OUT .= $_;
41630250
JH
384
385
386
387 =head1 MODULE DOCUMENTATION
388
389EOPOD2B
390
84f07fb2
NC
391 foreach (sort keys %Modules) {
392 podset($_, $Modules{$_});
393 }
41630250
JH
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;
c0f8aaaa 421 $OUT .= "$_\n";
d871876a 422
39440e4b 423 $OUT =~ s/\n\s+\n/\n\n/gs;
f20404e1 424 $OUT =~ s/\n{3,}/\n\n/g;
b8ce93b8
NC
425
426 $OUT =~ s/([^\n]+)/wrap('', '', $1)/ge;
427
02cc404a 428 return $OUT;
41630250
JH
429}
430
431# Below are all the auxiliary routines for generating perltoc.pod
432
433my ($inhead1, $inhead2, $initem);
434
435sub podset {
84f07fb2 436 my ($pod, $file) = @_;
41630250 437
536d7404
NC
438 local $/ = '';
439
ce9f0d31 440 open my $fh, '<', $file or my_die "Can't open file '$file' for $pod: $!";
0b01631d 441
84f07fb2 442 while(<$fh>) {
16114dde 443 tr/\015//d;
41630250 444 if (s/^=head1 (NAME)\s*/=head2 /) {
41630250 445 unhead1();
c0f8aaaa 446 $OUT .= "\n\n=head2 ";
84f07fb2 447 $_ = <$fh>;
767650bc
NC
448 # Remove svn keyword expansions from the Perl FAQ
449 s/ \(\$Revision: \d+ \$\)//g;
32ebae07 450 if ( /^\s*\Q$pod\E\b/ ) {
41630250 451 s/$pod\.pm/$pod/; # '.pm' in NAME !?
41630250
JH
452 } else {
453 s/^/$pod, /;
41630250 454 }
41630250 455 }
1fa7865d 456 elsif (s/^=head1 (.*)/=item $1/) {
41630250 457 unhead2();
c0f8aaaa 458 $OUT .= "=over 4\n\n" unless $inhead1;
41630250 459 $inhead1 = 1;
1fa7865d 460 $_ .= "\n";
41630250 461 }
1fa7865d 462 elsif (s/^=head2 (.*)/=item $1/) {
41630250 463 unitem();
c0f8aaaa 464 $OUT .= "=over 4\n\n" unless $inhead2;
41630250 465 $inhead2 = 1;
1fa7865d 466 $_ .= "\n";
41630250 467 }
1fa7865d 468 elsif (s/^=item ([^=].*)/$1/) {
41630250
JH
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:/;
c0f8aaaa 476 $OUT .= ", " if $initem;
41630250
JH
477 $initem = 1;
478 s/\.$//;
479 s/^-X\b/-I<X>/;
41630250 480 }
1fa7865d
NC
481 else {
482 unhead1() if /^=cut\s*\n/;
41630250
JH
483 next;
484 }
1fa7865d 485 $OUT .= $_;
41630250
JH
486 }
487}
488
489sub unhead1 {
490 unhead2();
491 if ($inhead1) {
c0f8aaaa 492 $OUT .= "\n\n=back\n\n";
41630250
JH
493 }
494 $inhead1 = 0;
495}
496
497sub unhead2 {
498 unitem();
499 if ($inhead2) {
c0f8aaaa 500 $OUT .= "\n\n=back\n\n";
41630250
JH
501 }
502 $inhead2 = 0;
503}
504
505sub unitem {
506 if ($initem) {
c0f8aaaa 507 $OUT .= "\n\n";
41630250
JH
508 }
509 $initem = 0;
510}
511
41630250
JH
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};
b0b6bf2b 521 next if $flags->{perlpod_omit};
41630250
JH
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 {
ce9f0d31 535 my_die "Illegal length " . scalar @$_;
41630250
JH
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 {
c69ca1d4 548 # Annoyingly, unexpand doesn't consider it good form to replace a single
41630250
JH
549 # space before a tab with a tab
550 # Annoyingly (2) it returns read only values.
453d7764 551 my @temp = unexpand (map {sprintf "%-32s%s", @$_} @_);
41630250
JH
552 map {s/ \t/\t\t/g; $_} @temp;
553}
554sub generate_manifest_pod {
b0b6bf2b 555 generate_manifest map {["pod/$_.pod", $Pods{$_}]}
3dc608da 556 sort grep {!$Copies{"$_.pod"}} grep {!$Generated{"$_.pod"}} keys %Pods;
41630250
JH
557}
558sub generate_manifest_readme {
dd0cfdaa
NC
559 generate_manifest sort {$a->[0] cmp $b->[0]}
560 ["README.vms", "Notes about installing the VMS port"],
561 map {["README.$_", $Readmes{$_}]} keys %Readmes;
41630250
JH
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++ . " = $_"}
bae7ea06 579 split /\n/, wrap('', '', join " ", map "[.lib.pods]$_.pod",
41630250
JH
580 sort keys %Pods, keys %Readmepods);
581 @lines, "pod = " . join ' ', map {"\$(pod$_)"} 0 .. $count - 1;
582}
583
584sub generate_descrip_mms_2 {
dd0cfdaa
NC
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]
41630250
JH
589SNIP
590 sort keys %Pods, keys %Readmepods;
591}
592
593sub generate_nmake_1 {
b0b6bf2b
AT
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);
41630250
JH
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 ",
9e64a656 605 join " ", sort keys %Copies, keys %Generated,
dd0cfdaa 606 map {"perl$_.pod"} keys %Readmes);
41630250 607 $line =~ s/$/ \\/mg;
b14c7f9a 608 $line =~ s/ \\$//;
41630250
JH
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
6d664f07
NC
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
41630250 629sub do_manifest {
131a60d2 630 my ($name, $prev) = @_;
41630250 631 my @manifest =
453d7764 632 grep {! m!^pod/[^.]+\.pod.*!}
131a60d2 633 grep {! m!^README\.(\S+)! || $Ignore{$1}} split "\n", $prev;
453d7764
NC
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()), '';
41630250
JH
642}
643
644sub do_nmake {
131a60d2 645 my ($name, $makefile) = @_;
41630250 646 $makefile =~ s/^\tcopy \.\.\\README.*\n/\0/gm;
6d664f07 647 verify_contiguous($name, $makefile, 'README copies');
b0b6bf2b
AT
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;
41630250 651
b14c7f9a
SH
652 $makefile =~ s{(-cd \$\(PODDIR\) && del /f[^\n]+).*?(-cd \.\.\\utils && del /f)}
653 {"$1\n" . &generate_nmake_2."\n\t$2"}se;
41630250
JH
654 $makefile;
655}
656
657# shut up used only once warning
658*do_dmake = *do_dmake = \&do_nmake;
659
660sub do_perlpod {
131a60d2 661 my ($name, $pod) = @_;
41630250
JH
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) {
ce9f0d31 670 my_die "Failed to insert amendments in do_perlpod";
41630250
JH
671 }
672 $pod;
673}
674
675sub do_podmak {
131a60d2 676 my ($name, $body) = @_;
d525b9bc 677 foreach my $variable (qw(pod man html tex)) {
ce9f0d31 678 my_die "could not find $variable in $name"
41630250
JH
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 {
131a60d2 686 my ($name, $makefile) = @_;
41630250 687 $makefile =~ s/\npod\d* =[^\n]*/\0/gs;
6d664f07 688 verify_contiguous($name, $makefile, 'pod assignments');
41630250
JH
689 $makefile =~ s/\0+/join "\n", '', &generate_descrip_mms_1/se;
690
ce9f0d31 691 my_die "$name contains NUL bytes" if $makefile =~ /\0/;
41630250 692
600dcb9e
CB
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
41630250 701# Looking for rules like this
bae7ea06
NC
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]
41630250 705
bae7ea06 706 $makefile =~ s/\n\Q[.lib.pods]\Eperl[^\n\.]*\.pod[^\n]+\n
41630250 707 [^\n]+\n # Another line
bae7ea06 708 [^\n]+\Q[.lib.pods]\E\n # ends [.lib.pods]
41630250 709 /\0/gsx;
6d664f07 710 verify_contiguous($name, $makefile, 'copy rules');
41630250 711 $makefile =~ s/\0+/join "\n", '', &generate_descrip_mms_2/se;
db34a22a 712
41630250
JH
713 $makefile;
714}
715
0dfdcd8a 716sub do_unix {
131a60d2 717 my ($name, $makefile_SH) = @_;
0dfdcd8a 718
7eb47696
NC
719 $makefile_SH =~ s{^(perltoc_pod_prereqs = extra.pods).*}
720 {join ' ', $1, map "pod/$_",
721 sort keys %Copies, grep {!/perltoc/} keys %Generated
722 }mge;
8e7bc40f 723
37ee6528
FR
724# pod/perl511delta.pod: pod/perldelta.pod
725# cd pod && $(LNS) perldelta.pod perl511delta.pod
8e7bc40f
NC
726
727 $makefile_SH =~ s!(
728pod/perl[a-z0-9_]+\.pod: pod/perl[a-z0-9_]+\.pod
e0be038f 729 \$\(LNS\) perl[a-z0-9_]+\.pod pod/perl[a-z0-9_]+\.pod
8e7bc40f 730)+!\0!gm;
0dfdcd8a 731
6d664f07 732 verify_contiguous($name, $makefile_SH, 'copy rules');
0dfdcd8a 733
8e7bc40f
NC
734 my @copy_rules = map "
735pod/$_: pod/$Copies{$_}
e0be038f 736 \$(LNS) $Copies{$_} pod/$_
8e7bc40f 737", keys %Copies;
0dfdcd8a 738
8e7bc40f 739 $makefile_SH =~ s/\0+/join '', @copy_rules/se;
0dfdcd8a
NC
740 $makefile_SH;
741
742}
743
41630250
JH
744# Do stuff
745
746my $built;
747while (my ($target, $name) = each %Targets) {
e94c1c05 748 print "Working on target $target\n" if $Verbose;
41630250
JH
749 next unless $Build{$target};
750 $built++;
02cc404a 751 my ($orig, $mode);
41630250 752 print "Now processing $name\n" if $Verbose;
02cc404a
NC
753 if ($target ne "toc") {
754 local $/;
ce9f0d31 755 open my $thing, '<', $name or my_die "Can't open $name: $!";
bac61051
NC
756 binmode $thing;
757 $orig = <$thing>;
ce9f0d31 758 my_die "$name contains NUL bytes" if $orig =~ /\0/;
02cc404a
NC
759 }
760
131a60d2 761 my $new = do {
41630250 762 no strict 'refs';
131a60d2 763 &{"do_$target"}($target, $orig);
41630250 764 };
02cc404a
NC
765
766 if (defined $orig) {
767 if ($new eq $orig) {
5733ee18
NC
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;
02cc404a
NC
776 next;
777 }
ce9f0d31
DM
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: $!";
41630250 780 }
02cc404a 781
ce9f0d31 782 open my $thing, '>', $name or my_die "Can't open $name for writing: $!";
bac61051 783 binmode $thing;
ce9f0d31
DM
784 print $thing $new or my_die "print to $name failed: $!";
785 close $thing or my_die "close $name failed: $!";
02cc404a 786 if (defined $mode) {
ce9f0d31 787 chmod $mode & 0777, $name or my_die "can't chmod $mode $name: $!";
02cc404a 788 }
41630250
JH
789}
790
5733ee18 791warn "$0: was not instructed to build anything\n" unless $built || $Test;