#! /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
# 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()
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
$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;
$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"
}
}
-# 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()
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]/@;
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"
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;
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;
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';
|| $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;
}
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 = '';
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;
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";
}
}
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;
}
if ( $opt_l ) {
- foreach (@ARGV ? @ARGV : (glob('doc/*/*.pod'),
+ foreach (@ARGV ? @ARGV : (glob('doc/*/*.pod'), glob('doc/*/*.pod.in'),
glob('doc/internal/*/*.pod'))) {
collectnames($_);
}
if ( $opt_n ) {
&publicize() if $opt_p;
- foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) {
+ foreach (@ARGV ? @ARGV : (glob('doc/*/*.pod'), glob('doc/*/*.pod.in'))) {
&check($_);
}
{
}
}
-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();
}