find-doc-nits revision 1.1.1.3.2.1 1 1.1 christos #! /usr/bin/env perl
2 1.1.1.3 christos # Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved.
3 1.1 christos #
4 1.1 christos # Licensed under the OpenSSL license (the "License"). You may not use
5 1.1 christos # this file except in compliance with the License. You can obtain a copy
6 1.1 christos # in the file LICENSE in the source distribution or at
7 1.1 christos # https://www.openssl.org/source/license.html
8 1.1 christos
9 1.1 christos
10 1.1 christos require 5.10.0;
11 1.1 christos use warnings;
12 1.1 christos use strict;
13 1.1 christos use Pod::Checker;
14 1.1 christos use File::Find;
15 1.1 christos use File::Basename;
16 1.1 christos use File::Spec::Functions;
17 1.1 christos use Getopt::Std;
18 1.1 christos use lib catdir(dirname($0), "perl");
19 1.1 christos use OpenSSL::Util::Pod;
20 1.1 christos
21 1.1 christos # Options.
22 1.1 christos our($opt_d);
23 1.1 christos our($opt_h);
24 1.1 christos our($opt_l);
25 1.1 christos our($opt_n);
26 1.1 christos our($opt_p);
27 1.1 christos our($opt_u);
28 1.1 christos our($opt_c);
29 1.1 christos
30 1.1 christos sub help()
31 1.1 christos {
32 1.1 christos print <<EOF;
33 1.1 christos Find small errors (nits) in documentation. Options:
34 1.1 christos -d Detailed list of undocumented (implies -u)
35 1.1 christos -l Print bogus links
36 1.1 christos -n Print nits in POD pages
37 1.1 christos -p Warn if non-public name documented (implies -n)
38 1.1 christos -u List undocumented functions
39 1.1 christos -h Print this help message
40 1.1 christos -c List undocumented commands and options
41 1.1 christos EOF
42 1.1 christos exit;
43 1.1 christos }
44 1.1 christos
45 1.1 christos my $temp = '/tmp/docnits.txt';
46 1.1 christos my $OUT;
47 1.1 christos my %public;
48 1.1 christos
49 1.1 christos my %mandatory_sections =
50 1.1 christos ( '*' => [ 'NAME', 'DESCRIPTION', 'COPYRIGHT' ],
51 1.1 christos 1 => [ 'SYNOPSIS', 'OPTIONS' ],
52 1.1 christos 3 => [ 'SYNOPSIS', 'RETURN VALUES' ],
53 1.1 christos 5 => [ ],
54 1.1 christos 7 => [ ] );
55 1.1 christos
56 1.1 christos # Cross-check functions in the NAME and SYNOPSIS section.
57 1.1 christos sub name_synopsis()
58 1.1 christos {
59 1.1 christos my $id = shift;
60 1.1 christos my $filename = shift;
61 1.1 christos my $contents = shift;
62 1.1 christos
63 1.1 christos # Get NAME section and all words in it.
64 1.1 christos return unless $contents =~ /=head1 NAME(.*)=head1 SYNOPSIS/ms;
65 1.1 christos my $tmp = $1;
66 1.1 christos $tmp =~ tr/\n/ /;
67 1.1 christos print "$id trailing comma before - in NAME\n" if $tmp =~ /, *-/;
68 1.1 christos $tmp =~ s/ -.*//g;
69 1.1 christos $tmp =~ s/ */ /g;
70 1.1 christos print "$id missing comma in NAME\n" if $tmp =~ /[^,] /;
71 1.1 christos $tmp =~ s/,//g;
72 1.1 christos
73 1.1 christos my $dirname = dirname($filename);
74 1.1 christos my $simplename = basename($filename);
75 1.1 christos $simplename =~ s/.pod$//;
76 1.1 christos my $foundfilename = 0;
77 1.1 christos my %foundfilenames = ();
78 1.1 christos my %names;
79 1.1 christos foreach my $n ( split ' ', $tmp ) {
80 1.1 christos $names{$n} = 1;
81 1.1 christos $foundfilename++ if $n eq $simplename;
82 1.1 christos $foundfilenames{$n} = 1
83 1.1 christos if -f "$dirname/$n.pod" && $n ne $simplename;
84 1.1 christos }
85 1.1 christos print "$id the following exist as other .pod files:\n",
86 1.1 christos join(" ", sort keys %foundfilenames), "\n"
87 1.1 christos if %foundfilenames;
88 1.1 christos print "$id $simplename (filename) missing from NAME section\n"
89 1.1 christos unless $foundfilename;
90 1.1 christos foreach my $n ( keys %names ) {
91 1.1 christos print "$id $n is not public\n"
92 1.1 christos if $opt_p and !defined $public{$n};
93 1.1 christos }
94 1.1 christos
95 1.1 christos # Find all functions in SYNOPSIS
96 1.1 christos return unless $contents =~ /=head1 SYNOPSIS(.*)=head1 DESCRIPTION/ms;
97 1.1 christos my $syn = $1;
98 1.1 christos foreach my $line ( split /\n+/, $syn ) {
99 1.1 christos my $sym;
100 1.1 christos $line =~ s/STACK_OF\([^)]+\)/int/g;
101 1.1 christos $line =~ s/__declspec\([^)]+\)//;
102 1.1 christos if ( $line =~ /env (\S*)=/ ) {
103 1.1 christos # environment variable env NAME=...
104 1.1 christos $sym = $1;
105 1.1 christos } elsif ( $line =~ /typedef.*\(\*(\S+)\)\(.*/ ) {
106 1.1 christos # a callback function pointer: typedef ... (*NAME)(...
107 1.1 christos $sym = $1;
108 1.1 christos } elsif ( $line =~ /typedef.* (\S+)\(.*/ ) {
109 1.1 christos # a callback function signature: typedef ... NAME(...
110 1.1 christos $sym = $1;
111 1.1 christos } elsif ( $line =~ /typedef.* (\S+);/ ) {
112 1.1 christos # a simple typedef: typedef ... NAME;
113 1.1 christos $sym = $1;
114 1.1 christos } elsif ( $line =~ /enum (\S*) \{/ ) {
115 1.1 christos # an enumeration: enum ... {
116 1.1 christos $sym = $1;
117 1.1 christos } elsif ( $line =~ /#define ([A-Za-z0-9_]+)/ ) {
118 1.1 christos $sym = $1;
119 1.1 christos } elsif ( $line =~ /([A-Za-z0-9_]+)\(/ ) {
120 1.1 christos $sym = $1;
121 1.1 christos }
122 1.1 christos else {
123 1.1 christos next;
124 1.1 christos }
125 1.1 christos print "$id $sym missing from NAME section\n"
126 1.1 christos unless defined $names{$sym};
127 1.1 christos $names{$sym} = 2;
128 1.1 christos
129 1.1 christos # Do some sanity checks on the prototype.
130 1.1 christos print "$id prototype missing spaces around commas: $line\n"
131 1.1 christos if ( $line =~ /[a-z0-9],[^ ]/ );
132 1.1 christos }
133 1.1 christos
134 1.1 christos foreach my $n ( keys %names ) {
135 1.1 christos next if $names{$n} == 2;
136 1.1 christos print "$id $n missing from SYNOPSIS\n";
137 1.1 christos }
138 1.1 christos }
139 1.1 christos
140 1.1.1.3.2.1 martin # Check if SECTION ($3) is located before BEFORE ($4)
141 1.1.1.3 christos sub check_section_location()
142 1.1.1.3 christos {
143 1.1.1.3.2.1 martin my $id = shift;
144 1.1.1.3 christos my $contents = shift;
145 1.1.1.3 christos my $section = shift;
146 1.1.1.3 christos my $before = shift;
147 1.1.1.3 christos
148 1.1.1.3.2.1 martin return
149 1.1.1.3.2.1 martin unless $contents =~ /=head1 $section/ and $contents =~ /=head1 $before/;
150 1.1.1.3.2.1 martin print "$id $section should be placed before $before section\n"
151 1.1.1.3 christos if $contents =~ /=head1 $before.*=head1 $section/ms;
152 1.1.1.3 christos }
153 1.1.1.3 christos
154 1.1 christos sub check()
155 1.1 christos {
156 1.1 christos my $filename = shift;
157 1.1 christos my $dirname = basename(dirname($filename));
158 1.1 christos
159 1.1 christos my $contents = '';
160 1.1 christos {
161 1.1 christos local $/ = undef;
162 1.1 christos open POD, $filename or die "Couldn't open $filename, $!";
163 1.1 christos $contents = <POD>;
164 1.1 christos close POD;
165 1.1 christos }
166 1.1 christos
167 1.1 christos my $id = "${filename}:1:";
168 1.1 christos
169 1.1.1.3.2.1 martin # Check ordering of some sections in man3
170 1.1.1.3.2.1 martin if ( $filename =~ m|man3/| ) {
171 1.1.1.3.2.1 martin &check_section_location($id, $contents, "RETURN VALUES", "EXAMPLES");
172 1.1.1.3.2.1 martin &check_section_location($id, $contents, "SEE ALSO", "HISTORY");
173 1.1.1.3.2.1 martin &check_section_location($id, $contents, "EXAMPLES", "SEE ALSO");
174 1.1.1.3.2.1 martin }
175 1.1.1.3.2.1 martin
176 1.1 christos &name_synopsis($id, $filename, $contents)
177 1.1 christos unless $contents =~ /=for comment generic/
178 1.1.1.2 christos or $filename =~ m@man[157]/@;
179 1.1 christos
180 1.1 christos print "$id doesn't start with =pod\n"
181 1.1 christos if $contents !~ /^=pod/;
182 1.1 christos print "$id doesn't end with =cut\n"
183 1.1 christos if $contents !~ /=cut\n$/;
184 1.1 christos print "$id more than one cut line.\n"
185 1.1 christos if $contents =~ /=cut.*=cut/ms;
186 1.1.1.3.2.1 martin print "$id EXAMPLE not EXAMPLES section.\n"
187 1.1.1.3.2.1 martin if $contents =~ /=head1 EXAMPLE[^S]/;
188 1.1.1.3.2.1 martin print "$id WARNING not WARNINGS section.\n"
189 1.1.1.3.2.1 martin if $contents =~ /=head1 WARNING[^S]/;
190 1.1 christos print "$id missing copyright\n"
191 1.1 christos if $contents !~ /Copyright .* The OpenSSL Project Authors/;
192 1.1 christos print "$id copyright not last\n"
193 1.1 christos if $contents =~ /head1 COPYRIGHT.*=head/ms;
194 1.1 christos print "$id head2 in All uppercase\n"
195 1.1 christos if $contents =~ /head2\s+[A-Z ]+\n/;
196 1.1 christos print "$id extra space after head\n"
197 1.1 christos if $contents =~ /=head\d\s\s+/;
198 1.1 christos print "$id period in NAME section\n"
199 1.1 christos if $contents =~ /=head1 NAME.*\.\n.*=head1 SYNOPSIS/ms;
200 1.1 christos print "$id POD markup in NAME section\n"
201 1.1 christos if $contents =~ /=head1 NAME.*[<>].*=head1 SYNOPSIS/ms;
202 1.1 christos print "$id Duplicate $1 in L<>\n"
203 1.1 christos if $contents =~ /L<([^>]*)\|([^>]*)>/ && $1 eq $2;
204 1.1 christos print "$id Bad =over $1\n"
205 1.1 christos if $contents =~ /=over([^ ][^24])/;
206 1.1 christos print "$id Possible version style issue\n"
207 1.1 christos if $contents =~ /OpenSSL version [019]/;
208 1.1 christos
209 1.1 christos if ( $contents !~ /=for comment multiple includes/ ) {
210 1.1 christos # Look for multiple consecutive openssl #include lines
211 1.1.1.2 christos # (non-consecutive lines are okay; see man3/MD5.pod).
212 1.1 christos if ( $contents =~ /=head1 SYNOPSIS(.*)=head1 DESCRIPTION/ms ) {
213 1.1 christos my $count = 0;
214 1.1 christos foreach my $line ( split /\n+/, $1 ) {
215 1.1 christos if ( $line =~ m@include <openssl/@ ) {
216 1.1 christos print "$id has multiple includes\n" if ++$count == 2;
217 1.1 christos } else {
218 1.1 christos $count = 0;
219 1.1 christos }
220 1.1 christos }
221 1.1 christos }
222 1.1 christos }
223 1.1 christos
224 1.1 christos open my $OUT, '>', $temp
225 1.1 christos or die "Can't open $temp, $!";
226 1.1 christos podchecker($filename, $OUT);
227 1.1 christos close $OUT;
228 1.1 christos open $OUT, '<', $temp
229 1.1 christos or die "Can't read $temp, $!";
230 1.1 christos while ( <$OUT> ) {
231 1.1 christos next if /\(section\) in.*deprecated/;
232 1.1 christos print;
233 1.1 christos }
234 1.1 christos close $OUT;
235 1.1 christos unlink $temp || warn "Can't remove $temp, $!";
236 1.1 christos
237 1.1.1.2 christos # Find what section this page is in; assume 3.
238 1.1.1.2 christos my $section = 3;
239 1.1.1.2 christos $section = $1 if $dirname =~ /man([1-9])/;
240 1.1.1.2 christos
241 1.1 christos foreach ((@{$mandatory_sections{'*'}}, @{$mandatory_sections{$section}})) {
242 1.1 christos # Skip "return values" if not -s
243 1.1 christos print "$id: missing $_ head1 section\n"
244 1.1 christos if $contents !~ /^=head1\s+${_}\s*$/m;
245 1.1 christos }
246 1.1 christos }
247 1.1 christos
248 1.1 christos my %dups;
249 1.1 christos
250 1.1 christos sub parsenum()
251 1.1 christos {
252 1.1 christos my $file = shift;
253 1.1 christos my @apis;
254 1.1 christos
255 1.1 christos open my $IN, '<', $file
256 1.1 christos or die "Can't open $file, $!, stopped";
257 1.1 christos
258 1.1 christos while ( <$IN> ) {
259 1.1 christos next if /^#/;
260 1.1 christos next if /\bNOEXIST\b/;
261 1.1 christos next if /\bEXPORT_VAR_AS_FUNC\b/;
262 1.1 christos my @fields = split();
263 1.1 christos die "Malformed line $_"
264 1.1 christos if scalar @fields != 2 && scalar @fields != 4;
265 1.1 christos push @apis, $fields[0];
266 1.1 christos }
267 1.1 christos
268 1.1 christos close $IN;
269 1.1 christos
270 1.1 christos print "# Found ", scalar(@apis), " in $file\n" unless $opt_p;
271 1.1 christos return sort @apis;
272 1.1 christos }
273 1.1 christos
274 1.1 christos sub getdocced()
275 1.1 christos {
276 1.1 christos my $dir = shift;
277 1.1 christos my %return;
278 1.1 christos
279 1.1 christos foreach my $pod ( glob("$dir/*.pod") ) {
280 1.1 christos my %podinfo = extract_pod_info($pod);
281 1.1 christos foreach my $n ( @{$podinfo{names}} ) {
282 1.1 christos $return{$n} = $pod;
283 1.1 christos print "# Duplicate $n in $pod and $dups{$n}\n"
284 1.1 christos if defined $dups{$n} && $dups{$n} ne $pod;
285 1.1 christos $dups{$n} = $pod;
286 1.1 christos }
287 1.1 christos }
288 1.1 christos
289 1.1 christos return %return;
290 1.1 christos }
291 1.1 christos
292 1.1 christos my %docced;
293 1.1 christos
294 1.1 christos sub checkmacros()
295 1.1 christos {
296 1.1 christos my $count = 0;
297 1.1 christos
298 1.1 christos print "# Checking macros (approximate)\n";
299 1.1 christos foreach my $f ( glob('include/openssl/*.h') ) {
300 1.1 christos # Skip some internals we don't want to document yet.
301 1.1 christos next if $f eq 'include/openssl/asn1.h';
302 1.1 christos next if $f eq 'include/openssl/asn1t.h';
303 1.1 christos next if $f eq 'include/openssl/err.h';
304 1.1 christos open(IN, $f) || die "Can't open $f, $!";
305 1.1 christos while ( <IN> ) {
306 1.1 christos next unless /^#\s*define\s*(\S+)\(/;
307 1.1 christos my $macro = $1;
308 1.1 christos next if $docced{$macro};
309 1.1 christos next if $macro =~ /i2d_/
310 1.1 christos || $macro =~ /d2i_/
311 1.1 christos || $macro =~ /DEPRECATEDIN/
312 1.1 christos || $macro =~ /IMPLEMENT_/
313 1.1 christos || $macro =~ /DECLARE_/;
314 1.1 christos print "$f:$macro\n" if $opt_d;
315 1.1 christos $count++;
316 1.1 christos }
317 1.1 christos close(IN);
318 1.1 christos }
319 1.1 christos print "# Found $count macros missing (not all should be documented)\n"
320 1.1 christos }
321 1.1 christos
322 1.1 christos sub printem()
323 1.1 christos {
324 1.1 christos my $libname = shift;
325 1.1 christos my $numfile = shift;
326 1.1 christos my $count = 0;
327 1.1 christos
328 1.1 christos foreach my $func ( &parsenum($numfile) ) {
329 1.1 christos next if $docced{$func};
330 1.1 christos
331 1.1 christos # Skip ASN1 utilities
332 1.1 christos next if $func =~ /^ASN1_/;
333 1.1 christos
334 1.1 christos print "$libname:$func\n" if $opt_d;
335 1.1 christos $count++;
336 1.1 christos }
337 1.1 christos print "# Found $count missing from $numfile\n\n";
338 1.1 christos }
339 1.1 christos
340 1.1 christos
341 1.1 christos # Collection of links in each POD file.
342 1.1 christos # filename => [ "foo(1)", "bar(3)", ... ]
343 1.1 christos my %link_collection = ();
344 1.1 christos # Collection of names in each POD file.
345 1.1 christos # "name(s)" => filename
346 1.1 christos my %name_collection = ();
347 1.1 christos
348 1.1 christos sub collectnames {
349 1.1 christos my $filename = shift;
350 1.1 christos $filename =~ m|man(\d)/|;
351 1.1 christos my $section = $1;
352 1.1 christos my $simplename = basename($filename, ".pod");
353 1.1 christos my $id = "${filename}:1:";
354 1.1 christos
355 1.1 christos my $contents = '';
356 1.1 christos {
357 1.1 christos local $/ = undef;
358 1.1 christos open POD, $filename or die "Couldn't open $filename, $!";
359 1.1 christos $contents = <POD>;
360 1.1 christos close POD;
361 1.1 christos }
362 1.1 christos
363 1.1 christos $contents =~ /=head1 NAME([^=]*)=head1 /ms;
364 1.1 christos my $tmp = $1;
365 1.1 christos unless (defined $tmp) {
366 1.1 christos print "$id weird name section\n";
367 1.1 christos return;
368 1.1 christos }
369 1.1 christos $tmp =~ tr/\n/ /;
370 1.1 christos $tmp =~ s/-.*//g;
371 1.1 christos
372 1.1 christos my @names = map { s/\s+//g; $_ } split(/,/, $tmp);
373 1.1 christos unless (grep { $simplename eq $_ } @names) {
374 1.1 christos print "$id missing $simplename\n";
375 1.1 christos push @names, $simplename;
376 1.1 christos }
377 1.1 christos foreach my $name (@names) {
378 1.1 christos next if $name eq "";
379 1.1 christos my $name_sec = "$name($section)";
380 1.1 christos if (! exists $name_collection{$name_sec}) {
381 1.1 christos $name_collection{$name_sec} = $filename;
382 1.1 christos } else { #elsif ($filename ne $name_collection{$name_sec}) {
383 1.1 christos print "$id $name_sec also in $name_collection{$name_sec}\n";
384 1.1 christos }
385 1.1 christos }
386 1.1 christos
387 1.1 christos my @foreign_names =
388 1.1 christos map { map { s/\s+//g; $_ } split(/,/, $_) }
389 1.1 christos $contents =~ /=for\s+comment\s+foreign\s+manuals:\s*(.*)\n\n/;
390 1.1 christos foreach (@foreign_names) {
391 1.1 christos $name_collection{$_} = undef; # It still exists!
392 1.1 christos }
393 1.1 christos
394 1.1 christos my @links = $contents =~ /L<
395 1.1 christos # if the link is of the form L<something|name(s)>,
396 1.1 christos # then remove 'something'. Note that 'something'
397 1.1 christos # may contain POD codes as well...
398 1.1 christos (?:(?:[^\|]|<[^>]*>)*\|)?
399 1.1.1.2 christos # we're only interested in references that have
400 1.1 christos # a one digit section number
401 1.1 christos ([^\/>\(]+\(\d\))
402 1.1 christos /gx;
403 1.1 christos $link_collection{$filename} = [ @links ];
404 1.1 christos }
405 1.1 christos
406 1.1 christos sub checklinks {
407 1.1 christos foreach my $filename (sort keys %link_collection) {
408 1.1 christos foreach my $link (@{$link_collection{$filename}}) {
409 1.1 christos print "${filename}:1: reference to non-existing $link\n"
410 1.1 christos unless exists $name_collection{$link};
411 1.1 christos }
412 1.1 christos }
413 1.1 christos }
414 1.1 christos
415 1.1 christos sub publicize() {
416 1.1 christos foreach my $name ( &parsenum('util/libcrypto.num') ) {
417 1.1 christos $public{$name} = 1;
418 1.1 christos }
419 1.1 christos foreach my $name ( &parsenum('util/libssl.num') ) {
420 1.1 christos $public{$name} = 1;
421 1.1 christos }
422 1.1 christos foreach my $name ( &parsenum('util/private.num') ) {
423 1.1 christos $public{$name} = 1;
424 1.1 christos }
425 1.1 christos }
426 1.1 christos
427 1.1 christos my %skips = (
428 1.1 christos 'aes128' => 1,
429 1.1 christos 'aes192' => 1,
430 1.1 christos 'aes256' => 1,
431 1.1 christos 'aria128' => 1,
432 1.1 christos 'aria192' => 1,
433 1.1 christos 'aria256' => 1,
434 1.1 christos 'camellia128' => 1,
435 1.1 christos 'camellia192' => 1,
436 1.1 christos 'camellia256' => 1,
437 1.1 christos 'des' => 1,
438 1.1 christos 'des3' => 1,
439 1.1 christos 'idea' => 1,
440 1.1 christos '[cipher]' => 1,
441 1.1 christos '[digest]' => 1,
442 1.1 christos );
443 1.1 christos
444 1.1 christos sub checkflags() {
445 1.1 christos my $cmd = shift;
446 1.1 christos my %cmdopts;
447 1.1 christos my %docopts;
448 1.1 christos my $ok = 1;
449 1.1 christos
450 1.1 christos # Get the list of options in the command.
451 1.1 christos open CFH, "./apps/openssl list --options $cmd|"
452 1.1 christos || die "Can list options for $cmd, $!";
453 1.1 christos while ( <CFH> ) {
454 1.1 christos chop;
455 1.1 christos s/ .$//;
456 1.1 christos $cmdopts{$_} = 1;
457 1.1 christos }
458 1.1 christos close CFH;
459 1.1 christos
460 1.1 christos # Get the list of flags from the synopsis
461 1.1.1.2 christos open CFH, "<doc/man1/$cmd.pod"
462 1.1 christos || die "Can't open $cmd.pod, $!";
463 1.1 christos while ( <CFH> ) {
464 1.1 christos chop;
465 1.1 christos last if /DESCRIPTION/;
466 1.1 christos next unless /\[B<-([^ >]+)/;
467 1.1 christos $docopts{$1} = 1;
468 1.1 christos }
469 1.1 christos close CFH;
470 1.1 christos
471 1.1 christos # See what's in the command not the manpage.
472 1.1 christos my @undocced = ();
473 1.1 christos foreach my $k ( keys %cmdopts ) {
474 1.1 christos push @undocced, $k unless $docopts{$k};
475 1.1 christos }
476 1.1 christos if ( scalar @undocced > 0 ) {
477 1.1 christos $ok = 0;
478 1.1 christos foreach ( @undocced ) {
479 1.1.1.2 christos print "doc/man1/$cmd.pod: Missing -$_\n";
480 1.1 christos }
481 1.1 christos }
482 1.1 christos
483 1.1 christos # See what's in the command not the manpage.
484 1.1 christos my @unimpl = ();
485 1.1 christos foreach my $k ( keys %docopts ) {
486 1.1 christos push @unimpl, $k unless $cmdopts{$k};
487 1.1 christos }
488 1.1 christos if ( scalar @unimpl > 0 ) {
489 1.1 christos $ok = 0;
490 1.1 christos foreach ( @unimpl ) {
491 1.1 christos next if defined $skips{$_};
492 1.1.1.2 christos print "doc/man1/$cmd.pod: Not implemented -$_\n";
493 1.1 christos }
494 1.1 christos }
495 1.1 christos
496 1.1 christos return $ok;
497 1.1 christos }
498 1.1 christos
499 1.1.1.2 christos getopts('cdlnphu');
500 1.1 christos
501 1.1 christos &help() if $opt_h;
502 1.1.1.2 christos $opt_n = 1 if $opt_p;
503 1.1 christos $opt_u = 1 if $opt_d;
504 1.1 christos
505 1.1.1.2 christos die "Need one of -[cdlnpu] flags.\n"
506 1.1 christos unless $opt_c or $opt_l or $opt_n or $opt_u;
507 1.1 christos
508 1.1 christos if ( $opt_c ) {
509 1.1 christos my $ok = 1;
510 1.1 christos my @commands = ();
511 1.1 christos
512 1.1 christos # Get list of commands.
513 1.1 christos open FH, "./apps/openssl list -1 -commands|"
514 1.1 christos || die "Can't list commands, $!";
515 1.1 christos while ( <FH> ) {
516 1.1 christos chop;
517 1.1 christos push @commands, $_;
518 1.1 christos }
519 1.1 christos close FH;
520 1.1 christos
521 1.1 christos # See if each has a manpage.
522 1.1 christos foreach ( @commands ) {
523 1.1 christos next if $_ eq 'help' || $_ eq 'exit';
524 1.1.1.2 christos if ( ! -f "doc/man1/$_.pod" ) {
525 1.1.1.2 christos print "doc/man1/$_.pod does not exist\n";
526 1.1 christos $ok = 0;
527 1.1 christos } else {
528 1.1 christos $ok = 0 if not &checkflags($_);
529 1.1 christos }
530 1.1 christos }
531 1.1 christos
532 1.1 christos # See what help is missing.
533 1.1 christos open FH, "./apps/openssl list --missing-help |"
534 1.1 christos || die "Can't list missing help, $!";
535 1.1 christos while ( <FH> ) {
536 1.1 christos chop;
537 1.1 christos my ($cmd, $flag) = split;
538 1.1 christos print "$cmd has no help for -$flag\n";
539 1.1 christos $ok = 0;
540 1.1 christos }
541 1.1 christos close FH;
542 1.1 christos
543 1.1 christos exit 1 if not $ok;
544 1.1 christos }
545 1.1 christos
546 1.1 christos if ( $opt_l ) {
547 1.1 christos foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) {
548 1.1 christos collectnames($_);
549 1.1 christos }
550 1.1 christos checklinks();
551 1.1 christos }
552 1.1 christos
553 1.1 christos if ( $opt_n ) {
554 1.1 christos &publicize() if $opt_p;
555 1.1 christos foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) {
556 1.1 christos &check($_);
557 1.1 christos }
558 1.1 christos }
559 1.1 christos
560 1.1 christos if ( $opt_u ) {
561 1.1.1.2 christos my %temp = &getdocced('doc/man3');
562 1.1 christos foreach ( keys %temp ) {
563 1.1 christos $docced{$_} = $temp{$_};
564 1.1 christos }
565 1.1 christos &printem('crypto', 'util/libcrypto.num');
566 1.1 christos &printem('ssl', 'util/libssl.num');
567 1.1 christos &checkmacros();
568 1.1 christos }
569 1.1 christos
570 1.1 christos exit;
571