| @@ -1,713 +1,713 @@ | | | @@ -1,713 +1,713 @@ |
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.34 2013/07/30 18:37:56 wiz Exp $ | | 4 | # $NetBSD: mdoclint,v 1.35 2013/07/30 18:46:29 wiz Exp $ |
5 | # | | 5 | # |
6 | # Copyright (c) 2001-2013 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 |
20 | # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 20 | # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
21 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 21 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
22 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 22 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
23 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 23 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 24 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
25 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 25 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
26 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 26 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
27 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 27 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 | # POSSIBILITY OF SUCH DAMAGE. | | 28 | # POSSIBILITY OF SUCH DAMAGE. |
29 | # | | 29 | # |
30 | | | 30 | |
31 | use strict; | | 31 | 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 | SECTION_SEE_ALSO => 2, | | 42 | SECTION_SEE_ALSO => 2, |
43 | SECTION_AUTHORS => 3 | | 43 | SECTION_AUTHORS => 3 |
44 | }; | | 44 | }; |
45 | | | 45 | |
46 | use vars qw( | | 46 | use vars qw( |
47 | $opt_A $opt_a $opt_D $opt_d $opt_e $opt_F $opt_f $opt_H $opt_h $opt_l | | 47 | $opt_A $opt_a $opt_D $opt_d $opt_e $opt_F $opt_f $opt_H $opt_h $opt_l |
48 | $opt_m | | 48 | $opt_m |
49 | $opt_n $opt_O $opt_o $opt_P $opt_p $opt_r $opt_S $opt_s $opt_v $opt_w | | 49 | $opt_n $opt_O $opt_o $opt_P $opt_p $opt_r $opt_S $opt_s $opt_v $opt_w |
50 | $opt_X $opt_x | | 50 | $opt_X $opt_x |
51 | ); | | 51 | ); |
52 | | | 52 | |
53 | | | 53 | |
54 | my $arch=`uname -m`; | | 54 | my $arch=`uname -m`; |
55 | chomp($arch); | | 55 | chomp($arch); |
56 | my $options="AaDdeFfHhlmnOoPprSsvwXx"; | | 56 | my $options="AaDdeFfHhlmnOoPprSsvwXx"; |
57 | | | 57 | |
58 | sub usage | | 58 | sub usage |
59 | { | | 59 | { |
60 | my $default = OPENBSD ? "-AaDdfmnoPprSsXx" : "-AaDdeflmnoPprSsXx"; | | 60 | my $default = OPENBSD ? "-AaDdfmnoPprSsXx" : "-AaDdeflmnoPprSsXx"; |
61 | | | 61 | |
62 | print STDERR <<"EOF"; | | 62 | print STDERR <<"EOF"; |
63 | mdoclint: verify man page correctness | | 63 | mdoclint: verify man page correctness |
64 | usage: mdoclint [-$options] file ... | | 64 | usage: mdoclint [-$options] file ... |
65 | -A warn about missing .An in AUTHORS section | | 65 | -A warn about missing .An in AUTHORS section |
66 | -a warn about SEE ALSO section problems | | 66 | -a warn about SEE ALSO section problems |
67 | -D warn about bad casing and archs in .Dt | | 67 | -D warn about bad casing and archs in .Dt |
68 | -d warn about bad date strings (in .Dd only) | | 68 | -d warn about bad date strings (in .Dd only) |
69 | -e warn about unsorted errors (for functions) | | 69 | -e warn about unsorted errors (for functions) |
70 | -F fix whitespace problems (asks before overwriting) | | 70 | -F fix whitespace problems (asks before overwriting) |
71 | -f warn about possible incorrect .Fn syntax | | 71 | -f warn about possible incorrect .Fn syntax |
72 | -H warn about characters that produce problems in HTML output | | 72 | -H warn about characters that produce problems in HTML output |
73 | -h display this help text | | 73 | -h display this help text |
74 | -l warn about unknown libraries | | 74 | -l warn about unknown libraries |
75 | -m warn about man pages that are not in mdoc(7) format | | 75 | -m warn about man pages that are not in mdoc(7) format |
76 | -n warn about .Nd's ending in '.' | | 76 | -n warn about .Nd's ending in '.' |
77 | -O warn about unsorted .It arguments | | 77 | -O warn about unsorted .It arguments |
78 | -o warn about non-empty .Os strings | | 78 | -o warn about non-empty .Os strings |
79 | -P warn about paragraph problems | | 79 | -P warn about paragraph problems |
80 | -p warn about punctuation problems | | 80 | -p warn about punctuation problems |
81 | -r warn about missing RCS Id | | 81 | -r warn about missing RCS Id |
82 | -S warn about any .Sh weirdness | | 82 | -S warn about any .Sh weirdness |
83 | -s warn about whitespace problems | | 83 | -s warn about whitespace problems |
84 | -v verbose output | | 84 | -v verbose output |
85 | -w show section header in warnings | | 85 | -w show section header in warnings |
86 | -X warn about explicit mentions of FreeBSD, NetBSD, or OpenBSD | | 86 | -X warn about explicit mentions of FreeBSD, NetBSD, or OpenBSD |
87 | -x warn about cross-references with missing targets | | 87 | -x warn about cross-references with missing targets |
88 | Default is $default if no flag is specified. | | 88 | Default is $default if no flag is specified. |
89 | EOF | | 89 | EOF |
90 | exit(0); | | 90 | exit(0); |
91 | } | | 91 | } |
92 | | | 92 | |
93 | | | 93 | |
94 | my %short = ( | | 94 | my %short = ( |
95 | "Free" => ".Fx", | | 95 | "Free" => ".Fx", |
96 | "Net" => ".Nx", | | 96 | "Net" => ".Nx", |
97 | "Open" => ".Ox" | | 97 | "Open" => ".Ox" |
98 | ); | | 98 | ); |
99 | | | 99 | |
100 | my %libraries = ( | | 100 | my %libraries = ( |
101 | "libarchive" => 1, | | 101 | "libarchive" => 1, |
102 | "libarm" => 1, | | 102 | "libarm" => 1, |
103 | "libarm32" => 1, | | 103 | "libarm32" => 1, |
104 | "libbluetooth" => 1, | | 104 | "libbluetooth" => 1, |
105 | "libc" => 1, | | 105 | "libc" => 1, |
106 | "libcdk" => 1, | | 106 | "libcdk" => 1, |
107 | "libcompat" => 1, | | 107 | "libcompat" => 1, |
108 | "libcrypt" => 1, | | 108 | "libcrypt" => 1, |
109 | "libcurses" => 1, | | 109 | "libcurses" => 1, |
110 | "libdm" => 1, | | 110 | "libdm" => 1, |
111 | "libedit" => 1, | | 111 | "libedit" => 1, |
112 | "libelf" => 1, | | 112 | "libelf" => 1, |
113 | "libevent" => 1, | | 113 | "libevent" => 1, |
114 | "libexecinfo" => 1, | | 114 | "libexecinfo" => 1, |
115 | "libfetch" => 1, | | 115 | "libfetch" => 1, |
116 | "libform" => 1, | | 116 | "libform" => 1, |
117 | "libi386" => 1, | | 117 | "libi386" => 1, |
118 | "libintl" => 1, | | 118 | "libintl" => 1, |
119 | "libipsec" => 1, | | 119 | "libipsec" => 1, |
120 | "libiscsi" => 1, | | 120 | "libiscsi" => 1, |
121 | "libisns" => 1, | | 121 | "libisns" => 1, |
122 | "libkvm" => 1, | | 122 | "libkvm" => 1, |
123 | "libm" => 1, | | 123 | "libm" => 1, |
124 | "libm68k" => 1, | | 124 | "libm68k" => 1, |
125 | "libmagic" => 1, | | 125 | "libmagic" => 1, |
126 | "libmandoc" => 1, | | 126 | "libmandoc" => 1, |
127 | "libmenu" => 1, | | 127 | "libmenu" => 1, |
128 | "libmj" => 1, | | 128 | "libmj" => 1, |
129 | "libnetpgp" => 1, | | 129 | "libnetpgp" => 1, |
130 | "libnetpgpverify" => 1, | | 130 | "libnetpgpverify" => 1, |
131 | "libnpf" => 1, | | 131 | "libnpf" => 1, |
132 | "libossaudio" => 1, | | 132 | "libossaudio" => 1, |
133 | "libpam" => 1, | | 133 | "libpam" => 1, |
134 | "libpcap" => 1, | | 134 | "libpcap" => 1, |
135 | "libpci" => 1, | | 135 | "libpci" => 1, |
136 | "libperfuse" => 1, | | 136 | "libperfuse" => 1, |
137 | "libpmc" => 1, | | 137 | "libpmc" => 1, |
138 | "libposix" => 1, | | 138 | "libposix" => 1, |
139 | "libppath" => 1, | | 139 | "libppath" => 1, |
140 | "libprop" => 1, | | 140 | "libprop" => 1, |
141 | "libpthread" => 1, | | 141 | "libpthread" => 1, |
142 | "libpuffs" => 1, | | 142 | "libpuffs" => 1, |
143 | "libquota" => 1, | | 143 | "libquota" => 1, |
144 | "librefuse" => 1, | | 144 | "librefuse" => 1, |
145 | "libresolv" => 1, | | 145 | "libresolv" => 1, |
146 | "librt" => 1, | | 146 | "librt" => 1, |
147 | "librumpclient" => 1, | | 147 | "librumpclient" => 1, |
148 | "libsaslc" => 1, | | 148 | "libsaslc" => 1, |
149 | "libssp" => 1, | | 149 | "libssp" => 1, |
150 | "libtermcap" => 1, | | 150 | "libtermcap" => 1, |
151 | "libterminfo" => 1, | | 151 | "libterminfo" => 1, |
152 | "libusbhid" => 1, | | 152 | "libusbhid" => 1, |
153 | "libutil" => 1, | | 153 | "libutil" => 1, |
154 | "libx86_64" => 1, | | 154 | "libx86_64" => 1, |
155 | "libz" => 1 | | 155 | "libz" => 1 |
156 | ); | | 156 | ); |
157 | | | 157 | |
158 | # constants to build | | 158 | # constants to build |
159 | my %sections; | | 159 | my %sections; |
160 | my $arches_re; | | 160 | my $arches_re; |
161 | my $sections_re; | | 161 | my $sections_re; |
162 | my $esections_re; | | 162 | my $esections_re; |
163 | my $valid_date_re; | | 163 | my $valid_date_re; |
164 | # and the code that builds them | | 164 | # and the code that builds them |
165 | { | | 165 | { |
166 | my @sections = ( | | 166 | my @sections = ( |
167 | "NAME", | | 167 | "NAME", |
168 | NETBSD ? "LIBRARY" : undef, | | 168 | NETBSD ? "LIBRARY" : undef, |
169 | "SYNOPSIS", | | 169 | "SYNOPSIS", |
170 | "DESCRIPTION", | | 170 | "DESCRIPTION", |
171 | NETBSD ? "IMPLEMENTATION NOTES" : undef, | | 171 | NETBSD ? "IMPLEMENTATION NOTES" : undef, |
172 | "RETURN VALUES", | | 172 | "RETURN VALUES", |
173 | "ENVIRONMENT", | | 173 | "ENVIRONMENT", |
174 | "FILES", | | 174 | "FILES", |
175 | "EXIT STATUS", | | 175 | "EXIT STATUS", |
176 | "EXAMPLES", | | 176 | "EXAMPLES", |
177 | "DIAGNOSTICS", | | 177 | "DIAGNOSTICS", |
178 | NETBSD ? "COMPATIBILITY" : undef, | | 178 | NETBSD ? "COMPATIBILITY" : undef, |
179 | "ERRORS", | | 179 | "ERRORS", |
180 | "SEE ALSO", | | 180 | "SEE ALSO", |
181 | "STANDARDS", | | 181 | "STANDARDS", |
182 | "HISTORY", | | 182 | "HISTORY", |
183 | "AUTHORS", | | 183 | "AUTHORS", |
184 | "CAVEATS", | | 184 | "CAVEATS", |
185 | "BUGS", | | 185 | "BUGS", |
186 | NETBSD ? "SECURITY CONSIDERATIONS" : undef | | 186 | NETBSD ? "SECURITY CONSIDERATIONS" : undef |
187 | ); | | 187 | ); |
188 | | | 188 | |
189 | my $i = 1; | | 189 | my $i = 1; |
190 | for my $sh (@sections) { | | 190 | for my $sh (@sections) { |
191 | if (defined $sh) { | | 191 | if (defined $sh) { |
192 | $sections{$sh} = $i++; | | 192 | $sections{$sh} = $i++; |
193 | } | | 193 | } |
194 | } | | 194 | } |
195 | my @arches; | | 195 | my @arches; |
196 | if (OPENBSD) { | | 196 | if (OPENBSD) { |
197 | @arches = | | 197 | @arches = |
198 | (qw(alpha amd64 arm armish aviion beagle cats hp300 hppa | | 198 | (qw(alpha amd64 arm armish aviion beagle cats hp300 hppa |
199 | hppa64 i386 landisk loongson luna88k macppc mips64 | | 199 | hppa64 i386 landisk loongson luna88k macppc mips64 |
200 | mvme68k mvme88k octeon sgi socppc sparc sparc64 vax | | 200 | mvme68k mvme88k octeon sgi socppc sparc sparc64 vax |
201 | zaurus)); | | 201 | zaurus)); |
202 | } | | 202 | } |
203 | if (NETBSD) { | | 203 | if (NETBSD) { |
204 | @arches = | | 204 | @arches = |
205 | (qw(acorn26 acorn32 algor alpha amiga arc atari | | 205 | (qw(acorn26 acorn32 algor alpha amiga arc atari |
206 | bebox cats cesfic cobalt dreamcast evbarm evbmips evbppc | | 206 | bebox cats cesfic cobalt dreamcast evbarm evbmips evbppc |
207 | evbsh3 evbsh5 hp300 hp700 hpcarm hpcmips hpcsh | | 207 | evbsh3 evbsh5 hp300 hp700 hpcarm hpcmips hpcsh |
208 | i386 ibmnws luna68k mac68k macppc mipsco mmeye | | 208 | i386 ibmnws luna68k mac68k macppc mipsco mmeye |
209 | mvme68k mvmeppc netwinder news68k newsmips next68k | | 209 | mvme68k mvmeppc netwinder news68k newsmips next68k |
210 | pc532 playstation2 pmax pmppc prep sandpoint sbmips | | 210 | pc532 playstation2 pmax pmppc prep sandpoint sbmips |
211 | sgimips shark sparc sparc64 sun2 sun3 vax walnut | | 211 | sgimips shark sparc sparc64 sun2 sun3 vax walnut |
212 | x68k x86 x86_64 xen)); | | 212 | x68k x86 x86_64 xen)); |
213 | } | | 213 | } |
214 | my $a = join('|', @arches); | | 214 | my $a = join('|', @arches); |
215 | $arches_re = qr{(?:$a)}o; | | 215 | $arches_re = qr{(?:$a)}o; |
216 | if (OPENBSD) { | | 216 | if (OPENBSD) { |
217 | $sections_re = qr{(?:3p|[1-9])}o; | | 217 | $sections_re = qr{(?:3p|[1-9])}o; |
218 | $esections_re = qr{(?:3p|[0-9])}o; | | 218 | $esections_re = qr{(?:3p|[0-9])}o; |
219 | } | | 219 | } |
220 | if (NETBSD) { | | 220 | if (NETBSD) { |
221 | $sections_re = qr{[1-9]}o; | | 221 | $sections_re = qr{[1-9]}o; |
222 | $esections_re = qr{[0-9]}o; | | 222 | $esections_re = qr{[0-9]}o; |
223 | } | | 223 | } |
224 | if (OPENBSD) { | | 224 | if (OPENBSD) { |
225 | $valid_date_re = qr{\$Mdocdate\b}; | | 225 | $valid_date_re = qr{\$Mdocdate\b}; |
226 | } | | 226 | } |
227 | if (NETBSD) { | | 227 | if (NETBSD) { |
228 | $valid_date_re = qr{(?:January|February|March|April|May|June|July|August|September|October|November|December)\s*[1-9][0-9]*,\s*(?:198[0-9]|199[0-9]|200[0-9]|201[0-3])$}o; | | 228 | $valid_date_re = qr{(?:January|February|March|April|May|June|July|August|September|October|November|December)\s*[1-9][0-9]*,\s*(?:198[0-9]|199[0-9]|200[0-9]|201[0-3])$}o; |
229 | } | | 229 | } |
230 | } | | 230 | } |
231 | | | 231 | |
232 | sub debug | | 232 | sub debug |
233 | { | | 233 | { |
234 | my $self = shift; | | 234 | my $self = shift; |
235 | print STDOUT "debug: $self->{fn}:$self->{ln}: @_\n" if $opt_v; | | 235 | print STDOUT "debug: $self->{fn}:$self->{ln}: @_\n" if $opt_v; |
236 | } | | 236 | } |
237 | | | 237 | |
238 | sub warning | | 238 | sub warning |
239 | { | | 239 | { |
240 | my $self = shift; | | 240 | my $self = shift; |
241 | my $extra = ""; | | 241 | my $extra = ""; |
242 | if ($opt_w) { | | 242 | if ($opt_w) { |
243 | $extra = $self->{current_section_header}.":"; | | 243 | $extra = $self->{current_section_header}.":"; |
244 | } | | 244 | } |
245 | print STDOUT "$self->{fn}:$extra$self->{ln}: ", join('', @_), "\n"; | | 245 | print STDOUT "$self->{fn}:$extra$self->{ln}: ", join('', @_), "\n"; |
246 | } | | 246 | } |
247 | | | 247 | |
248 | my $order = " !\"#\$\%&'()*+,-./:;<=>?[\\]^_{|}~". | | 248 | my $order = " !\"#\$\%&'()*+,-./:;<=>?[\\]^_{|}~". |
249 | "0123456789". | | 249 | "0123456789". |
250 | "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; | | 250 | "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; |
251 | | | 251 | |
252 | sub forder { | | 252 | sub forder { |
253 | my ($a, $b, $c, $len, $i); | | 253 | my ($a, $b, $c, $len, $i); |
254 | $a = $_[0]; | | 254 | $a = $_[0]; |
255 | $b = $_[1]; | | 255 | $b = $_[1]; |
256 | $len = (length($a) < length($b))? length($a) : length($b); | | 256 | $len = (length($a) < length($b))? length($a) : length($b); |
257 | for($i = 0; $i<=$len; $i++) { | | 257 | for($i = 0; $i<=$len; $i++) { |
258 | $c = (index($order,substr($a,$i,1)) <=> index($order,substr($b,$i,1))); | | 258 | $c = (index($order,substr($a,$i,1)) <=> index($order,substr($b,$i,1))); |
259 | if($c){ return $c }; | | 259 | if($c){ return $c }; |
260 | } | | 260 | } |
261 | return (length($a) <=> length($b)); | | 261 | return (length($a) <=> length($b)); |
262 | } | | 262 | } |
263 | | | 263 | |
264 | | | 264 | |
265 | sub handle_options | | 265 | sub handle_options |
266 | { | | 266 | { |
267 | getopts($options); | | 267 | getopts($options); |
268 | $opt_h and usage(); | | 268 | $opt_h and usage(); |
269 | | | 269 | |
270 | # default to all warnings if no flag is set | | 270 | # default to all warnings if no flag is set |
271 | unless ($opt_A or $opt_a or $opt_D or $opt_d or $opt_e | | 271 | unless ($opt_A or $opt_a or $opt_D or $opt_d or $opt_e |
272 | or $opt_f or $opt_H or $opt_l | | 272 | or $opt_f or $opt_H or $opt_l |
273 | or $opt_m or $opt_n or $opt_O | | 273 | or $opt_m or $opt_n or $opt_O |
274 | or $opt_o or $opt_P or $opt_p or $opt_r | | 274 | or $opt_o or $opt_P or $opt_p or $opt_r |
275 | or $opt_S or $opt_s or $opt_X or $opt_x) { | | 275 | or $opt_S or $opt_s or $opt_X or $opt_x) { |
276 | $opt_A = $opt_a = $opt_D = $opt_d = $opt_f = $opt_m = | | 276 | $opt_A = $opt_a = $opt_D = $opt_d = $opt_f = $opt_m = |
277 | $opt_n = $opt_O = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = | | 277 | $opt_n = $opt_O = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = |
278 | $opt_s = $opt_X = $opt_x = 1; | | 278 | $opt_s = $opt_X = $opt_x = 1; |
279 | $opt_e = $opt_l = 1 if NETBSD; | | 279 | $opt_e = $opt_l = 1 if NETBSD; |
280 | } | | 280 | } |
281 | } | | 281 | } |
282 | | | 282 | |
283 | | | 283 | |
284 | sub verify_xref | | 284 | sub verify_xref |
285 | { | | 285 | { |
286 | my ($self, $page, $section, $pre, $post) = @_; | | 286 | my ($self, $page, $section, $pre, $post) = @_; |
287 | if ("$page.$section" eq $self->{fn}) { | | 287 | if ("$page.$section" eq $self->{fn}) { |
288 | $self->warning("Xref to itself (use .Nm instead)") if $opt_x; | | 288 | $self->warning("Xref to itself (use .Nm instead)") if $opt_x; |
289 | } | | 289 | } |
290 | # try to find corresponding man page | | 290 | # try to find corresponding man page |
291 | for my $dir ("/usr/share/man", | | 291 | for my $dir ("/usr/share/man", |
292 | OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { | | 292 | OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { |
293 | for my $a ("", $arch) { | | 293 | for my $a ("", $arch) { |
294 | for my $page ("man$section/$a/$page.$section") { | | 294 | for my $page ("man$section/$a/$page.$section") { |
295 | return 1 if -f "$dir/$page"; | | 295 | return 1 if -f "$dir/$page"; |
296 | } | | 296 | } |
297 | } | | 297 | } |
298 | } | | 298 | } |
299 | return 1 if -f "./$page.$section"; | | 299 | return 1 if -f "./$page.$section"; |
300 | | | 300 | |
301 | $self->warning($pre."trailing Xref to $page($section)$post") if $opt_x; | | 301 | $self->warning($pre."trailing Xref to $page($section)$post") if $opt_x; |
302 | return 0; | | 302 | return 0; |
303 | } | | 303 | } |
304 | | | 304 | |
305 | sub new | | 305 | sub new |
306 | { | | 306 | { |
307 | my ($class, $fn) = @_; | | 307 | my ($class, $fn) = @_; |
308 | | | 308 | |
309 | my $o = { | | 309 | my $o = { |
310 | mandoc_p => 1, | | 310 | mandoc_p => 1, |
311 | all => [], | | 311 | all => [], |
312 | lastline => '', | | 312 | lastline => '', |
313 | changes => 0, | | 313 | changes => 0, |
314 | oxrcsidseen => 0, | | 314 | oxrcsidseen => 0, |
315 | nxrcsidseen => 0, | | 315 | nxrcsidseen => 0, |
316 | lastsh => 0, | | 316 | lastsh => 0, |
317 | sasection => 0, | | 317 | sasection => 0, |
318 | saname => '', | | 318 | saname => '', |
319 | sarest => ',', | | 319 | sarest => ',', |
320 | inauthors => 0, | | 320 | inauthors => 0, |
321 | in_section => 0, | | 321 | in_section => 0, |
322 | inliteral => 0, | | 322 | inliteral => 0, |
323 | shseen => {}, | | 323 | shseen => {}, |
324 | last_error_name => '', | | 324 | last_error_name => '', |
325 | current_section_header => '', | | 325 | current_section_header => '', |
326 | fn => $fn | | 326 | fn => $fn |
327 | }; | | 327 | }; |
328 | open my $input, '<', $fn or die "can't open input file $fn"; | | 328 | open my $input, '<', $fn or die "can't open input file $fn"; |
329 | $o->{file} = $input; | | 329 | $o->{file} = $input; |
330 | $o->{ln} = 0; | | 330 | $o->{ln} = 0; |
331 | bless $o, $class; | | 331 | bless $o, $class; |
332 | } | | 332 | } |
333 | | | 333 | |
334 | sub next_line | | 334 | sub next_line |
335 | { | | 335 | { |
336 | my ($self) = @_; | | 336 | my ($self) = @_; |
337 | | | 337 | |
338 | my $l = readline($self->{file}); | | 338 | my $l = readline($self->{file}); |
339 | if (defined $l) { | | 339 | if (defined $l) { |
340 | $self->{ln}++; | | 340 | $self->{ln}++; |
341 | } | | 341 | } |
342 | return $l; | | 342 | return $l; |
343 | } | | 343 | } |
344 | | | 344 | |
345 | sub close | | 345 | sub close |
346 | { | | 346 | { |
347 | my ($self) = @_; | | 347 | my ($self) = @_; |
348 | | | 348 | |
349 | close($self->{file}); | | 349 | close($self->{file}); |
350 | } | | 350 | } |
351 | | | 351 | |
352 | sub parse_macro_args | | 352 | sub parse_macro_args |
353 | { | | 353 | { |
354 | my ($s, $string) = @_; | | 354 | my ($s, $string) = @_; |
355 | $_ = $string; | | 355 | $_ = $string; |
356 | my @params = (); | | 356 | my @params = (); |
357 | while (!/^$/) { | | 357 | while (!/^$/) { |
358 | if (s/^\"(.*?)\"\s*//) { | | 358 | if (s/^\"(.*?)\"\s*//) { |
359 | push(@params, $1); | | 359 | push(@params, $1); |
360 | } elsif (s/^(\S+)\s*//) { | | 360 | } elsif (s/^(\S+)\s*//) { |
361 | push(@params, $1); | | 361 | push(@params, $1); |
362 | } | | 362 | } |
363 | } | | 363 | } |
364 | if (@params > 9 and OPENBSD) { | | 364 | if (@params > 9 and OPENBSD) { |
365 | $s->warning("$string holds >9 parameters"); | | 365 | $s->warning("$string holds >9 parameters"); |
366 | } | | 366 | } |
367 | return @params; | | 367 | return @params; |
368 | } | | 368 | } |
369 | | | 369 | |
370 | sub end_of_section | | 370 | sub end_of_section |
371 | { | | 371 | { |
372 | my ($s) = @_; | | 372 | my ($s) = @_; |
373 | | | 373 | |
374 | if ($s->{in_section} == SECTION_SEE_ALSO and not $s->{sarest} eq "") { | | 374 | if ($s->{in_section} == SECTION_SEE_ALSO and not $s->{sarest} eq "") { |
375 | $s->warning("unneeded characters at end of SEE ALSO: ", | | 375 | $s->warning("unneeded characters at end of SEE ALSO: ", |
376 | "`$s->{sarest}'") if $opt_a; | | 376 | "`$s->{sarest}'") if $opt_a; |
377 | # to avoid a second warning at EOF | | 377 | # to avoid a second warning at EOF |
378 | $s->{sarest} = ""; | | 378 | $s->{sarest} = ""; |
379 | } | | 379 | } |
380 | | | 380 | |
381 | if ($s->{in_section} == SECTION_AUTHORS) { | | 381 | if ($s->{in_section} == SECTION_AUTHORS) { |
382 | if (!$s->{an_found}) { | | 382 | if (!$s->{an_found}) { |
383 | $s->warning("missing .An in AUTHORS section") if $opt_A; | | 383 | $s->warning("missing .An in AUTHORS section") if $opt_A; |
384 | } | | 384 | } |
385 | } | | 385 | } |
386 | } | | 386 | } |
387 | | | 387 | |
388 | sub set_section_header | | 388 | sub set_section_header |
389 | { | | 389 | { |
390 | my ($s, $section_header) = @_; | | 390 | my ($s, $section_header) = @_; |
391 | $section_header = join(' ', $s->parse_macro_args($section_header)); | | 391 | $section_header = join(' ', $s->parse_macro_args($section_header)); |
392 | | | 392 | |
393 | end_of_section($s); | | 393 | end_of_section($s); |
394 | | | 394 | |
395 | if ($section_header eq 'SEE ALSO') { | | 395 | if ($section_header eq 'SEE ALSO') { |
396 | $s->{in_section} = SECTION_SEE_ALSO; | | 396 | $s->{in_section} = SECTION_SEE_ALSO; |
397 | } elsif ($section_header eq 'AUTHORS') { | | 397 | } elsif ($section_header eq 'AUTHORS') { |
398 | $s->{in_section} = SECTION_AUTHORS; | | 398 | $s->{in_section} = SECTION_AUTHORS; |
399 | } else { | | 399 | } else { |
400 | $s->{in_section} = 0; | | 400 | $s->{in_section} = 0; |
401 | } | | 401 | } |
402 | | | 402 | |
403 | if (not $sections{$section_header}) { | | 403 | if (not $sections{$section_header}) { |
404 | $s->warning("unknown section header: ", | | 404 | $s->warning("unknown section header: ", |
405 | "`$section_header'") if $opt_S; | | 405 | "`$section_header'") if $opt_S; |
406 | } else { | | 406 | } else { |
407 | if ($s->{lastsh} >= $sections{$section_header}) { | | 407 | if ($s->{lastsh} >= $sections{$section_header}) { |
408 | $s->warning("section header ", | | 408 | $s->warning("section header ", |
409 | "`$section_header' in wrong order") if $opt_S; | | 409 | "`$section_header' in wrong order") if $opt_S; |
410 | } | | 410 | } |
411 | $s->{shseen}->{$section_header} = 1; | | 411 | $s->{shseen}->{$section_header} = 1; |
412 | $s->{lastsh} = $sections{$section_header}; | | 412 | $s->{lastsh} = $sections{$section_header}; |
413 | } | | 413 | } |
414 | | | 414 | |
415 | if ($s->{lastline} =~ /^\.Pp/o) { | | 415 | if ($s->{lastline} =~ /^\.Pp/o) { |
416 | $s->warning("Paragraph problem: section header after .Pp") | | 416 | $s->warning("Paragraph problem: section header after .Pp") |
417 | if $opt_P; | | 417 | if $opt_P; |
418 | } | | 418 | } |
419 | | | 419 | |
420 | $s->{current_section_header} = $section_header; | | 420 | $s->{current_section_header} = $section_header; |
421 | } | | 421 | } |
422 | | | 422 | |
423 | sub process_and_save_line | | 423 | sub process_and_save_line |
424 | { | | 424 | { |
425 | my $s; | | 425 | my $s; |
426 | ($s, $_) = @_; | | 426 | ($s, $_) = @_; |
427 | my $result = $s->process_line($_); | | 427 | my $result = $s->process_line($_); |
428 | # note that process_line chomps \n, then re-adds it, | | 428 | # note that process_line chomps \n, then re-adds it, |
429 | # so we detect a change on last lines without a \n. | | 429 | # so we detect a change on last lines without a \n. |
430 | if ($result ne $_) { | | 430 | if ($result ne $_) { |
431 | $s->{changes} = 1; | | 431 | $s->{changes} = 1; |
432 | } | | 432 | } |
433 | push(@{$s->{all}}, $result); | | 433 | push(@{$s->{all}}, $result); |
434 | } | | 434 | } |
435 | | | 435 | |
436 | sub process_line | | 436 | sub process_line |
437 | { | | 437 | { |
438 | my $s; | | 438 | my $s; |
439 | ($s, $_) = @_; | | 439 | ($s, $_) = @_; |
440 | chomp; | | 440 | chomp; |
441 | # always cut trailing spaces | | 441 | # always cut trailing spaces |
442 | if (/\s+$/o) { | | 442 | if (/\s+$/o) { |
443 | $s->warning("trailing space: `$_'") if $opt_s; | | 443 | $s->warning("trailing space: `$_'") if $opt_s; |
444 | s/\s+$//o; | | 444 | s/\s+$//o; |
445 | } | | 445 | } |
446 | if (/\$OpenBSD\b.*\$/o) { | | 446 | if (/\$OpenBSD\b.*\$/o) { |
447 | $s->{oxrcsidseen}++; | | 447 | $s->{oxrcsidseen}++; |
448 | if (OPENBSD and ($s->{oxrcsidseen} > 1)) { | | 448 | if (OPENBSD and ($s->{oxrcsidseen} > 1)) { |
449 | $s->warning("RCS Id seen twice") if $opt_r; | | 449 | $s->warning("RCS Id seen twice") if $opt_r; |
450 | } | | 450 | } |
451 | return "$_\n"; | | 451 | return "$_\n"; |
452 | } | | 452 | } |
453 | if (/[\$]NetBSD\b.*\$/o) { | | 453 | if (/[\$]NetBSD\b.*\$/o) { |
454 | $s->{nxrcsidseen}++; | | 454 | $s->{nxrcsidseen}++; |
455 | if (NETBSD and ($s->{nxrcsidseen} > 1)) { | | 455 | if (NETBSD and ($s->{nxrcsidseen} > 1)) { |
456 | $s->warning("RCS Id seen twice") if $opt_r; | | 456 | $s->warning("RCS Id seen twice") if $opt_r; |
457 | } | | 457 | } |
458 | return "$_\n"; | | 458 | return "$_\n"; |
459 | } | | 459 | } |
460 | # comments | | 460 | # comments |
461 | if (/^\.\\\"/) { | | 461 | if (/^\.\\\"/) { |
462 | return "$_\n"; | | 462 | return "$_\n"; |
463 | } | | 463 | } |
464 | if (/^\.TH\s+/o) { | | 464 | if (/^\.TH\s+/o) { |
465 | $s->warning("not mandoc") if $opt_m; | | 465 | $s->warning("not mandoc") if $opt_m; |
466 | $s->{mandoc_p} = 0; | | 466 | $s->{mandoc_p} = 0; |
467 | # /^.TH\s*[\w-_".]+\s*([1-9])/; | | 467 | # /^.TH\s*[\w-_".]+\s*([1-9])/; |
468 | # $section = $1; | | 468 | # $section = $1; |
469 | return "$_\n"; | | 469 | return "$_\n"; |
470 | } | | 470 | } |
471 | # if (/^.Dt\s*[\w-_".]+\s*([1-9])/) { | | 471 | # if (/^.Dt\s*[\w-_".]+\s*([1-9])/) { |
472 | # $section = $1; | | 472 | # $section = $1; |
473 | # } | | 473 | # } |
474 | if (/^\.Dt\s+/o) { | | 474 | if (/^\.Dt\s+/o) { |
475 | if (! /^\.Dt\s+(?:[A-Z\d._-]+)\s+$sections_re(?:\s+$arches_re)?$/o) { | | 475 | if (! /^\.Dt\s+(?:[A-Z\d._-]+)\s+$sections_re(?:\s+$arches_re)?$/o) { |
476 | $s->warning("bad .Dt: `$_'") if $opt_D; | | 476 | $s->warning("bad .Dt: `$_'") if $opt_D; |
477 | } | | 477 | } |
478 | } | | 478 | } |
479 | | | 479 | |
480 | if ($s->{mandoc_p}) { | | 480 | if ($s->{mandoc_p}) { |
481 | if (/^\.Sh\s+(.*)$/o) { | | 481 | if (/^\.Sh\s+(.*)$/o) { |
482 | $s->set_section_header($1); | | 482 | $s->set_section_header($1); |
483 | return "$_\n"; | | 483 | return "$_\n"; |
484 | } | | 484 | } |
485 | } else { | | 485 | } else { |
486 | if (/^\.SH\s+(.*)$/o) { | | 486 | if (/^\.SH\s+(.*)$/o) { |
487 | $s->set_section_header($1); | | 487 | $s->set_section_header($1); |
488 | return "$_\n"; | | 488 | return "$_\n"; |
489 | } | | 489 | } |
490 | } | | 490 | } |
491 | | | 491 | |
492 | if ($s->{in_section} == SECTION_SEE_ALSO) { | | 492 | if ($s->{in_section} == SECTION_SEE_ALSO) { |
493 | if (/^\.Xr\s+(\S+)\s+($sections_re)\s?(.*)?$/o) { | | 493 | if (/^\.Xr\s+(\S+)\s+($sections_re)\s?(.*)?$/o) { |
494 | my ($saname, $sasection, $sarest) = ($1, $2, $3); | | 494 | my ($saname, $sasection, $sarest) = ($1, $2, $3); |
495 | $saname =~ s/^\\&//o; | | 495 | $saname =~ s/^\\&//o; |
496 | if ($s->{sasection} gt $sasection | | 496 | if ($s->{sasection} gt $sasection |
497 | or ($s->{sasection} eq $sasection and | | 497 | or ($s->{sasection} eq $sasection and |
498 | (lc($s->{saname}) gt lc($saname)))) { | | 498 | (lc($s->{saname}) gt lc($saname)))) { |
499 | $s->warning("SEE ALSO: `.Xr $s->{saname} ", | | 499 | $s->warning("SEE ALSO: `.Xr $s->{saname} ", |
500 | "$s->{sasection}' should be after ", | | 500 | "$s->{sasection}' should be after ", |
501 | "`.Xr $saname $sasection'") if $opt_a; | | 501 | "`.Xr $saname $sasection'") if $opt_a; |
502 | } | | 502 | } |
503 | if ($s->{sarest} ne ",") { | | 503 | if ($s->{sarest} ne ",") { |
504 | $s->warning("SEE ALSO: .Xr not separated ", | | 504 | $s->warning("SEE ALSO: .Xr not separated ", |
505 | "by comma, but `$s->{sarest}'") if $opt_a; | | 505 | "by comma, but `$s->{sarest}'") if $opt_a; |
506 | } | | 506 | } |
507 | $s->{saname} = $saname; | | 507 | $s->{saname} = $saname; |
508 | $s->{sasection} = $sasection; | | 508 | $s->{sasection} = $sasection; |
509 | $s->{sarest} = $sarest; | | 509 | $s->{sarest} = $sarest; |
510 | } | | 510 | } |
511 | if (/^\.Rs(?:\s+|$)/o) { | | 511 | if (/^\.Rs(?:\s+|$)/o) { |
512 | if ($s->{sarest} ne "") { | | 512 | if ($s->{sarest} ne "") { |
513 | $s->warning("SEE ALSO: Not necessary to ", | | 513 | $s->warning("SEE ALSO: Not necessary to ", |
514 | "separate .Xr from .Rs by ", | | 514 | "separate .Xr from .Rs by ", |
515 | "`$s->{sarest}'") if $opt_a; | | 515 | "`$s->{sarest}'") if $opt_a; |
516 | } | | 516 | } |
517 | $s->{sarest} = ""; | | 517 | $s->{sarest} = ""; |
518 | } | | 518 | } |
519 | } | | 519 | } |
520 | if ($s->{in_section} == SECTION_AUTHORS) { | | 520 | if ($s->{in_section} == SECTION_AUTHORS) { |
521 | if (/^\.An / && not /^\.An -(no|)split/) { | | 521 | if (/^\.An / && not /^\.An -(no|)split/) { |
522 | $s->{an_found} = 1; | | 522 | $s->{an_found} = 1; |
523 | } | | 523 | } |
524 | } | | 524 | } |
525 | | | 525 | |
526 | if (/^\.Fn.*,.+/o) { | | 526 | if (/^\.Fn.*,.+/o) { |
527 | $s->warning("possible .Fn misuse: `$_'") if $opt_f; | | 527 | $s->warning("possible .Fn misuse: `$_'") if $opt_f; |
528 | } | | 528 | } |
529 | if (OPENBSD) { | | 529 | if (OPENBSD) { |
530 | if (/^(?:[<>])/o or /[^\\][<>]/o) { | | 530 | if (/^(?:[<>])/o or /[^\\][<>]/o) { |
531 | $s->warning("use \*(Lt \*(Gt (or .Aq) ", | | 531 | $s->warning("use \*(Lt \*(Gt (or .Aq) ", |
532 | "instead of < >: `$_'") if $opt_H; | | 532 | "instead of < >: `$_'") if $opt_H; |
533 | } | | 533 | } |
534 | } | | 534 | } |
535 | if (NETBSD) { | | 535 | if (NETBSD) { |
536 | if (/^(?:[<>&])/o or /[^\\][<>&]/o) { | | 536 | if (/^(?:[<>&])/o or /[^\\][<>&]/o) { |
537 | $s->warning("use \*[Lt] \*[Gt] (or .Aq) \*[Am] ", | | 537 | $s->warning("use \*[Lt] \*[Gt] (or .Aq) \*[Am] ", |
538 | "instead of < > &: `$_'") if $opt_H; | | 538 | "instead of < > &: `$_'") if $opt_H; |
539 | } | | 539 | } |
540 | } | | 540 | } |
541 | | | 541 | |
542 | if (/\b(Free|Net|Open)BSD\b/o | | 542 | if (/\b(Free|Net|Open)BSD\b/o |
543 | and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o | | 543 | and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o |
544 | and not /\bOpenBSD\::.*3p\b/o | | 544 | and not /\bOpenBSD\::.*3p\b/o |
545 | and not /\/pub\/OpenBSD\//o | | 545 | and not /\/pub\/OpenBSD\//o |
546 | and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { | | 546 | and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { |
547 | $s->warning("verbose mention of `$1BSD' instead of " | | 547 | $s->warning("verbose mention of `$1BSD' instead of " |
548 | . "`$short{$1}': `$_'") if $opt_X; | | 548 | . "`$short{$1}': `$_'") if $opt_X; |
549 | } | | 549 | } |
550 | if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { | | 550 | if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { |
551 | $s->warning("`.Bx $1' found -- use $short{$1} instead") | | 551 | $s->warning("`.Bx $1' found -- use $short{$1} instead") |
552 | if $opt_X; | | 552 | if $opt_X; |
553 | } | | 553 | } |
554 | if (/^\.Lb\s+(\S+)/o) { | | 554 | if (/^\.Lb\s+(\S+)/o) { |
555 | if (not $libraries{$1}) { | | 555 | if (not $libraries{$1}) { |
556 | $s->warning("Unknown library `$1' used as Lb argument") if $opt_l; | | 556 | $s->warning("Unknown library `$1' used as Lb argument") if $opt_l; |
557 | } | | 557 | } |
558 | } | | 558 | } |
559 | if (/^\.Os\s+(.+)/o) { | | 559 | if (/^\.Os\s+(.+)/o) { |
560 | $s->warning(".Os used with argument `$1'") if $opt_o; | | 560 | $s->warning(".Os used with argument `$1'") if $opt_o; |
561 | } | | 561 | } |
562 | | | 562 | |
563 | if (/^\.Nd.*\.$/o) { | | 563 | if (/^\.Nd.*\.$/o) { |
564 | $s->warning(".Nd ends with a dot: `$_'") if $opt_n; | | 564 | $s->warning(".Nd ends with a dot: `$_'") if $opt_n; |
565 | } | | 565 | } |
566 | | | 566 | |
567 | if (/(\w\w)\.\s+[A-Z]/o and not /^.%T/ and not $s->{inliteral}) { | | 567 | if (/(\w\w)\.\s+[A-Z]/o and not /^.%T/ and not $s->{inliteral}) { |
568 | if ("$1" ne "St") { | | 568 | if ("$1" ne "St") { |
569 | $s->warning("new sentence, new line: `$_'") if $opt_p; | | 569 | $s->warning("new sentence, new line: `$_'") if $opt_p; |
570 | } | | 570 | } |
571 | } | | 571 | } |
572 | if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o | | 572 | if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o |
573 | and not /\s\.\.\.$/o and not /\\&.$/o) { | | 573 | and not /\s\.\.\.$/o and not /\\&.$/o) { |
574 | $s->warning("punctuation in format string ", | | 574 | $s->warning("punctuation in format string ", |
575 | "without space: `$_'") if $opt_p; | | 575 | "without space: `$_'") if $opt_p; |
576 | } | | 576 | } |
577 | if (/^\./o and /Ns [\.();,\[\]\{\}:]/o) { | | 577 | if (/^\./o and /Ns [\.();,\[\]\{\}:]/o) { |
578 | $s->warning("possible Ns abuse: `$_'") if $opt_p; | | 578 | $s->warning("possible Ns abuse: `$_'") if $opt_p; |
579 | } | | 579 | } |
580 | if ((/^([^\.]\w+)\(\)/o or /^[^\.].*\s(\w+)\(\)/o) and not $s->{inliteral}) { | | 580 | if ((/^([^\.]\w+)\(\)/o or /^[^\.].*\s(\w+)\(\)/o) and not $s->{inliteral}) { |
581 | $s->warning("use .Fn or .Xr for functions: `$1()'") if $opt_p; | | 581 | $s->warning("use .Fn or .Xr for functions: `$1()'") if $opt_p; |
582 | } | | 582 | } |
583 | | | 583 | |
584 | my $destruct = $_; | | 584 | my $destruct = $_; |
585 | if ($s->{mandoc_p}) { | | 585 | if ($s->{mandoc_p}) { |
586 | $destruct =~ s/\\\&([\w\.])/$1/o; | | 586 | $destruct =~ s/\\\&([\w\.])/$1/o; |
587 | if ($destruct =~ /^\.Xr\s+([\w\:\.\-\+\/]+)\s+($esections_re)(.*)/o) { | | 587 | if ($destruct =~ /^\.Xr\s+([\w\:\.\-\+\/]+)\s+($esections_re)(.*)/o) { |
588 | $s->debug("Xref to $1($2) found: `$_'"); | | 588 | $s->debug("Xref to $1($2) found: `$_'"); |
589 | $s->verify_xref($1, $2, "", ""); | | 589 | $s->verify_xref($1, $2, "", ""); |
590 | if ($3 =~ /^\S/o) { | | 590 | if ($3 =~ /^\S/o) { |
591 | $s->warning("No space after section number in Xref: `$_'") if $opt_x; | | 591 | $s->warning("No space after section number in Xref: `$_'") if $opt_x; |
592 | } | | 592 | } |
593 | } elsif ($destruct =~ /^\.Xr/o) { | | 593 | } elsif ($destruct =~ /^\.Xr/o) { |
594 | $s->warning("Weird Xref found: `$_'") if $opt_x; | | 594 | $s->warning("Weird Xref found: `$_'") if $opt_x; |
595 | } | | 595 | } |
596 | } else { | | 596 | } else { |
597 | $destruct =~ s/\\f.//go; | | 597 | $destruct =~ s/\\f.//go; |
598 | if ($destruct !~ /^\.\\\"/o) { | | 598 | if ($destruct !~ /^\.\\\"/o) { |
599 | while ($destruct =~ s/([-\w.]+)\s*\(($esections_re)\)//o) { | | 599 | while ($destruct =~ s/([-\w.]+)\s*\(($esections_re)\)//o) { |
600 | $s->debug("possible Xref to $1($2) found: `$_'"); | | 600 | $s->debug("possible Xref to $1($2) found: `$_'"); |
601 | $s->verify_xref($1, $2, "possible ", ": `$_'"); | | 601 | $s->verify_xref($1, $2, "possible ", ": `$_'"); |
602 | # so that we have a chance to find more than one | | 602 | # so that we have a chance to find more than one |
603 | # per line | | 603 | # per line |
604 | $destruct =~ s/(\w+)\s*\(($sections_re)\)//o; | | 604 | $destruct =~ s/(\w+)\s*\(($sections_re)\)//o; |
605 | } | | 605 | } |
606 | } | | 606 | } |
607 | } | | 607 | } |
608 | | | 608 | |
609 | if (/^\.Dd/o and not /^\.Dd\s+$valid_date_re/o) { | | 609 | if (/^\.Dd/o and not /^\.Dd\s+$valid_date_re/o) { |
610 | $s->warning("Invalid date found: `$_'") if $opt_d; | | 610 | $s->warning("Invalid date found: `$_'") if $opt_d; |
611 | } | | 611 | } |
612 | | | 612 | |
613 | if (/^\.Bd\b.*-literal\b/o) { | | 613 | if (/^\.Bd\b.*-literal\b/o) { |
614 | $s->{inliteral} = 1; | | 614 | $s->{inliteral} = 1; |
615 | } | | 615 | } |
616 | if ($s->{inliteral} == 1) { | | 616 | if ($s->{inliteral} == 1) { |
617 | if (/^\.Ed\b/o) { | | 617 | if (/^\.Ed\b/o) { |
618 | $s->{inliteral} = 0; | | 618 | $s->{inliteral} = 0; |
619 | } | | 619 | } |
620 | } elsif (/^$/o) { | | 620 | } elsif (/^$/o) { |
621 | $s->warning("Paragraph problem: empty line -- ", | | 621 | $s->warning("Paragraph problem: empty line -- ", |
622 | "use .Pp for paragraphs") if $opt_P; | | 622 | "use .Pp for paragraphs") if $opt_P; |
623 | } | | 623 | } |
624 | if ($s->{lastline} =~ /^\.Pp/o and /^(\.Ss|\.Pp)/o) { | | 624 | if ($s->{lastline} =~ /^\.Pp/o and /^(\.Ss|\.Pp)/o) { |
625 | $s->warning("Paragraph problem: $1 after .Pp") if $opt_P; | | 625 | $s->warning("Paragraph problem: $1 after .Pp") if $opt_P; |
626 | } | | 626 | } |
627 | if (/^\.Pp/o and $s->{lastline} =~ /^(\.S[Ssh])/o) { | | 627 | if (/^\.Pp/o and $s->{lastline} =~ /^(\.S[Ssh])/o) { |
628 | $s->warning("Paragraph problem: .Pp after $1") if $opt_P; | | 628 | $s->warning("Paragraph problem: .Pp after $1") if $opt_P; |
629 | } | | 629 | } |
630 | | | 630 | |
631 | # Check whether the list of possible errors for a function is | | 631 | # Check whether the list of possible errors for a function is |
632 | # sorted alphabetically. | | 632 | # sorted alphabetically. |
633 | # | | 633 | # |
634 | # Error names should not be sorted across different lists. | | 634 | # Error names should not be sorted across different lists. |
635 | # (see bind(2) for an example.) | | 635 | # (see bind(2) for an example.) |
636 | # | | 636 | # |
637 | /^\.Bl\s+/o and $s->{last_error_name} = ""; | | 637 | /^\.Bl\s+/o and $s->{last_error_name} = ""; |
638 | | | 638 | |
639 | if ($s->{current_section_header} eq "ERRORS" and | | 639 | if ($s->{current_section_header} eq "ERRORS" and |
640 | /^\.It\s+Bq\s+Er\s+(E[\w_]+)$/o) { | | 640 | /^\.It\s+(Bq\s+)?(Er\s+)?(E[\w_]+)$/o) { |
641 | my $current_error_name = $1; | | 641 | my $current_error_name = $3; |
642 | | | 642 | |
643 | if ($s->{last_error_name} eq $current_error_name) { | | 643 | if ($s->{last_error_name} eq $current_error_name) { |
644 | $s->warning("Duplicate item for ", | | 644 | $s->warning("Duplicate item for ", |
645 | $current_error_name, ".") if $opt_e; | | 645 | $current_error_name, ".") if $opt_e; |
646 | } elsif ($current_error_name lt $s->{last_error_name}) { | | 646 | } elsif ($current_error_name lt $s->{last_error_name}) { |
647 | $s->warning("$s->{last_error_name} and ", | | 647 | $s->warning("$s->{last_error_name} and ", |
648 | "$current_error_name are not in ", | | 648 | "$current_error_name are not in ", |
649 | "alphabetical order.") if $opt_e; | | 649 | "alphabetical order.") if $opt_e; |
650 | } | | 650 | } |
651 | $s->{last_error_name} = $current_error_name; | | 651 | $s->{last_error_name} = $current_error_name; |
652 | } | | 652 | } |
653 | | | 653 | |
654 | $s->{lastline} = $_; | | 654 | $s->{lastline} = $_; |
655 | return "$_\n"; | | 655 | return "$_\n"; |
656 | } | | 656 | } |
657 | | | 657 | |
658 | sub finish | | 658 | sub finish |
659 | { | | 659 | { |
660 | my ($s) = @_; | | 660 | my ($s) = @_; |
661 | | | 661 | |
662 | if (NETBSD and not $s->{nxrcsidseen}) { | | 662 | if (NETBSD and not $s->{nxrcsidseen}) { |
663 | $s->warning("Missing RCS Id") if $opt_r; | | 663 | $s->warning("Missing RCS Id") if $opt_r; |
664 | } | | 664 | } |
665 | if (OPENBSD and not $s->{oxrcsidseen}) { | | 665 | if (OPENBSD and not $s->{oxrcsidseen}) { |
666 | $s->warning("Missing RCS Id") if $opt_r; | | 666 | $s->warning("Missing RCS Id") if $opt_r; |
667 | } | | 667 | } |
668 | | | 668 | |
669 | if ($s->{lastline} =~ /^\.Pp/o) { | | 669 | if ($s->{lastline} =~ /^\.Pp/o) { |
670 | $s->warning("Paragraph problem: .Pp at EOF") if $opt_P; | | 670 | $s->warning("Paragraph problem: .Pp at EOF") if $opt_P; |
671 | } | | 671 | } |
672 | | | 672 | |
673 | end_of_section($s); | | 673 | end_of_section($s); |
674 | | | 674 | |
675 | # if (not ($fn =~ /$section$/)) { | | 675 | # if (not ($fn =~ /$section$/)) { |
676 | # $s->warning("section doesn't match (internal value: $section)"); | | 676 | # $s->warning("section doesn't match (internal value: $section)"); |
677 | # } | | 677 | # } |
678 | if ($s->{mandoc_p}) { | | 678 | if ($s->{mandoc_p}) { |
679 | foreach my $i (qw(NAME SYNOPSIS DESCRIPTION)) { | | 679 | foreach my $i (qw(NAME SYNOPSIS DESCRIPTION)) { |
680 | if (not ($s->{shseen}{$i})) { | | 680 | if (not ($s->{shseen}{$i})) { |
681 | $s->warning("missing $i section") if $opt_S; | | 681 | $s->warning("missing $i section") if $opt_S; |
682 | } | | 682 | } |
683 | } | | 683 | } |
684 | } | | 684 | } |
685 | } | | 685 | } |
686 | | | 686 | |
687 | package main; | | 687 | package main; |
688 | | | 688 | |
689 | sub handle_file | | 689 | sub handle_file |
690 | { | | 690 | { |
691 | my $parser = Parser->new($_[0]); | | 691 | my $parser = Parser->new($_[0]); |
692 | | | 692 | |
693 | while ($_ = $parser->next_line) { | | 693 | while ($_ = $parser->next_line) { |
694 | $parser->process_and_save_line($_); | | 694 | $parser->process_and_save_line($_); |
695 | } | | 695 | } |
696 | | | 696 | |
697 | $parser->finish; | | 697 | $parser->finish; |
698 | $parser->close; | | 698 | $parser->close; |
699 | if ($Parser::opt_F and $parser->{changes}) { | | 699 | if ($Parser::opt_F and $parser->{changes}) { |
700 | open OUT, ">$_[0].new" or | | 700 | open OUT, ">$_[0].new" or |
701 | die "can't open output file `$_[0].new'"; | | 701 | die "can't open output file `$_[0].new'"; |
702 | for my $l (@{$parser->{all}}) { | | 702 | for my $l (@{$parser->{all}}) { |
703 | print OUT $l | | 703 | print OUT $l |
704 | } | | 704 | } |
705 | close OUT; | | 705 | close OUT; |
706 | system("mv -i $_[0].new $_[0]"); | | 706 | system("mv -i $_[0].new $_[0]"); |
707 | } | | 707 | } |
708 | } | | 708 | } |
709 | | | 709 | |
710 | Parser->handle_options; | | 710 | Parser->handle_options; |
711 | foreach my $file (@ARGV) { | | 711 | foreach my $file (@ARGV) { |
712 | handle_file($file); | | 712 | handle_file($file); |
713 | } | | 713 | } |