find-doc-nits revision 1.1.1.2 1 1.1 christos #! /usr/bin/env perl
2 1.1.1.2 christos # Copyright 2002-2018 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 christos sub check()
141 1.1 christos {
142 1.1 christos my $filename = shift;
143 1.1 christos my $dirname = basename(dirname($filename));
144 1.1 christos
145 1.1 christos my $contents = '';
146 1.1 christos {
147 1.1 christos local $/ = undef;
148 1.1 christos open POD, $filename or die "Couldn't open $filename, $!";
149 1.1 christos $contents = <POD>;
150 1.1 christos close POD;
151 1.1 christos }
152 1.1 christos
153 1.1 christos my $id = "${filename}:1:";
154 1.1 christos
155 1.1 christos &name_synopsis($id, $filename, $contents)
156 1.1 christos unless $contents =~ /=for comment generic/
157 1.1.1.2 christos or $filename =~ m@man[157]/@;
158 1.1 christos
159 1.1 christos print "$id doesn't start with =pod\n"
160 1.1 christos if $contents !~ /^=pod/;
161 1.1 christos print "$id doesn't end with =cut\n"
162 1.1 christos if $contents !~ /=cut\n$/;
163 1.1 christos print "$id more than one cut line.\n"
164 1.1 christos if $contents =~ /=cut.*=cut/ms;
165 1.1 christos print "$id missing copyright\n"
166 1.1 christos if $contents !~ /Copyright .* The OpenSSL Project Authors/;
167 1.1 christos print "$id copyright not last\n"
168 1.1 christos if $contents =~ /head1 COPYRIGHT.*=head/ms;
169 1.1 christos print "$id head2 in All uppercase\n"
170 1.1 christos if $contents =~ /head2\s+[A-Z ]+\n/;
171 1.1 christos print "$id extra space after head\n"
172 1.1 christos if $contents =~ /=head\d\s\s+/;
173 1.1 christos print "$id period in NAME section\n"
174 1.1 christos if $contents =~ /=head1 NAME.*\.\n.*=head1 SYNOPSIS/ms;
175 1.1 christos print "$id POD markup in NAME section\n"
176 1.1 christos if $contents =~ /=head1 NAME.*[<>].*=head1 SYNOPSIS/ms;
177 1.1 christos print "$id Duplicate $1 in L<>\n"
178 1.1 christos if $contents =~ /L<([^>]*)\|([^>]*)>/ && $1 eq $2;
179 1.1 christos print "$id Bad =over $1\n"
180 1.1 christos if $contents =~ /=over([^ ][^24])/;
181 1.1 christos print "$id Possible version style issue\n"
182 1.1 christos if $contents =~ /OpenSSL version [019]/;
183 1.1 christos
184 1.1 christos if ( $contents !~ /=for comment multiple includes/ ) {
185 1.1 christos # Look for multiple consecutive openssl #include lines
186 1.1.1.2 christos # (non-consecutive lines are okay; see man3/MD5.pod).
187 1.1 christos if ( $contents =~ /=head1 SYNOPSIS(.*)=head1 DESCRIPTION/ms ) {
188 1.1 christos my $count = 0;
189 1.1 christos foreach my $line ( split /\n+/, $1 ) {
190 1.1 christos if ( $line =~ m@include <openssl/@ ) {
191 1.1 christos print "$id has multiple includes\n" if ++$count == 2;
192 1.1 christos } else {
193 1.1 christos $count = 0;
194 1.1 christos }
195 1.1 christos }
196 1.1 christos }
197 1.1 christos }
198 1.1 christos
199 1.1 christos open my $OUT, '>', $temp
200 1.1 christos or die "Can't open $temp, $!";
201 1.1 christos podchecker($filename, $OUT);
202 1.1 christos close $OUT;
203 1.1 christos open $OUT, '<', $temp
204 1.1 christos or die "Can't read $temp, $!";
205 1.1 christos while ( <$OUT> ) {
206 1.1 christos next if /\(section\) in.*deprecated/;
207 1.1 christos print;
208 1.1 christos }
209 1.1 christos close $OUT;
210 1.1 christos unlink $temp || warn "Can't remove $temp, $!";
211 1.1 christos
212 1.1.1.2 christos # Find what section this page is in; assume 3.
213 1.1.1.2 christos my $section = 3;
214 1.1.1.2 christos $section = $1 if $dirname =~ /man([1-9])/;
215 1.1.1.2 christos
216 1.1 christos foreach ((@{$mandatory_sections{'*'}}, @{$mandatory_sections{$section}})) {
217 1.1 christos # Skip "return values" if not -s
218 1.1 christos print "$id: missing $_ head1 section\n"
219 1.1 christos if $contents !~ /^=head1\s+${_}\s*$/m;
220 1.1 christos }
221 1.1 christos }
222 1.1 christos
223 1.1 christos my %dups;
224 1.1 christos
225 1.1 christos sub parsenum()
226 1.1 christos {
227 1.1 christos my $file = shift;
228 1.1 christos my @apis;
229 1.1 christos
230 1.1 christos open my $IN, '<', $file
231 1.1 christos or die "Can't open $file, $!, stopped";
232 1.1 christos
233 1.1 christos while ( <$IN> ) {
234 1.1 christos next if /^#/;
235 1.1 christos next if /\bNOEXIST\b/;
236 1.1 christos next if /\bEXPORT_VAR_AS_FUNC\b/;
237 1.1 christos my @fields = split();
238 1.1 christos die "Malformed line $_"
239 1.1 christos if scalar @fields != 2 && scalar @fields != 4;
240 1.1 christos push @apis, $fields[0];
241 1.1 christos }
242 1.1 christos
243 1.1 christos close $IN;
244 1.1 christos
245 1.1 christos print "# Found ", scalar(@apis), " in $file\n" unless $opt_p;
246 1.1 christos return sort @apis;
247 1.1 christos }
248 1.1 christos
249 1.1 christos sub getdocced()
250 1.1 christos {
251 1.1 christos my $dir = shift;
252 1.1 christos my %return;
253 1.1 christos
254 1.1 christos foreach my $pod ( glob("$dir/*.pod") ) {
255 1.1 christos my %podinfo = extract_pod_info($pod);
256 1.1 christos foreach my $n ( @{$podinfo{names}} ) {
257 1.1 christos $return{$n} = $pod;
258 1.1 christos print "# Duplicate $n in $pod and $dups{$n}\n"
259 1.1 christos if defined $dups{$n} && $dups{$n} ne $pod;
260 1.1 christos $dups{$n} = $pod;
261 1.1 christos }
262 1.1 christos }
263 1.1 christos
264 1.1 christos return %return;
265 1.1 christos }
266 1.1 christos
267 1.1 christos my %docced;
268 1.1 christos
269 1.1 christos sub checkmacros()
270 1.1 christos {
271 1.1 christos my $count = 0;
272 1.1 christos
273 1.1 christos print "# Checking macros (approximate)\n";
274 1.1 christos foreach my $f ( glob('include/openssl/*.h') ) {
275 1.1 christos # Skip some internals we don't want to document yet.
276 1.1 christos next if $f eq 'include/openssl/asn1.h';
277 1.1 christos next if $f eq 'include/openssl/asn1t.h';
278 1.1 christos next if $f eq 'include/openssl/err.h';
279 1.1 christos open(IN, $f) || die "Can't open $f, $!";
280 1.1 christos while ( <IN> ) {
281 1.1 christos next unless /^#\s*define\s*(\S+)\(/;
282 1.1 christos my $macro = $1;
283 1.1 christos next if $docced{$macro};
284 1.1 christos next if $macro =~ /i2d_/
285 1.1 christos || $macro =~ /d2i_/
286 1.1 christos || $macro =~ /DEPRECATEDIN/
287 1.1 christos || $macro =~ /IMPLEMENT_/
288 1.1 christos || $macro =~ /DECLARE_/;
289 1.1 christos print "$f:$macro\n" if $opt_d;
290 1.1 christos $count++;
291 1.1 christos }
292 1.1 christos close(IN);
293 1.1 christos }
294 1.1 christos print "# Found $count macros missing (not all should be documented)\n"
295 1.1 christos }
296 1.1 christos
297 1.1 christos sub printem()
298 1.1 christos {
299 1.1 christos my $libname = shift;
300 1.1 christos my $numfile = shift;
301 1.1 christos my $count = 0;
302 1.1 christos
303 1.1 christos foreach my $func ( &parsenum($numfile) ) {
304 1.1 christos next if $docced{$func};
305 1.1 christos
306 1.1 christos # Skip ASN1 utilities
307 1.1 christos next if $func =~ /^ASN1_/;
308 1.1 christos
309 1.1 christos print "$libname:$func\n" if $opt_d;
310 1.1 christos $count++;
311 1.1 christos }
312 1.1 christos print "# Found $count missing from $numfile\n\n";
313 1.1 christos }
314 1.1 christos
315 1.1 christos
316 1.1 christos # Collection of links in each POD file.
317 1.1 christos # filename => [ "foo(1)", "bar(3)", ... ]
318 1.1 christos my %link_collection = ();
319 1.1 christos # Collection of names in each POD file.
320 1.1 christos # "name(s)" => filename
321 1.1 christos my %name_collection = ();
322 1.1 christos
323 1.1 christos sub collectnames {
324 1.1 christos my $filename = shift;
325 1.1 christos $filename =~ m|man(\d)/|;
326 1.1 christos my $section = $1;
327 1.1 christos my $simplename = basename($filename, ".pod");
328 1.1 christos my $id = "${filename}:1:";
329 1.1 christos
330 1.1 christos my $contents = '';
331 1.1 christos {
332 1.1 christos local $/ = undef;
333 1.1 christos open POD, $filename or die "Couldn't open $filename, $!";
334 1.1 christos $contents = <POD>;
335 1.1 christos close POD;
336 1.1 christos }
337 1.1 christos
338 1.1 christos $contents =~ /=head1 NAME([^=]*)=head1 /ms;
339 1.1 christos my $tmp = $1;
340 1.1 christos unless (defined $tmp) {
341 1.1 christos print "$id weird name section\n";
342 1.1 christos return;
343 1.1 christos }
344 1.1 christos $tmp =~ tr/\n/ /;
345 1.1 christos $tmp =~ s/-.*//g;
346 1.1 christos
347 1.1 christos my @names = map { s/\s+//g; $_ } split(/,/, $tmp);
348 1.1 christos unless (grep { $simplename eq $_ } @names) {
349 1.1 christos print "$id missing $simplename\n";
350 1.1 christos push @names, $simplename;
351 1.1 christos }
352 1.1 christos foreach my $name (@names) {
353 1.1 christos next if $name eq "";
354 1.1 christos my $name_sec = "$name($section)";
355 1.1 christos if (! exists $name_collection{$name_sec}) {
356 1.1 christos $name_collection{$name_sec} = $filename;
357 1.1 christos } else { #elsif ($filename ne $name_collection{$name_sec}) {
358 1.1 christos print "$id $name_sec also in $name_collection{$name_sec}\n";
359 1.1 christos }
360 1.1 christos }
361 1.1 christos
362 1.1 christos my @foreign_names =
363 1.1 christos map { map { s/\s+//g; $_ } split(/,/, $_) }
364 1.1 christos $contents =~ /=for\s+comment\s+foreign\s+manuals:\s*(.*)\n\n/;
365 1.1 christos foreach (@foreign_names) {
366 1.1 christos $name_collection{$_} = undef; # It still exists!
367 1.1 christos }
368 1.1 christos
369 1.1 christos my @links = $contents =~ /L<
370 1.1 christos # if the link is of the form L<something|name(s)>,
371 1.1 christos # then remove 'something'. Note that 'something'
372 1.1 christos # may contain POD codes as well...
373 1.1 christos (?:(?:[^\|]|<[^>]*>)*\|)?
374 1.1.1.2 christos # we're only interested in references that have
375 1.1 christos # a one digit section number
376 1.1 christos ([^\/>\(]+\(\d\))
377 1.1 christos /gx;
378 1.1 christos $link_collection{$filename} = [ @links ];
379 1.1 christos }
380 1.1 christos
381 1.1 christos sub checklinks {
382 1.1 christos foreach my $filename (sort keys %link_collection) {
383 1.1 christos foreach my $link (@{$link_collection{$filename}}) {
384 1.1 christos print "${filename}:1: reference to non-existing $link\n"
385 1.1 christos unless exists $name_collection{$link};
386 1.1 christos }
387 1.1 christos }
388 1.1 christos }
389 1.1 christos
390 1.1 christos sub publicize() {
391 1.1 christos foreach my $name ( &parsenum('util/libcrypto.num') ) {
392 1.1 christos $public{$name} = 1;
393 1.1 christos }
394 1.1 christos foreach my $name ( &parsenum('util/libssl.num') ) {
395 1.1 christos $public{$name} = 1;
396 1.1 christos }
397 1.1 christos foreach my $name ( &parsenum('util/private.num') ) {
398 1.1 christos $public{$name} = 1;
399 1.1 christos }
400 1.1 christos }
401 1.1 christos
402 1.1 christos my %skips = (
403 1.1 christos 'aes128' => 1,
404 1.1 christos 'aes192' => 1,
405 1.1 christos 'aes256' => 1,
406 1.1 christos 'aria128' => 1,
407 1.1 christos 'aria192' => 1,
408 1.1 christos 'aria256' => 1,
409 1.1 christos 'camellia128' => 1,
410 1.1 christos 'camellia192' => 1,
411 1.1 christos 'camellia256' => 1,
412 1.1 christos 'des' => 1,
413 1.1 christos 'des3' => 1,
414 1.1 christos 'idea' => 1,
415 1.1 christos '[cipher]' => 1,
416 1.1 christos '[digest]' => 1,
417 1.1 christos );
418 1.1 christos
419 1.1 christos sub checkflags() {
420 1.1 christos my $cmd = shift;
421 1.1 christos my %cmdopts;
422 1.1 christos my %docopts;
423 1.1 christos my $ok = 1;
424 1.1 christos
425 1.1 christos # Get the list of options in the command.
426 1.1 christos open CFH, "./apps/openssl list --options $cmd|"
427 1.1 christos || die "Can list options for $cmd, $!";
428 1.1 christos while ( <CFH> ) {
429 1.1 christos chop;
430 1.1 christos s/ .$//;
431 1.1 christos $cmdopts{$_} = 1;
432 1.1 christos }
433 1.1 christos close CFH;
434 1.1 christos
435 1.1 christos # Get the list of flags from the synopsis
436 1.1.1.2 christos open CFH, "<doc/man1/$cmd.pod"
437 1.1 christos || die "Can't open $cmd.pod, $!";
438 1.1 christos while ( <CFH> ) {
439 1.1 christos chop;
440 1.1 christos last if /DESCRIPTION/;
441 1.1 christos next unless /\[B<-([^ >]+)/;
442 1.1 christos $docopts{$1} = 1;
443 1.1 christos }
444 1.1 christos close CFH;
445 1.1 christos
446 1.1 christos # See what's in the command not the manpage.
447 1.1 christos my @undocced = ();
448 1.1 christos foreach my $k ( keys %cmdopts ) {
449 1.1 christos push @undocced, $k unless $docopts{$k};
450 1.1 christos }
451 1.1 christos if ( scalar @undocced > 0 ) {
452 1.1 christos $ok = 0;
453 1.1 christos foreach ( @undocced ) {
454 1.1.1.2 christos print "doc/man1/$cmd.pod: Missing -$_\n";
455 1.1 christos }
456 1.1 christos }
457 1.1 christos
458 1.1 christos # See what's in the command not the manpage.
459 1.1 christos my @unimpl = ();
460 1.1 christos foreach my $k ( keys %docopts ) {
461 1.1 christos push @unimpl, $k unless $cmdopts{$k};
462 1.1 christos }
463 1.1 christos if ( scalar @unimpl > 0 ) {
464 1.1 christos $ok = 0;
465 1.1 christos foreach ( @unimpl ) {
466 1.1 christos next if defined $skips{$_};
467 1.1.1.2 christos print "doc/man1/$cmd.pod: Not implemented -$_\n";
468 1.1 christos }
469 1.1 christos }
470 1.1 christos
471 1.1 christos return $ok;
472 1.1 christos }
473 1.1 christos
474 1.1.1.2 christos getopts('cdlnphu');
475 1.1 christos
476 1.1 christos &help() if $opt_h;
477 1.1.1.2 christos $opt_n = 1 if $opt_p;
478 1.1 christos $opt_u = 1 if $opt_d;
479 1.1 christos
480 1.1.1.2 christos die "Need one of -[cdlnpu] flags.\n"
481 1.1 christos unless $opt_c or $opt_l or $opt_n or $opt_u;
482 1.1 christos
483 1.1 christos if ( $opt_c ) {
484 1.1 christos my $ok = 1;
485 1.1 christos my @commands = ();
486 1.1 christos
487 1.1 christos # Get list of commands.
488 1.1 christos open FH, "./apps/openssl list -1 -commands|"
489 1.1 christos || die "Can't list commands, $!";
490 1.1 christos while ( <FH> ) {
491 1.1 christos chop;
492 1.1 christos push @commands, $_;
493 1.1 christos }
494 1.1 christos close FH;
495 1.1 christos
496 1.1 christos # See if each has a manpage.
497 1.1 christos foreach ( @commands ) {
498 1.1 christos next if $_ eq 'help' || $_ eq 'exit';
499 1.1.1.2 christos if ( ! -f "doc/man1/$_.pod" ) {
500 1.1.1.2 christos print "doc/man1/$_.pod does not exist\n";
501 1.1 christos $ok = 0;
502 1.1 christos } else {
503 1.1 christos $ok = 0 if not &checkflags($_);
504 1.1 christos }
505 1.1 christos }
506 1.1 christos
507 1.1 christos # See what help is missing.
508 1.1 christos open FH, "./apps/openssl list --missing-help |"
509 1.1 christos || die "Can't list missing help, $!";
510 1.1 christos while ( <FH> ) {
511 1.1 christos chop;
512 1.1 christos my ($cmd, $flag) = split;
513 1.1 christos print "$cmd has no help for -$flag\n";
514 1.1 christos $ok = 0;
515 1.1 christos }
516 1.1 christos close FH;
517 1.1 christos
518 1.1 christos exit 1 if not $ok;
519 1.1 christos }
520 1.1 christos
521 1.1 christos if ( $opt_l ) {
522 1.1 christos foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) {
523 1.1 christos collectnames($_);
524 1.1 christos }
525 1.1 christos checklinks();
526 1.1 christos }
527 1.1 christos
528 1.1 christos if ( $opt_n ) {
529 1.1 christos &publicize() if $opt_p;
530 1.1 christos foreach (@ARGV ? @ARGV : glob('doc/*/*.pod')) {
531 1.1 christos &check($_);
532 1.1 christos }
533 1.1 christos }
534 1.1 christos
535 1.1 christos if ( $opt_u ) {
536 1.1.1.2 christos my %temp = &getdocced('doc/man3');
537 1.1 christos foreach ( keys %temp ) {
538 1.1 christos $docced{$_} = $temp{$_};
539 1.1 christos }
540 1.1 christos &printem('crypto', 'util/libcrypto.num');
541 1.1 christos &printem('ssl', 'util/libssl.num');
542 1.1 christos &checkmacros();
543 1.1 christos }
544 1.1 christos
545 1.1 christos exit;
546