Fix some pod-page ordering nits
[openssl.git] / util / find-doc-nits
index 5d5c2d05b2790fe4ade677e2cd2d18fbf68bb8bb..563a6956a7c4de144401266333e94bb1a8992a64 100755 (executable)
@@ -1,5 +1,5 @@
 #! /usr/bin/env perl
-# Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved.
 #
 # Licensed under the Apache License 2.0 (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
@@ -20,11 +20,15 @@ use OpenSSL::Util::Pod;
 
 # Options.
 our($opt_d);
+our($opt_e);
+our($opt_s);
+our($opt_o);
 our($opt_h);
 our($opt_l);
 our($opt_n);
 our($opt_p);
 our($opt_u);
+our($opt_v);
 our($opt_c);
 
 sub help()
@@ -32,10 +36,14 @@ sub help()
     print <<EOF;
 Find small errors (nits) in documentation.  Options:
     -d Detailed list of undocumented (implies -u)
+    -e Detailed list of new undocumented (implies -v)
+    -s Same as -e except no output is generated if nothing is undocumented
+    -o Causes -e/-v to count symbols added since 1.1.1 as new (implies -v)
     -l Print bogus links
     -n Print nits in POD pages
     -p Warn if non-public name documented (implies -n)
     -u Count undocumented functions
+    -v Count new undocumented functions
     -h Print this help message
     -c List undocumented commands and options
 EOF
@@ -66,12 +74,12 @@ sub name_synopsis()
     $tmp =~ tr/\n/ /;
     print "$id trailing comma before - in NAME\n" if $tmp =~ /, *-/;
     $tmp =~ s/ -.*//g;
+    print "$id POD markup among the names in NAME\n" if $tmp =~ /[<>]/;
     $tmp =~ s/  */ /g;
     print "$id missing comma in NAME\n" if $tmp =~ /[^,] /;
 
     my $dirname = dirname($filename);
-    my $simplename = basename($filename);
-    $simplename =~ s/.pod$//;
+    my $simplename = basename(basename($filename, ".in"), ".pod");
     my $foundfilename = 0;
     my %foundfilenames = ();
     my %names;
@@ -83,9 +91,10 @@ sub name_synopsis()
         $names{$n} = 1;
         $foundfilename++ if $n eq $simplename;
         $foundfilenames{$n} = 1
-            if -f "$dirname/$n.pod" && $n ne $simplename;
+            if ((-f "$dirname/$n.pod.in" || -f "$dirname/$n.pod")
+                && $n ne $simplename);
     }
-    print "$id the following exist as other .pod files:\n",
+    print "$id the following exist as other .pod or .pod.in files:\n",
         join(" ", sort keys %foundfilenames), "\n"
         if %foundfilenames;
     print "$id $simplename (filename) missing from NAME section\n"
@@ -142,16 +151,18 @@ sub name_synopsis()
     }
 }
 
-# Check if EXAMPLES is located after RETURN VALUES section.
-sub check_example_location()
+# Check if SECTION ($3) is located before BEFORE ($4)
+sub check_section_location()
 {
-    my $filename = shift;
+    my $id = shift;
     my $contents = shift;
+    my $section = shift;
+    my $before = shift;
 
-    return unless $contents =~ /=head1 RETURN VALUES/
-        and $contents =~ /=head1 EXAMPLES/;
-    print "$filename: RETURN VAULES should be placed before EXAMPLES section\n"
-        if $contents =~ /=head1 EXAMPLES.*=head1 RETURN VALUES/ms;
+    return
+        unless $contents =~ /=head1 $section/ and $contents =~ /=head1 $before/;
+    print "$id $section should be placed before $before section\n"
+        if $contents =~ /=head1 $before.*=head1 $section/ms;
 }
 
 sub check()
@@ -167,10 +178,15 @@ sub check()
         close POD;
     }
 
-    &check_example_location($filename, $contents) if $filename =~ m|man3/|;
-
     my $id = "${filename}:1:";
 
+    # Check ordering of some sections in man3
+    if ( $filename =~ m|man3/| ) {
+        &check_section_location($id, $contents, "RETURN VALUES", "EXAMPLE");
+        &check_section_location($id, $contents, "SEE ALSO", "HISTORY");
+        &check_section_location($id, $contents, "EXAMPLE", "SEE ALSO");
+    }
+
     &name_synopsis($id, $filename, $contents)
         unless $contents =~ /=for comment generic/
             or $filename =~ m@man[157]/@;
@@ -191,8 +207,6 @@ sub check()
         if $contents =~ /=head\d\s\s+/;
     print "$id period in NAME section\n"
         if $contents =~ /=head1 NAME.*\.\n.*=head1 SYNOPSIS/ms;
-    print "$id POD markup in NAME section\n"
-        if $contents =~ /=head1 NAME.*[<>].*=head1 SYNOPSIS/ms;
     print "$id Duplicate $1 in L<>\n"
         if $contents =~ /L<([^>]*)\|([^>]*)>/ && $1 eq $2;
     print "$id Bad =over $1\n"
@@ -252,7 +266,6 @@ sub parsenum()
     while ( <$IN> ) {
         next if /^#/;
         next if /\bNOEXIST\b/;
-        next if /\bEXPORT_VAR_AS_FUNC\b/;
         my @fields = split();
         die "Malformed line $_"
             if scalar @fields != 2 && scalar @fields != 4;
@@ -270,7 +283,7 @@ sub getdocced
     my $dir = shift;
     my %return;
 
-    foreach my $pod ( glob("$dir/*.pod") ) {
+    foreach my $pod ( glob("$dir/*.pod"), glob("$dir/*.pod.in") ) {
         my %podinfo = extract_pod_info($pod);
         foreach my $n ( @{$podinfo{names}} ) {
             $return{$n} = $pod;
@@ -285,12 +298,36 @@ sub getdocced
 
 my %docced;
 
+sub loadmissing($)
+{
+    my $missingfile = shift;
+    my @missing;
+
+    open FH, $missingfile
+        || die "Can't open $missingfile";
+    while ( <FH> ) {
+        chomp;
+        next if /^#/;
+        push @missing, $_;
+    }
+    close FH;
+
+    return @missing;
+}
+
 sub checkmacros()
 {
     my $count = 0;
     my %seen;
+    my @missing;
+
+    if ($opt_o) {
+        @missing = loadmissing('util/missingmacro111.txt');
+    } elsif ($opt_v) {
+        @missing = loadmissing('util/missingmacro.txt');
+    }
 
-    print "# Checking macros (approximate)\n";
+    print "# Checking macros (approximate)\n" if !$opt_s;
     foreach my $f ( glob('include/openssl/*.h') ) {
         # Skip some internals we don't want to document yet.
         next if $f eq 'include/openssl/asn1.h';
@@ -306,33 +343,43 @@ sub checkmacros()
                 || $macro =~ /DEPRECATEDIN/
                 || $macro =~ /IMPLEMENT_/
                 || $macro =~ /DECLARE_/;
-            print "$f:$macro\n" if $opt_d;
+
+            # Skip macros known to be missing
+            next if $opt_v && grep( /^$macro$/, @missing);
+    
+            print "$f:$macro\n" if $opt_d || $opt_e;
             $count++;
             $seen{$macro} = 1;
         }
         close(IN);
     }
-    print "# Found $count macros missing (not all should be documented)\n"
+    print "# Found $count macros missing\n" if !$opt_s || $count > 0;
 }
 
 sub printem()
 {
     my $libname = shift;
     my $numfile = shift;
+    my $missingfile = shift;
     my $count = 0;
     my %seen;
 
+    my @missing = loadmissing($missingfile) if ($opt_v);
+
     foreach my $func ( &parsenum($numfile) ) {
         next if $docced{$func} || defined $seen{$func};
 
         # Skip ASN1 utilities
         next if $func =~ /^ASN1_/;
 
-        print "$libname:$func\n" if $opt_d;
+        # Skip functions known to be missing
+        next if $opt_v && grep( /^$func$/, @missing);
+
+        print "$libname:$func\n" if $opt_d || $opt_e;
         $count++;
         $seen{$func} = 1;
     }
-    print "# Found $count missing from $numfile\n\n";
+    print "# Found $count missing from $numfile\n\n" if !$opt_s || $count > 0;
 }
 
 
@@ -347,7 +394,7 @@ sub collectnames {
     my $filename = shift;
     $filename =~ m|man(\d)/|;
     my $section = $1;
-    my $simplename = basename($filename, ".pod");
+    my $simplename = basename(basename($filename, ".in"), ".pod");
     my $id = "${filename}:1:";
 
     my $contents = '';
@@ -365,9 +412,12 @@ sub collectnames {
         return;
     }
     $tmp =~ tr/\n/ /;
-    $tmp =~ s/-.*//g;
+    $tmp =~ s/ -.*//g;
 
-    my @names = map { s/^\s+//g; s/\s+$//g; $_ } split(/,/, $tmp);
+    my @names =
+        map { s|/|-|g; $_ }              # Treat slash as dash
+        map { s/^\s+//g; s/\s+$//g; $_ } # Trim prefix and suffix blanks
+        split(/,/, $tmp);
     unless (grep { $simplename eq $_ } @names) {
         print "$id missing $simplename\n";
         push @names, $simplename;
@@ -380,8 +430,10 @@ sub collectnames {
         my $name_sec = "$name($section)";
         if (! exists $name_collection{$name_sec}) {
             $name_collection{$name_sec} = $filename;
-        } else { #elsif ($filename ne $name_collection{$name_sec}) {
-            print "$id $name_sec also in $name_collection{$name_sec}\n";
+        } elsif ($filename eq $name_collection{$name_sec}) {
+            print "$id $name_sec repeated in NAME section of $name_collection{$name_sec}\n"
+        } else {
+            print "$id $name_sec also in NAME section of $name_collection{$name_sec}\n";
         }
     }
 
@@ -497,14 +549,22 @@ sub checkflags() {
     return $ok;
 }
 
-getopts('cdlnphu');
+getopts('cdesolnphuv');
 
 &help() if $opt_h;
+
 $opt_n = 1 if $opt_p;
 $opt_u = 1 if $opt_d;
+$opt_e = 1 if $opt_s;
+$opt_v = 1 if $opt_o || $opt_e;
+
+die "Cannot use both -u and -v" if $opt_u && $opt_v;
+die "Cannot use both -d and -e" if $opt_d && $opt_e;
 
-die "Need one of -[cdlnpu] flags.\n"
-    unless $opt_c or $opt_l or $opt_n or $opt_u;
+# We only need to check c, l, n, u and v.
+# Options d, e, s, o and p imply one of the above.
+die "Need one of -[cdesolnpuv] flags.\n"
+    unless $opt_c or $opt_l or $opt_n or $opt_u or $opt_v;
 
 if ( $opt_c ) {
     my $ok = 1;
@@ -545,7 +605,7 @@ if ( $opt_c ) {
 }
 
 if ( $opt_l ) {
-    foreach (@ARGV ? @ARGV : (glob('doc/*/*.pod'),
+    foreach (@ARGV ? @ARGV : (glob('doc/*/*.pod'), glob('doc/*/*.pod.in'),
                               glob('doc/internal/*/*.pod'))) {
         collectnames($_);
     }
@@ -554,7 +614,7 @@ if ( $opt_l ) {
 
 if ( $opt_n ) {
     &publicize() if $opt_p;
-    foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) {
+    foreach (@ARGV ? @ARGV : (glob('doc/*/*.pod'), glob('doc/*/*.pod.in'))) {
         &check($_);
     }
     {
@@ -565,13 +625,18 @@ if ( $opt_n ) {
     }
 }
 
-if ( $opt_u ) {
+if ( $opt_u || $opt_v) {
     my %temp = getdocced('doc/man3');
     foreach ( keys %temp ) {
         $docced{$_} = $temp{$_};
     }
-    &printem('crypto', 'util/libcrypto.num');
-    &printem('ssl', 'util/libssl.num');
+    if ($opt_o) {
+        &printem('crypto', 'util/libcrypto.num', 'util/missingcrypto111.txt');
+        &printem('ssl', 'util/libssl.num', 'util/missingssl111.txt');
+    } else {
+        &printem('crypto', 'util/libcrypto.num', 'util/missingcrypto.txt');
+        &printem('ssl', 'util/libssl.num', 'util/missingssl.txt');
+    }
     &checkmacros();
 }