]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - util/find-doc-nits
apps & al : Fix various typos, repeated words, align some spelling to LDP.
[thirdparty/openssl.git] / util / find-doc-nits
index a581adfa35b0c5e5d94b90651116f9868b6fbfd1..04911fae51588464134dcf1d2ff984d0e326689c 100755 (executable)
@@ -1,5 +1,5 @@
 #! /usr/bin/env perl
-# Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2002-2021 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
@@ -28,9 +28,6 @@ use configdata;
 # Set to 1 for debug output
 my $debug = 0;
 
-# Where to find openssl command
-my $openssl = "./util/opensslwrap.sh";
-
 # Options.
 our($opt_d);
 our($opt_e);
@@ -38,6 +35,7 @@ our($opt_s);
 our($opt_o);
 our($opt_h);
 our($opt_l);
+our($opt_m);
 our($opt_n);
 our($opt_p);
 our($opt_u);
@@ -48,11 +46,12 @@ our($opt_c);
 sub help {
     print <<EOF;
 Find small errors (nits) in documentation.  Options:
-    -c List undocumented commands and options
+    -c List undocumented commands, undocumented options and unimplemented options.
     -d Detailed list of undocumented (implies -u)
     -e Detailed list of new undocumented (implies -v)
     -h Print this help message
     -l Print bogus links
+    -m Name(s) of manuals to focus on. Default: man1,man3,man5,man7
     -n Print nits in POD pages
     -o Causes -e/-v to count symbols added since 1.1.1 as new (implies -v)
     -u Count undocumented functions
@@ -61,7 +60,7 @@ EOF
     exit;
 }
 
-getopts('cdehlnouv');
+getopts('cdehlm:nouv');
 
 help() if $opt_h;
 $opt_u = 1 if $opt_d;
@@ -81,7 +80,11 @@ my $temp = '/tmp/docnits.txt';
 my $OUT;
 my $status = 0;
 
-my @sections = ( 'man1', 'man3', 'man5', 'man7' );
+$opt_m = "man1,man3,man5,man7" unless $opt_m;
+die "Argument of -m option may contain only man1, man3, man5, and/or man7"
+    unless $opt_m =~ /^(man[1357][, ]?)*$/;
+my @sections = ( split /[, ]/, $opt_m );
+
 my %mandatory_sections = (
     '*' => [ 'NAME', 'DESCRIPTION', 'COPYRIGHT' ],
     1   => [ 'SYNOPSIS', 'OPTIONS' ],
@@ -102,7 +105,7 @@ my $ignored = qr/(?| ^i2d_
                  |   ^sk_
                  |   ^SKM_DEFINE_STACK_OF_INTERNAL
                  |   ^lh_
-                 |   ^DEFINE_LHASH_OF_INTERNAL
+                 |   ^DEFINE_LHASH_OF_(INTERNAL|DEPRECATED)
                  )/x;
 
 # A common regexp for C symbol names
@@ -151,7 +154,7 @@ my %collected_results = ();
 #                       - exclusive selectors, only applicable together with
 #                         any of the manual selectors.  If any of these are
 #                         present, only the manuals from the given sections
-#                         will be include.  If none of these are present,
+#                         will be included.  If none of these are present,
 #                         the manuals from all sections will be returned.
 #
 # All returned manual files come from configdata.pm.
@@ -351,6 +354,7 @@ sub name_synopsis {
 
         my $sym;
         my $is_prototype = 1;
+        $line =~ s/LHASH_OF\([^)]+\)/int/g;
         $line =~ s/STACK_OF\([^)]+\)/int/g;
         $line =~ s/SPARSE_ARRAY_OF\([^)]+\)/int/g;
         $line =~ s/__declspec\([^)]+\)//;
@@ -545,8 +549,10 @@ sub option_check {
         err($id, "Malformed option [1] in SYNOPSIS: $&");
     }
 
+    my @synopsis;
     while ( $synopsis =~ /$markup_re/msg ) {
         my $found = $&;
+        push @synopsis, $found if $found =~ /^B<-/;
         print STDERR "$id:DEBUG[option_check] SYNOPSIS: found $found\n"
             if $debug;
         my $option_uw = normalise_option($id, $filename, $found);
@@ -556,6 +562,7 @@ sub option_check {
 
     # In OPTIONS, we look for =item paragraphs.
     # (?=^\s*$) detects an empty line.
+    my @options;
     while ( $options =~ /=item\s+(.*?)(?=^\s*$)/msg ) {
         my $item = $&;
 
@@ -569,8 +576,19 @@ sub option_check {
             my $option_uw = normalise_option($id, $filename, $found);
             err($id, "Malformed option in OPTIONS: $found")
                 if defined $option_uw && $option_uw eq '';
+            if ($found =~ /^B<-/) {
+                push @options, $found;
+                err($id, "OPTIONS entry $found missing from SYNOPSIS")
+                    unless (grep /^\Q$found\E$/, @synopsis)
+                         || $id =~ /(openssl|-options)\.pod:1:$/;
+            }
         }
     }
+    foreach (@synopsis) {
+        my $option = $_;
+        err($id, "SYNOPSIS entry $option missing from OPTIONS")
+            unless (grep /^\Q$option\E$/, @options);
+    }
 }
 
 # Normal symbol form
@@ -609,6 +627,7 @@ my %preferred_words = (
     'bitmask'       => 'bit mask',
     'builtin'       => 'built-in',
    #'epoch'         => 'Epoch', # handled specially, below
+    'fall-back'     => 'fallback',
     'file name'     => 'filename',
     'file system'   => 'filesystem',
     'host name'     => 'hostname',
@@ -711,9 +730,8 @@ sub check {
         next if $target =~ /openssl-?/;
         next if ( grep { basename($_) eq "$target.pod" }
                   files(TAGS => [ 'manual', 'man1' ]) );
-        # TODO: Filter out "foreign manual" links.
         next if $target =~ /ps|apropos|sha1sum|procmail|perl/;
-        err($id, "Bad command link L<$target(1)>");
+        err($id, "Bad command link L<$target(1)>") if grep /man1/, @sections;
     }
     # Check for proper in-man-3 API links.
     while ( $contents =~ /L<([^>]*)\(3\)(?:\/.*)?>/g ) {
@@ -778,7 +796,8 @@ sub check {
 
     open my $OUT, '>', $temp
         or die "Can't open $temp, $!";
-    podchecker($filename, $OUT);
+    err($id, "POD errors")
+        if podchecker($filename, $OUT) != 0;
     close $OUT;
     open $OUT, '<', $temp
         or die "Can't read $temp, $!";
@@ -884,7 +903,7 @@ sub checkstate () {
 
         err("$_ is supposedly public but is documented as internal")
             if ( $declared_public && $name_map{$_} =~ /\/internal\// );
-        err("$_ is supposedly internal but is documented as public")
+        err("$_ is supposedly internal (maybe missing from other.syms) but is documented as public")
             if ( $declared_internal && $name_map{$_} !~ /\/internal\// );
     }
 }
@@ -980,16 +999,27 @@ sub collectnames {
         }
     }
 
-    my @links =
-        $podinfo{contents} =~ /L<
-                              # if the link is of the form L<something|name(s)>,
-                              # then remove 'something'.  Note that 'something'
-                              # may contain POD codes as well...
-                              (?:(?:[^\|]|<[^>]*>)*\|)?
-                              # we're only interested in references that have
-                              # a one digit section number
-                              ([^\/>\(]+\(\d\))
-                             /gx;
+    my @links = ();
+    # Don't use this regexp directly on $podinfo{contents}, as it causes
+    # a regexp recursion, which fails on really big PODs.  Instead, use
+    # $markup_re to pick up general markup, and use this regexp to check
+    # that the markup that was found is indeed a link.
+    my $linkre = qr/L<
+                    # if the link is of the form L<something|name(s)>,
+                    # then remove 'something'.  Note that 'something'
+                    # may contain POD codes as well...
+                    (?:(?:[^\|]|<[^>]*>)*\|)?
+                    # we're only interested in references that have
+                    # a one digit section number
+                    ([^\/>\(]+\(\d\))
+                   /x;
+    while ( $podinfo{contents} =~ /$markup_re/msg ) {
+        my $x = $1;
+
+        if ($x =~ $linkre) {
+            push @links, $1;
+        }
+    }
     $link_map{$filename} = [ @links ];
 }
 
@@ -1026,21 +1056,40 @@ my %skips = (
     'digest' => 1,
 );
 
+my %genopts; # generic options parsed from apps/include/opt.h
+
 # Check the flags of a command and see if everything is in the manpage
 sub checkflags {
     my $cmd = shift;
     my $doc = shift;
-    my %cmdopts;
+    my @cmdopts;
     my %docopts;
-    my %localskips;
 
-    # Get the list of options in the command.
-    open CFH, "$openssl list --options $cmd|"
-        or die "Can list options for $cmd, $!";
+    # Get the list of options in the command source file.
+    my $active = 0;
+    my $expect_helpstr = "";
+    open CFH, "apps/$cmd.c"
+        or die "Can't open apps/$cmd.c to list options for $cmd, $!";
     while ( <CFH> ) {
         chop;
-        s/ .$//;
-        $cmdopts{$_} = 1;
+        if ($active) {
+            last if m/^\s*};/;
+            if ($expect_helpstr ne "") {
+                next if m/^\s*#\s*if/;
+                err("$cmd does not implement help for -$expect_helpstr") unless m/^\s*"/;
+                $expect_helpstr = "";
+            }
+            if (m/\{\s*"([^"]+)"\s*,\s*OPT_[A-Z0-9_]+\s*,\s*('[-\/:<>cEfFlMnNpsuU]'|0)(.*)$/
+                    && !($cmd eq "s_client" && $1 eq "wdebug")) {
+                push @cmdopts, $1;
+                $expect_helpstr = $1;
+                $expect_helpstr = "" if $3 =~ m/^\s*,\s*"/;
+            } elsif (m/[\s,](OPT_[A-Z]+_OPTIONS?)\s*(,|$)/) {
+                push @cmdopts, @{ $genopts{$1} };
+            }
+        } elsif (m/^const\s+OPTIONS\s*/) {
+            $active = 1;
+        }
     }
     close CFH;
 
@@ -1050,12 +1099,6 @@ sub checkflags {
     while ( <CFH> ) {
         chop;
         last if /DESCRIPTION/;
-        if ( /=for openssl ifdef (.*)/ ) {
-            foreach my $f ( split / /, $1 ) {
-                $localskips{$f} = 1;
-            }
-            next;
-        }
         my $opt;
         if ( /\[B<-([^ >]+)/ ) {
             $opt = $1;
@@ -1070,16 +1113,16 @@ sub checkflags {
     close CFH;
 
     # See what's in the command not the manpage.
-    my @undocced = sort grep { !defined $docopts{$_} } keys %cmdopts;
+    my @undocced = sort grep { !defined $docopts{$_} } @cmdopts;
     foreach ( @undocced ) {
-        next if /-/; # Skip the -- end-of-flags marker
-        err("$doc: undocumented option -$_");
+        err("$doc: undocumented $cmd option -$_");
     }
 
     # See what's in the command not the manpage.
-    my @unimpl = sort grep { !defined $cmdopts{$_} } keys %docopts;
+    my @unimpl = sort grep { my $e = $_; !(grep /^\Q$e\E$/, @cmdopts) } keys %docopts;
     foreach ( @unimpl ) {
-        next if defined $skips{$_} || defined $localskips{$_};
+        next if $_ eq "-"; # Skip the -- end-of-flags marker
+        next if defined $skips{$_};
         err("$doc: $cmd does not implement -$_");
     }
 }
@@ -1094,18 +1137,27 @@ sub checkflags {
 if ( $opt_c ) {
     my @commands = ();
 
-    # Get list of commands.
-    open FH, "$openssl list -1 -commands|"
-        or die "Can't list commands, $!";
-    while ( <FH> ) {
+    # Get the lists of generic options.
+    my $active = "";
+    open OFH, catdir($config{sourcedir}, "apps/include/opt.h")
+        or die "Can't open apps/include/opt.h to list generic options, $!";
+    while ( <OFH> ) {
         chop;
-        push @commands, $_;
+        push @{ $genopts{$active} }, $1 if $active ne "" && m/^\s+\{\s*"([^"]+)"\s*,\s*OPT_/;
+        $active = $1 if m/^\s*#\s*define\s+(OPT_[A-Z]+_OPTIONS?)\s*\\\s*$/;
+        $active = "" if m/^\s*$/;
     }
-    close FH;
+    close OFH;
+
+    # Get list of commands.
+    opendir(DIR, "apps");
+    @commands = grep(/\.c$/, readdir(DIR));
+    closedir(DIR);
 
     # See if each has a manpage.
     foreach my $cmd ( @commands ) {
-        next if $cmd eq 'help' || $cmd eq 'exit';
+        $cmd =~ s/\.c$//;
+        next if $cmd eq 'progs' || $cmd eq 'vms_decc_init';
         my @doc = ( grep { basename($_) eq "openssl-$cmd.pod"
                            # For "tsget" and "CA.pl" pod pages
                            || basename($_) eq "$cmd.pod" }
@@ -1119,18 +1171,6 @@ if ( $opt_c ) {
             checkflags($cmd, @doc);
         }
     }
-
-    # See what help is missing.
-    open FH, "$openssl list --missing-help |"
-        or die "Can't list missing help, $!";
-    while ( <FH> ) {
-        chop;
-        my ($cmd, $flag) = split;
-        err("$cmd has no help for -$flag");
-    }
-    close FH;
-
-    exit $status;
 }
 
 # Populate %state
@@ -1170,9 +1210,10 @@ if ( $opt_l ) {
 
 if ( $opt_n ) {
     # If not given args, check that all man1 commands are named properly.
-    if ( scalar @ARGV == 0 ) {
+    if ( scalar @ARGV == 0 && grep /man1/, @sections ) {
         foreach ( files(TAGS => [ 'public_manual', 'man1' ]) ) {
-            next if /CA.pl/ || /openssl\.pod/ || /tsget\.pod/;
+            next if /openssl\.pod/
+                || /CA\.pl/ || /tsget\.pod/; # these commands are special cases
             err("$_ doesn't start with openssl-") unless /openssl-/;
         }
     }