From 35ea640a01e3bdeaf8086aba7f05b40c11538f8f Mon Sep 17 00:00:00 2001 From: Rich Salz Date: Wed, 1 Jun 2016 13:10:24 -0400 Subject: [PATCH] Add script to find undocumented API Also tweaks to find-doc-nits, including name/synopsis checking. Ironically, it also reports on duplicated doc names :) Reviewed-by: Richard Levitte --- util/find-doc-nits.pl | 105 ++++++++++++++++++++++++++++++----------- util/find-undoc-api.pl | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 28 deletions(-) mode change 100644 => 100755 util/find-doc-nits.pl create mode 100755 util/find-undoc-api.pl diff --git a/util/find-doc-nits.pl b/util/find-doc-nits.pl old mode 100644 new mode 100755 index 4c6f0dbdd8..b0fab95353 --- a/util/find-doc-nits.pl +++ b/util/find-doc-nits.pl @@ -13,6 +13,9 @@ use strict; use Pod::Checker; use File::Find; use File::Basename; +use Getopt::Std; + +our($opt_s); my $temp = '/tmp/docnits.txt'; my $OUT; @@ -28,6 +31,46 @@ my %default_sections = crypto => 3, ssl => 3 ); +# Cross-check functions in the NAME and SYNOPSIS section. +sub name_synopsis() +{ + my $id = shift; + my $filename = shift; + my $contents = shift; + + # If it's a generic page (all lowercase), or apps, skip it. + return if $filename =~ /[a-z]+\.pod/; + return if $filename =~ m@/apps/@; + + # Get NAME section and all words in it. + return unless $contents =~ /=head1 NAME(.*)=head1 SYNOPSIS/ms; + my $tmp = $1; + $tmp =~ tr/\n/ /; + $tmp =~ s/-.*//g; + $tmp =~ s/,//g; + my %names; + foreach my $n ( split ' ', $tmp ) { + $names{$n} = 1; + } + + # Find all functions in SYNOPSIS + return unless $contents =~ /=head1 SYNOPSIS(.*)=head1 DESCRIPTION/ms; + my $syn = $1; + foreach my $line ( split /\n+/, $syn ) { + next if $line =~ /typedef/; + next if $line =~ /STACK_OF/; + next unless $line =~ /([A-Za-z0-9_]+)\(/; + print "$id $1 missing from NAME section\n" + unless defined $names{$1}; + $names{$1} = 2; + } + + foreach my $n ( keys %names ) { + next if $names{$n} == 2; + print "$id $n missing from SYNOPSIS\n"; + } +} + sub check() { my $filename = shift; @@ -42,22 +85,27 @@ sub check() } my $id = "${filename}:1:"; - print $OUT "$id doesn't start with =pod\n" + + &name_synopsis($id, $filename, $contents); + + print "$id doesn't start with =pod\n" if $contents !~ /^=pod/; - print $OUT "$id doesn't end with =cut\n" + print "$id doesn't end with =cut\n" if $contents !~ /=cut\n$/; - print $OUT "$id more than one cut line.\n" + print "$id more than one cut line.\n" if $contents =~ /=cut.*=cut/ms; - print $OUT "$id missing copyright\n" + print "$id missing copyright\n" if $contents !~ /Copyright .* The OpenSSL Project Authors/; - print $OUT "$id copyright not last\n" + print "$id copyright not last\n" if $contents =~ /head1 COPYRIGHT.*=head/ms; - print $OUT "$id head2 in All uppercase\n" + print "$id head2 in All uppercase\n" if $contents =~ /head2\s+[A-Z ]+\n/; - print $OUT "$id period in NAME section\n" - if $contents =~ /NAME.*\.\n.*SYNOPSIS/ms; - print $OUT "$id POD markup in NAME section\n" - if $contents =~ /NAME.*[<>].*SYNOPSIS/ms; + print "$id extra space after head\n" + 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; # Look for multiple consecutive openssl #include lines. # Consecutive because of files like md5.pod. Sometimes it's okay @@ -68,7 +116,7 @@ sub check() foreach my $line ( split /\n+/, $1 ) { if ( $line =~ m@include ', $temp + or die "Can't open $temp, $!"; podchecker($filename, $OUT); + close $OUT; + open $OUT, '<', $temp + or die "Can't read $temp, $!"; + while ( <$OUT> ) { + next if /\(section\) in.*deprecated/; + print; + } + close $OUT; + unlink $temp || warn "Can't remove $temp, $!"; } -open $OUT, '>', $temp - or die "Can't open $temp, $!"; -foreach (@ARGV ? @ARGV : glob('*/*.pod')) { +getopts('s'); + +foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) { &check($_); } -close $OUT; -my $count = 0; -open $OUT, '<', $temp - or die "Can't read $temp, $!"; -while ( <$OUT> ) { - next if /\(section\) in.*deprecated/; - $count++; - print; -} -close $OUT; -unlink $temp || warn "Can't remove $temp, $!"; - -exit $count; +exit; diff --git a/util/find-undoc-api.pl b/util/find-undoc-api.pl new file mode 100755 index 0000000000..7b2cb973b7 --- /dev/null +++ b/util/find-undoc-api.pl @@ -0,0 +1,82 @@ +#! /usr/bin/env perl +# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use warnings; + +use File::Spec::Functions; +use File::Basename; +#use File::Copy; +#use File::Path; +use lib catdir(dirname($0), "perl"); +use OpenSSL::Util::Pod; + +my %dups; + +sub parsenum() +{ + my $file = shift; + my @apis; + + open my $IN, '<', $file + or die "Can't open $file, $!, stopped"; + + while ( <$IN> ) { + next if /\sNOEXIST/; + next if /EXPORT_VAR_AS_FUNC/; + push @apis, $1 if /([^\s]+).\s/; + } + + close $IN; + + print "# Found ", scalar(@apis), " in $file\n"; + return sort @apis; +} + +sub getdocced() +{ + my $dir = shift; + my %return; + + foreach my $pod ( glob("$dir/*.pod") ) { + next if $pod eq 'doc/crypto/crypto.pod'; + next if $pod eq 'doc/ssl/ssl.pod'; + my %podinfo = extract_pod_info($pod); + foreach my $n ( @{$podinfo{names}} ) { + $return{$n} = $pod; + print "# Duplicate $n in $pod and $dups{$n}\n" + if defined $dups{$n}; + $dups{$n} = $pod; + } + } + + return %return; +} + +sub printem() +{ + my $docdir = shift; + my $numfile = shift; + my %docced = &getdocced($docdir); + my $count = 0; + + foreach my $func ( &parsenum($numfile) ) { + next if $docced{$func}; + + # Skip ASN1 utilities + next if $func =~ /^ASN1_/; + + print $func, "\n"; + $count++; + } + print "# Found $count missing from $numfile\n\n"; +} + + +&printem('doc/crypto', 'util/libcrypto.num'); +&printem('doc/ssl', 'util/libssl.num');