This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
67178ede22ae890d50a45780c7bd4b2f5026f789
[perl5.git] / dist / Devel-PPPort / devel / scanprov
1 #!/usr/bin/perl -w
2 ################################################################################
3 #
4 #  scanprov -- scan Perl headers for provided macros
5 #
6 ################################################################################
7 #
8 #  Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
9 #  Version 2.x, Copyright (C) 2001, Paul Marquess.
10 #  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
11 #
12 #  This program is free software; you can redistribute it and/or
13 #  modify it under the same terms as Perl itself.
14 #
15 ################################################################################
16
17 use strict;
18 use Getopt::Long;
19
20 require './parts/ppptools.pl';
21 require './parts/inc/inctools';
22
23 our %opt = (
24   mode    => 'check',
25   install => '/tmp/perl/install/default',
26   blead   => 'bleadperl',
27 );
28
29 GetOptions(\%opt, qw( install=s mode=s blead=s )) or die;
30
31 my $write = $opt{mode} eq 'write';
32
33 my %embed = map { ( $_->{name} => 1 ) }
34             parse_embed(qw(parts/embed.fnc parts/apidoc.fnc parts/ppport.fnc ));
35
36 # @provided is set to the elements that are provided, but not functions in the
37 # .fnc files
38 my @provided = grep { !exists $embed{$_} }
39                map { /^(\w+)/ ? $1 : () }
40                `$^X ppport.h --list-provided`;
41
42 my @perls = sort { $b->{version} <=> $a->{version} }
43             map { { version => `$_ -e 'printf "%.6f", \$]'`, path => $_ } }
44             ($opt{blead}, glob "$opt{install}/*/bin/perl5.*");
45
46 for (1 .. $#perls) {
47   $perls[$_]{todo} = $perls[$_-1]{version};
48 }
49
50 # Get rid of blead
51 shift @perls;
52
53 my %v;
54
55 # We look in descending order of perl versions.  Each time through the loop
56 # @provided is narrowed.
57 for my $p (@perls) {
58   print "checking perl $p->{version}...\n";
59
60   # Get the hdr files associated with this version
61   my $archlib = `$p->{path} -MConfig -l -e 'print \$Config{archlib}'`;
62   chomp $archlib;
63   local @ARGV = glob "$archlib/CORE/*.h";
64   my %sym;
65
66   # %sym's keys are every single \w+ that occurs in all the headers,
67   # regardless of if they are in a comment, or what.
68   while (<>) { $sym{$_}++ for /(\w+)/g; }
69
70   # @provided is narrowed to include only those \w+ things that are mentioned
71   # in some hdr in this release.  (If it isn't even mentioned, it won't exist in
72   # the release.)  For those not mentioned, a key is added of the \w+ in %v.
73   # It is a subkey of this release's "todo" release, which is the next higher
74   # one.  If we are at version n, we have already done version n+1 and the
75   # provided element was mentioned there, and now it no longer is.  We take
76   # that to mean that to mean that the element became provided for in n+1.
77   # (khw notes that it could have just been in a comment for a bunch of
78   # releases above this, like
79   #         /* Oh how I wish we had FOO */
80   # and at some point FOO got added.  The method here is, hence, just a
81   # heuristic.
82   @provided = map { $sym{$_} or $v{$p->{todo}}{$_}++;
83                     $sym{$_} ? $_ : ()
84                   } @provided;
85 }
86
87 # Read in the parts/base files.  The hash ref has keys being all symbols found
88 # in all the files in base/, and the values being the perl versions each symbol
89 # became defined in.
90 my $out = 'parts/base';
91 my $todo = parse_todo($out);
92
93 # Now add the results from above.  At this point, The keys of %v are the 7
94 # digit BCD version numbers, and their subkeys are the symbols provided by
95 # D:P that are first mentioned in this version, like this:
96 #   '5009002' => {
97 #                  'MY_CXT_CLONE' => 1,
98 #                  'SV_NOSTEAL' => 1,
99 #                  'UTF8_MAXBYTES' => 1
100 #                },
101
102 for my $v (keys %v) {
103
104   # @new becomes the symbols for version $v not already in the file for $v
105   my @new = sort dictionary_order grep { !exists $todo->{$_} }
106                                                                 keys %{$v{$v}};
107   @new or next; # Nothing new, skip writing
108
109   my $file = $v;
110   $file =~ s/\.//g;
111   $file = "$out/$file";
112   -e $file or die "non-existent: $file\n";
113   print "-- $file --\n";
114   $write and (open F, ">>$file" or die "$file: $!\n");
115   for (@new) {
116     print "adding $_\n";
117     $write and printf F "%-30s # added by $0\n", $_;
118   }
119   $write and close F;
120 }