| @@ -1,19 +1,19 @@ | | | @@ -1,19 +1,19 @@ |
1 | #!@PERL5@ | | 1 | #!@PERL5@ |
2 | # | | 2 | # |
3 | # $OpenBSD: mdoclint,v 1.14 2009/04/13 12:40:05 espie Exp $ | | 3 | # $OpenBSD: mdoclint,v 1.14 2009/04/13 12:40:05 espie Exp $ |
4 | # $NetBSD: mdoclint,v 1.21 2013/01/01 01:42:08 jnemeth Exp $ | | 4 | # $NetBSD: mdoclint,v 1.22 2013/03/06 21:26:45 wiz Exp $ |
5 | # | | 5 | # |
6 | # Copyright (c) 2001-2012 Thomas Klausner | | 6 | # Copyright (c) 2001-2013 Thomas Klausner |
7 | # All rights reserved. | | 7 | # All rights reserved. |
8 | # | | 8 | # |
9 | # Redistribution and use in source and binary forms, with or without | | 9 | # Redistribution and use in source and binary forms, with or without |
10 | # modification, are permitted provided that the following conditions | | 10 | # modification, are permitted provided that the following conditions |
11 | # are met: | | 11 | # are met: |
12 | # 1. Redistributions of source code must retain the above copyright | | 12 | # 1. Redistributions of source code must retain the above copyright |
13 | # notice, this list of conditions and the following disclaimer. | | 13 | # notice, this list of conditions and the following disclaimer. |
14 | # 2. Redistributions in binary form must reproduce the above copyright | | 14 | # 2. Redistributions in binary form must reproduce the above copyright |
15 | # notice, this list of conditions and the following disclaimer in the | | 15 | # notice, this list of conditions and the following disclaimer in the |
16 | # documentation and/or other materials provided with the distribution. | | 16 | # documentation and/or other materials provided with the distribution. |
17 | # | | 17 | # |
18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR, THOMAS KLAUSNER, | | 18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR, THOMAS KLAUSNER, |
19 | # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 19 | # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| @@ -32,77 +32,132 @@ use strict; | | | @@ -32,77 +32,132 @@ use strict; |
32 | use warnings; | | 32 | use warnings; |
33 | | | 33 | |
34 | $| = 1; | | 34 | $| = 1; |
35 | | | 35 | |
36 | package Parser; | | 36 | package Parser; |
37 | use Getopt::Std; | | 37 | use Getopt::Std; |
38 | | | 38 | |
39 | use constant { | | 39 | use constant { |
40 | OPENBSD => 0, | | 40 | OPENBSD => 0, |
41 | NETBSD => 1 | | 41 | NETBSD => 1 |
42 | }; | | 42 | }; |
43 | | | 43 | |
44 | use vars qw( | | 44 | use vars qw( |
45 | $opt_A $opt_a $opt_D $opt_d $opt_e $opt_F $opt_f $opt_H $opt_h $opt_m | | 45 | $opt_A $opt_a $opt_D $opt_d $opt_e $opt_F $opt_f $opt_H $opt_h $opt_l |
| | | 46 | $opt_m |
46 | $opt_n $opt_O $opt_o $opt_P $opt_p $opt_r $opt_S $opt_s $opt_v $opt_w | | 47 | $opt_n $opt_O $opt_o $opt_P $opt_p $opt_r $opt_S $opt_s $opt_v $opt_w |
47 | $opt_X $opt_x | | 48 | $opt_X $opt_x |
48 | ); | | 49 | ); |
49 | | | 50 | |
50 | | | 51 | |
51 | my $arch=`uname -m`; | | 52 | my $arch=`uname -m`; |
52 | chomp($arch); | | 53 | chomp($arch); |
53 | my $options="AaDdeFfHhmnOoPprSsvwXx"; | | 54 | my $options="AaDdeFfHhlmnOoPprSsvwXx"; |
54 | | | 55 | |
55 | sub usage | | 56 | sub usage |
56 | { | | 57 | { |
57 | my $default = OPENBSD ? "-aDdfmnoPprSsXx" : "-aDdefmnoPprSsXx"; | | 58 | my $default = OPENBSD ? "-aDdfmnoPprSsXx" : "-aDdefmnoPprSsXx"; |
58 | | | 59 | |
59 | print STDERR <<"EOF"; | | 60 | print STDERR <<"EOF"; |
60 | mdoclint: verify man page correctness | | 61 | mdoclint: verify man page correctness |
61 | usage: mdoclint [-$options] file ... | | 62 | usage: mdoclint [-$options] file ... |
62 | -A warn about missing .An in AUTHORS section | | 63 | -A warn about missing .An in AUTHORS section |
63 | -a warn about SEE ALSO section problems | | 64 | -a warn about SEE ALSO section problems |
64 | -D warn about bad casing and archs in .Dt | | 65 | -D warn about bad casing and archs in .Dt |
65 | -d warn about bad date strings (in .Dd only) | | 66 | -d warn about bad date strings (in .Dd only) |
66 | -e warn about unsorted errors (for functions) | | 67 | -e warn about unsorted errors (for functions) |
67 | -F fix whitespace problems (asks before overwriting) | | 68 | -F fix whitespace problems (asks before overwriting) |
68 | -f warn about possible incorrect .Fn syntax | | 69 | -f warn about possible incorrect .Fn syntax |
69 | -H warn about characters that produce problems in HTML output | | 70 | -H warn about characters that produce problems in HTML output |
70 | -h display this help text | | 71 | -h display this help text |
| | | 72 | -l warn about unknown libraries |
71 | -m warn about man pages that are not in mdoc(7) format | | 73 | -m warn about man pages that are not in mdoc(7) format |
72 | -n warn about .Nd's ending in '.' | | 74 | -n warn about .Nd's ending in '.' |
73 | -O warn about unsorted .It arguments | | 75 | -O warn about unsorted .It arguments |
74 | -o warn about non-empty .Os strings | | 76 | -o warn about non-empty .Os strings |
75 | -P warn about paragraph problems | | 77 | -P warn about paragraph problems |
76 | -p warn about punctuation problems | | 78 | -p warn about punctuation problems |
77 | -r warn about missing RCS Id | | 79 | -r warn about missing RCS Id |
78 | -S warn about any .Sh weirdness | | 80 | -S warn about any .Sh weirdness |
79 | -s warn about whitespace problems | | 81 | -s warn about whitespace problems |
80 | -v verbose output | | 82 | -v verbose output |
81 | -w show section header in warnings | | 83 | -w show section header in warnings |
82 | -X warn about explicit mentions of FreeBSD, NetBSD, or OpenBSD | | 84 | -X warn about explicit mentions of FreeBSD, NetBSD, or OpenBSD |
83 | -x warn about cross-references with missing targets | | 85 | -x warn about cross-references with missing targets |
84 | Default is $default if no flag is specified. | | 86 | Default is $default if no flag is specified. |
85 | EOF | | 87 | EOF |
86 | exit(0); | | 88 | exit(0); |
87 | } | | 89 | } |
88 | | | 90 | |
89 | | | 91 | |
90 | my %short = ( | | 92 | my %short = ( |
91 | "Free" => ".Fx", | | 93 | "Free" => ".Fx", |
92 | "Net" => ".Nx", | | 94 | "Net" => ".Nx", |
93 | "Open" => ".Ox" | | 95 | "Open" => ".Ox" |
94 | ); | | 96 | ); |
95 | | | 97 | |
| | | 98 | my %libraries = ( |
| | | 99 | "libarchive" => 1, |
| | | 100 | "libarm" => 1, |
| | | 101 | "libarm32" => 1, |
| | | 102 | "libbluetooth" => 1, |
| | | 103 | "libc" => 1, |
| | | 104 | "libcdk" => 1, |
| | | 105 | "libcompat" => 1, |
| | | 106 | "libcrypt" => 1, |
| | | 107 | "libcurses" => 1, |
| | | 108 | "libdm" => 1, |
| | | 109 | "libedit" => 1, |
| | | 110 | "libelf" => 1, |
| | | 111 | "libevent" => 1, |
| | | 112 | "libexecinfo" => 1, |
| | | 113 | "libfetch" => 1, |
| | | 114 | "libform" => 1, |
| | | 115 | "libi386" => 1, |
| | | 116 | "libintl" => 1, |
| | | 117 | "libipsec" => 1, |
| | | 118 | "libiscsi" => 1, |
| | | 119 | "libisns" => 1, |
| | | 120 | "libkvm" => 1, |
| | | 121 | "libm" => 1, |
| | | 122 | "libm68k" => 1, |
| | | 123 | "libmagic" => 1, |
| | | 124 | "libmenu" => 1, |
| | | 125 | "libnetpgp" => 1, |
| | | 126 | "libossaudio" => 1, |
| | | 127 | "libpam" => 1, |
| | | 128 | "libpcap" => 1, |
| | | 129 | "libpci" => 1, |
| | | 130 | "libperfuse" => 1, |
| | | 131 | "libpmc" => 1, |
| | | 132 | "libposix" => 1, |
| | | 133 | "libppath" => 1, |
| | | 134 | "libprop" => 1, |
| | | 135 | "libpthread" => 1, |
| | | 136 | "libpuffs" => 1, |
| | | 137 | "libquota" => 1, |
| | | 138 | "librefuse" => 1, |
| | | 139 | "libresolv" => 1, |
| | | 140 | "librt" => 1, |
| | | 141 | "libsaslc" => 1, |
| | | 142 | "libssp" => 1, |
| | | 143 | "libtermcap" => 1, |
| | | 144 | "libterminfo" => 1, |
| | | 145 | "libusbhid" => 1, |
| | | 146 | "libutil" => 1, |
| | | 147 | "libx86_64" => 1, |
| | | 148 | "libz" => 1 |
| | | 149 | ); |
| | | 150 | |
96 | # constants to build | | 151 | # constants to build |
97 | my %sections; | | 152 | my %sections; |
98 | my $arches_re; | | 153 | my $arches_re; |
99 | my $sections_re; | | 154 | my $sections_re; |
100 | my $esections_re; | | 155 | my $esections_re; |
101 | my $valid_date_re; | | 156 | my $valid_date_re; |
102 | # and the code that builds them | | 157 | # and the code that builds them |
103 | { | | 158 | { |
104 | my @sections = ( | | 159 | my @sections = ( |
105 | "NAME", | | 160 | "NAME", |
106 | NETBSD ? "LIBRARY" : undef, | | 161 | NETBSD ? "LIBRARY" : undef, |
107 | "SYNOPSIS", | | 162 | "SYNOPSIS", |
108 | "DESCRIPTION", | | 163 | "DESCRIPTION", |
| @@ -196,33 +251,34 @@ sub forder { | | | @@ -196,33 +251,34 @@ sub forder { |
196 | if($c){ return $c }; | | 251 | if($c){ return $c }; |
197 | } | | 252 | } |
198 | return (length($a) <=> length($b)); | | 253 | return (length($a) <=> length($b)); |
199 | } | | 254 | } |
200 | | | 255 | |
201 | | | 256 | |
202 | sub handle_options | | 257 | sub handle_options |
203 | { | | 258 | { |
204 | getopts($options); | | 259 | getopts($options); |
205 | $opt_h and usage(); | | 260 | $opt_h and usage(); |
206 | | | 261 | |
207 | # default to all warnings if no flag is set | | 262 | # default to all warnings if no flag is set |
208 | unless ($opt_A or $opt_a or $opt_D or $opt_d or $opt_e | | 263 | unless ($opt_A or $opt_a or $opt_D or $opt_d or $opt_e |
209 | or $opt_f or $opt_H or $opt_m or $opt_n or $opt_O | | 264 | or $opt_f or $opt_H or $opt_l |
| | | 265 | or $opt_m or $opt_n or $opt_O |
210 | or $opt_o or $opt_P or $opt_p or $opt_r | | 266 | or $opt_o or $opt_P or $opt_p or $opt_r |
211 | or $opt_S or $opt_s or $opt_X or $opt_x) { | | 267 | or $opt_S or $opt_s or $opt_X or $opt_x) { |
212 | $opt_A = $opt_a = $opt_D = $opt_d = $opt_f = $opt_m = | | 268 | $opt_A = $opt_a = $opt_D = $opt_d = $opt_f = $opt_m = |
213 | $opt_n = $opt_O = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = | | 269 | $opt_n = $opt_O = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = |
214 | $opt_s = $opt_X = $opt_x = 1; | | 270 | $opt_s = $opt_X = $opt_x = 1; |
215 | $opt_e = 1 if NETBSD; | | 271 | $opt_e = $opt_l = 1 if NETBSD; |
216 | } | | 272 | } |
217 | } | | 273 | } |
218 | | | 274 | |
219 | | | 275 | |
220 | sub verify_xref | | 276 | sub verify_xref |
221 | { | | 277 | { |
222 | my ($self, $page, $section, $pre, $post) = @_; | | 278 | my ($self, $page, $section, $pre, $post) = @_; |
223 | if ("$page.$section" eq $self->{fn}) { | | 279 | if ("$page.$section" eq $self->{fn}) { |
224 | $self->warning("Xref to itself (use .Nm instead)") if $opt_x; | | 280 | $self->warning("Xref to itself (use .Nm instead)") if $opt_x; |
225 | } | | 281 | } |
226 | # try to find corresponding man page | | 282 | # try to find corresponding man page |
227 | for my $dir ("/usr/share/man", | | 283 | for my $dir ("/usr/share/man", |
228 | OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { | | 284 | OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { |
| @@ -451,26 +507,31 @@ sub process_line | | | @@ -451,26 +507,31 @@ sub process_line |
451 | | | 507 | |
452 | if (/\b(Free|Net|Open)BSD\b/o | | 508 | if (/\b(Free|Net|Open)BSD\b/o |
453 | and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o | | 509 | and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o |
454 | and not /\bOpenBSD\::.*3p\b/o | | 510 | and not /\bOpenBSD\::.*3p\b/o |
455 | and not /\/pub\/OpenBSD\//o | | 511 | and not /\/pub\/OpenBSD\//o |
456 | and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { | | 512 | and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { |
457 | $s->warning("verbose mention of `$1BSD' instead of " | | 513 | $s->warning("verbose mention of `$1BSD' instead of " |
458 | . "`$short{$1}': `$_'") if $opt_X; | | 514 | . "`$short{$1}': `$_'") if $opt_X; |
459 | } | | 515 | } |
460 | if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { | | 516 | if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { |
461 | $s->warning("`.Bx $1' found -- use $short{$1} instead") | | 517 | $s->warning("`.Bx $1' found -- use $short{$1} instead") |
462 | if $opt_X; | | 518 | if $opt_X; |
463 | } | | 519 | } |
| | | 520 | if (/^\.Lb\s+(\S+)/o) { |
| | | 521 | if (not $libraries{$1}) { |
| | | 522 | $s->warning("Unknown library `$1' used as Lb argument") if $opt_l; |
| | | 523 | } |
| | | 524 | } |
464 | if (/^\.Os\s+(.+)/o) { | | 525 | if (/^\.Os\s+(.+)/o) { |
465 | $s->warning(".Os used with argument `$1'") if $opt_o; | | 526 | $s->warning(".Os used with argument `$1'") if $opt_o; |
466 | } | | 527 | } |
467 | | | 528 | |
468 | if (/^\.Nd.*\.$/o) { | | 529 | if (/^\.Nd.*\.$/o) { |
469 | $s->warning(".Nd ends with a dot: `$_'") if $opt_n; | | 530 | $s->warning(".Nd ends with a dot: `$_'") if $opt_n; |
470 | } | | 531 | } |
471 | | | 532 | |
472 | if (/\w\w\.\s+[A-Z]/o) { | | 533 | if (/\w\w\.\s+[A-Z]/o) { |
473 | $s->warning("new sentence, new line: `$_'") if $opt_p; | | 534 | $s->warning("new sentence, new line: `$_'") if $opt_p; |
474 | } | | 535 | } |
475 | if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o | | 536 | if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o |
476 | and not /\s\.\.\.$/o and not /\\&.$/o) { | | 537 | and not /\s\.\.\.$/o and not /\\&.$/o) { |