| @@ -1,702 +1,702 @@ | | | @@ -1,702 +1,702 @@ |
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.38 2013/07/30 19:07:23 wiz Exp $ | | 4 | # $NetBSD: mdoclint,v 1.39 2013/08/02 13:16:54 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_P $opt_p $opt_r $opt_S $opt_s $opt_v $opt_w | | 49 | $opt_n $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="AaDdeFfHhlmnoPprSsvwXx"; | | 56 | my $options="AaDdeFfHhlmnoPprSsvwXx"; |
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 handle_options | | 252 | sub handle_options |
253 | { | | 253 | { |
254 | getopts($options); | | 254 | getopts($options); |
255 | $opt_h and usage(); | | 255 | $opt_h and usage(); |
256 | | | 256 | |
257 | # default to all warnings if no flag is set | | 257 | # default to all warnings if no flag is set |
258 | unless ($opt_A or $opt_a or $opt_D or $opt_d or $opt_e | | 258 | unless ($opt_A or $opt_a or $opt_D or $opt_d or $opt_e |
259 | or $opt_f or $opt_H or $opt_l | | 259 | or $opt_f or $opt_H or $opt_l |
260 | or $opt_m or $opt_n | | 260 | or $opt_m or $opt_n |
261 | or $opt_o or $opt_P or $opt_p or $opt_r | | 261 | or $opt_o or $opt_P or $opt_p or $opt_r |
262 | or $opt_S or $opt_s or $opt_X or $opt_x) { | | 262 | or $opt_S or $opt_s or $opt_X or $opt_x) { |
263 | $opt_A = $opt_a = $opt_D = $opt_d = $opt_f = $opt_m = | | 263 | $opt_A = $opt_a = $opt_D = $opt_d = $opt_f = $opt_m = |
264 | $opt_n = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = | | 264 | $opt_n = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = |
265 | $opt_s = $opt_X = $opt_x = 1; | | 265 | $opt_s = $opt_X = $opt_x = 1; |
266 | $opt_e = $opt_l = 1 if NETBSD; | | 266 | $opt_e = $opt_l = 1 if NETBSD; |
267 | } | | 267 | } |
268 | } | | 268 | } |
269 | | | 269 | |
270 | | | 270 | |
271 | sub verify_xref | | 271 | sub verify_xref |
272 | { | | 272 | { |
273 | my ($self, $page, $section, $pre, $post) = @_; | | 273 | my ($self, $page, $section, $pre, $post) = @_; |
274 | if ("$page.$section" eq $self->{fn}) { | | 274 | if ("$page.$section" eq $self->{fn}) { |
275 | $self->warning("Xref to itself (use .Nm instead)") if $opt_x; | | 275 | $self->warning("Xref to itself (use .Nm instead)") if $opt_x; |
276 | } | | 276 | } |
277 | # try to find corresponding man page | | 277 | # try to find corresponding man page |
278 | for my $dir ("/usr/share/man", | | 278 | for my $dir ("/usr/share/man", |
279 | OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { | | 279 | OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { |
280 | for my $a ("", $arch) { | | 280 | for my $a ("", $arch) { |
281 | for my $page ("man$section/$a/$page.$section") { | | 281 | for my $page ("man$section/$a/$page.$section") { |
282 | return 1 if -f "$dir/$page"; | | 282 | return 1 if -f "$dir/$page"; |
283 | } | | 283 | } |
284 | } | | 284 | } |
285 | } | | 285 | } |
286 | return 1 if -f "./$page.$section"; | | 286 | return 1 if -f "./$page.$section"; |
287 | | | 287 | |
288 | $self->warning($pre."trailing Xref to $page($section)$post") if $opt_x; | | 288 | $self->warning($pre."trailing Xref to $page($section)$post") if $opt_x; |
289 | return 0; | | 289 | return 0; |
290 | } | | 290 | } |
291 | | | 291 | |
292 | sub new | | 292 | sub new |
293 | { | | 293 | { |
294 | my ($class, $fn) = @_; | | 294 | my ($class, $fn) = @_; |
295 | | | 295 | |
296 | my $o = { | | 296 | my $o = { |
297 | mandoc_p => 1, | | 297 | mandoc_p => 1, |
298 | all => [], | | 298 | all => [], |
299 | lastline => '', | | 299 | lastline => '', |
300 | changes => 0, | | 300 | changes => 0, |
301 | oxrcsidseen => 0, | | 301 | oxrcsidseen => 0, |
302 | nxrcsidseen => 0, | | 302 | nxrcsidseen => 0, |
303 | lastsh => 0, | | 303 | lastsh => 0, |
304 | sasection => 0, | | 304 | sasection => 0, |
305 | saname => '', | | 305 | saname => '', |
306 | sarest => ',', | | 306 | sarest => ',', |
307 | inauthors => 0, | | 307 | inauthors => 0, |
308 | in_section => 0, | | 308 | in_section => 0, |
309 | inliteral => 0, | | 309 | inliteral => 0, |
310 | shseen => {}, | | 310 | shseen => {}, |
311 | last_error_name => '', | | 311 | last_error_name => '', |
312 | current_section_header => '', | | 312 | current_section_header => '', |
313 | fn => $fn | | 313 | fn => $fn |
314 | }; | | 314 | }; |
315 | open my $input, '<', $fn or die "can't open input file $fn"; | | 315 | open my $input, '<', $fn or die "can't open input file $fn"; |
316 | $o->{file} = $input; | | 316 | $o->{file} = $input; |
317 | $o->{ln} = 0; | | 317 | $o->{ln} = 0; |
318 | bless $o, $class; | | 318 | bless $o, $class; |
319 | } | | 319 | } |
320 | | | 320 | |
321 | sub next_line | | 321 | sub next_line |
322 | { | | 322 | { |
323 | my ($self) = @_; | | 323 | my ($self) = @_; |
324 | | | 324 | |
325 | my $l = readline($self->{file}); | | 325 | my $l = readline($self->{file}); |
326 | if (defined $l) { | | 326 | if (defined $l) { |
327 | $self->{ln}++; | | 327 | $self->{ln}++; |
328 | } | | 328 | } |
329 | return $l; | | 329 | return $l; |
330 | } | | 330 | } |
331 | | | 331 | |
332 | sub close | | 332 | sub close |
333 | { | | 333 | { |
334 | my ($self) = @_; | | 334 | my ($self) = @_; |
335 | | | 335 | |
336 | close($self->{file}); | | 336 | close($self->{file}); |
337 | } | | 337 | } |
338 | | | 338 | |
339 | sub parse_macro_args | | 339 | sub parse_macro_args |
340 | { | | 340 | { |
341 | my ($s, $string) = @_; | | 341 | my ($s, $string) = @_; |
342 | $_ = $string; | | 342 | $_ = $string; |
343 | my @params = (); | | 343 | my @params = (); |
344 | while (!/^$/) { | | 344 | while (!/^$/) { |
345 | if (s/^\"(.*?)\"\s*//) { | | 345 | if (s/^\"(.*?)\"\s*//) { |
346 | push(@params, $1); | | 346 | push(@params, $1); |
347 | } elsif (s/^(\S+)\s*//) { | | 347 | } elsif (s/^(\S+)\s*//) { |
348 | push(@params, $1); | | 348 | push(@params, $1); |
349 | } | | 349 | } |
350 | } | | 350 | } |
351 | if (@params > 9 and OPENBSD) { | | 351 | if (@params > 9 and OPENBSD) { |
352 | $s->warning("$string holds >9 parameters"); | | 352 | $s->warning("$string holds >9 parameters"); |
353 | } | | 353 | } |
354 | return @params; | | 354 | return @params; |
355 | } | | 355 | } |
356 | | | 356 | |
357 | sub end_of_section | | 357 | sub end_of_section |
358 | { | | 358 | { |
359 | my ($s) = @_; | | 359 | my ($s) = @_; |
360 | | | 360 | |
361 | if ($s->{in_section} == SECTION_SEE_ALSO and not $s->{sarest} eq "") { | | 361 | if ($s->{in_section} == SECTION_SEE_ALSO and not $s->{sarest} eq "") { |
362 | $s->warning("unneeded characters at end of SEE ALSO: ", | | 362 | $s->warning("unneeded characters at end of SEE ALSO: ", |
363 | "`$s->{sarest}'") if $opt_a; | | 363 | "`$s->{sarest}'") if $opt_a; |
364 | # to avoid a second warning at EOF | | 364 | # to avoid a second warning at EOF |
365 | $s->{sarest} = ""; | | 365 | $s->{sarest} = ""; |
366 | } | | 366 | } |
367 | | | 367 | |
368 | if ($s->{in_section} == SECTION_AUTHORS) { | | 368 | if ($s->{in_section} == SECTION_AUTHORS) { |
369 | if (!$s->{an_found}) { | | 369 | if (!$s->{an_found}) { |
370 | $s->warning("missing .An in AUTHORS section") if $opt_A; | | 370 | $s->warning("missing .An in AUTHORS section") if $opt_A; |
371 | } | | 371 | } |
372 | } | | 372 | } |
373 | } | | 373 | } |
374 | | | 374 | |
375 | sub set_section_header | | 375 | sub set_section_header |
376 | { | | 376 | { |
377 | my ($s, $section_header) = @_; | | 377 | my ($s, $section_header) = @_; |
378 | $section_header = join(' ', $s->parse_macro_args($section_header)); | | 378 | $section_header = join(' ', $s->parse_macro_args($section_header)); |
379 | | | 379 | |
380 | end_of_section($s); | | 380 | end_of_section($s); |
381 | | | 381 | |
382 | if ($section_header eq 'SEE ALSO') { | | 382 | if ($section_header eq 'SEE ALSO') { |
383 | $s->{in_section} = SECTION_SEE_ALSO; | | 383 | $s->{in_section} = SECTION_SEE_ALSO; |
384 | } elsif ($section_header eq 'AUTHORS') { | | 384 | } elsif ($section_header eq 'AUTHORS') { |
385 | $s->{in_section} = SECTION_AUTHORS; | | 385 | $s->{in_section} = SECTION_AUTHORS; |
386 | } else { | | 386 | } else { |
387 | $s->{in_section} = 0; | | 387 | $s->{in_section} = 0; |
388 | } | | 388 | } |
389 | | | 389 | |
390 | if (not $sections{$section_header}) { | | 390 | if (not $sections{$section_header}) { |
391 | $s->warning("unknown section header: ", | | 391 | $s->warning("unknown section header: ", |
392 | "`$section_header'") if $opt_S; | | 392 | "`$section_header'") if $opt_S; |
393 | } else { | | 393 | } else { |
394 | if ($s->{lastsh} >= $sections{$section_header}) { | | 394 | if ($s->{lastsh} >= $sections{$section_header}) { |
395 | $s->warning("section header ", | | 395 | $s->warning("section header ", |
396 | "`$section_header' in wrong order") if $opt_S; | | 396 | "`$section_header' in wrong order") if $opt_S; |
397 | } | | 397 | } |
398 | $s->{shseen}->{$section_header} = 1; | | 398 | $s->{shseen}->{$section_header} = 1; |
399 | $s->{lastsh} = $sections{$section_header}; | | 399 | $s->{lastsh} = $sections{$section_header}; |
400 | } | | 400 | } |
401 | | | 401 | |
402 | if ($s->{lastline} =~ /^\.Pp/o) { | | 402 | if ($s->{lastline} =~ /^\.Pp/o) { |
403 | $s->warning("Paragraph problem: section header after .Pp") | | 403 | $s->warning("Paragraph problem: section header after .Pp") |
404 | if $opt_P; | | 404 | if $opt_P; |
405 | } | | 405 | } |
406 | | | 406 | |
407 | $s->{current_section_header} = $section_header; | | 407 | $s->{current_section_header} = $section_header; |
408 | } | | 408 | } |
409 | | | 409 | |
410 | sub process_and_save_line | | 410 | sub process_and_save_line |
411 | { | | 411 | { |
412 | my $s; | | 412 | my $s; |
413 | ($s, $_) = @_; | | 413 | ($s, $_) = @_; |
414 | my $result = $s->process_line($_); | | 414 | my $result = $s->process_line($_); |
415 | # note that process_line chomps \n, then re-adds it, | | 415 | # note that process_line chomps \n, then re-adds it, |
416 | # so we detect a change on last lines without a \n. | | 416 | # so we detect a change on last lines without a \n. |
417 | if ($result ne $_) { | | 417 | if ($result ne $_) { |
418 | $s->{changes} = 1; | | 418 | $s->{changes} = 1; |
419 | } | | 419 | } |
420 | push(@{$s->{all}}, $result); | | 420 | push(@{$s->{all}}, $result); |
421 | } | | 421 | } |
422 | | | 422 | |
423 | sub process_line | | 423 | sub process_line |
424 | { | | 424 | { |
425 | my $s; | | 425 | my $s; |
426 | ($s, $_) = @_; | | 426 | ($s, $_) = @_; |
427 | chomp; | | 427 | chomp; |
428 | # always cut trailing spaces | | 428 | # always cut trailing spaces |
429 | if (/\s+$/o) { | | 429 | if (/\s+$/o) { |
430 | $s->warning("trailing space: `$_'") if $opt_s; | | 430 | $s->warning("trailing space: `$_'") if $opt_s; |
431 | s/\s+$//o; | | 431 | s/\s+$//o; |
432 | } | | 432 | } |
433 | if (/\$OpenBSD\b.*\$/o) { | | 433 | if (/\$OpenBSD\b.*\$/o) { |
434 | $s->{oxrcsidseen}++; | | 434 | $s->{oxrcsidseen}++; |
435 | if (OPENBSD and ($s->{oxrcsidseen} > 1)) { | | 435 | if (OPENBSD and ($s->{oxrcsidseen} > 1)) { |
436 | $s->warning("RCS Id seen twice") if $opt_r; | | 436 | $s->warning("RCS Id seen twice") if $opt_r; |
437 | } | | 437 | } |
438 | return "$_\n"; | | 438 | return "$_\n"; |
439 | } | | 439 | } |
440 | if (/[\$]NetBSD\b.*\$/o) { | | 440 | if (/[\$]NetBSD\b.*\$/o) { |
441 | $s->{nxrcsidseen}++; | | 441 | $s->{nxrcsidseen}++; |
442 | if (NETBSD and ($s->{nxrcsidseen} > 1)) { | | 442 | if (NETBSD and ($s->{nxrcsidseen} > 1)) { |
443 | $s->warning("RCS Id seen twice") if $opt_r; | | 443 | $s->warning("RCS Id seen twice") if $opt_r; |
444 | } | | 444 | } |
445 | return "$_\n"; | | 445 | return "$_\n"; |
446 | } | | 446 | } |
447 | # comments | | 447 | # comments |
448 | if (/^\.\\\"/) { | | 448 | if (/^\.\\\"/) { |
449 | return "$_\n"; | | 449 | return "$_\n"; |
450 | } | | 450 | } |
451 | if (/^\.TH\s+/o) { | | 451 | if (/^\.TH\s+/o) { |
452 | $s->warning("not mandoc") if $opt_m; | | 452 | $s->warning("not mandoc") if $opt_m; |
453 | $s->{mandoc_p} = 0; | | 453 | $s->{mandoc_p} = 0; |
454 | # /^.TH\s*[\w-_".]+\s*([1-9])/; | | 454 | # /^.TH\s*[\w-_".]+\s*([1-9])/; |
455 | # $section = $1; | | 455 | # $section = $1; |
456 | return "$_\n"; | | 456 | return "$_\n"; |
457 | } | | 457 | } |
458 | # if (/^.Dt\s*[\w-_".]+\s*([1-9])/) { | | 458 | # if (/^.Dt\s*[\w-_".]+\s*([1-9])/) { |
459 | # $section = $1; | | 459 | # $section = $1; |
460 | # } | | 460 | # } |
461 | if (/^\.Dt\s+/o) { | | 461 | if (/^\.Dt\s+/o) { |
462 | if (! /^\.Dt\s+(?:[A-Z\d._-]+)\s+$sections_re(?:\s+$arches_re)?$/o) { | | 462 | if (! /^\.Dt\s+(?:[A-Z\d._-]+)\s+$sections_re(?:\s+$arches_re)?$/o) { |
463 | $s->warning("bad .Dt: `$_'") if $opt_D; | | 463 | $s->warning("bad .Dt: `$_'") if $opt_D; |
464 | } | | 464 | } |
465 | } | | 465 | } |
466 | | | 466 | |
467 | if ($s->{mandoc_p}) { | | 467 | if ($s->{mandoc_p}) { |
468 | if (/^\.Sh\s+(.*)$/o) { | | 468 | if (/^\.Sh\s+(.*)$/o) { |
469 | my $line = $_; | | 469 | my $line = $_; |
470 | $s->set_section_header($1); | | 470 | $s->set_section_header($1); |
471 | return "$line\n"; | | 471 | return "$line\n"; |
472 | } | | 472 | } |
473 | } else { | | 473 | } else { |
474 | if (/^\.SH\s+(.*)$/o) { | | 474 | if (/^\.SH\s+(.*)$/o) { |
475 | my $line = $_; | | 475 | my $line = $_; |
476 | $s->set_section_header($1); | | 476 | $s->set_section_header($1); |
477 | return "$line\n"; | | 477 | return "$line\n"; |
478 | } | | 478 | } |
479 | } | | 479 | } |
480 | | | 480 | |
481 | if ($s->{in_section} == SECTION_SEE_ALSO) { | | 481 | if ($s->{in_section} == SECTION_SEE_ALSO) { |
482 | if (/^\.Xr\s+(\S+)\s+($sections_re)\s?(.*)?$/o) { | | 482 | if (/^\.Xr\s+(\S+)\s+($sections_re)\s?(.*)?$/o) { |
483 | my ($saname, $sasection, $sarest) = ($1, $2, $3); | | 483 | my ($saname, $sasection, $sarest) = ($1, $2, $3); |
484 | $saname =~ s/^\\&//o; | | 484 | $saname =~ s/^\\&//o; |
485 | if ($s->{sasection} gt $sasection | | 485 | if ($s->{sasection} gt $sasection |
486 | or ($s->{sasection} eq $sasection and | | 486 | or ($s->{sasection} eq $sasection and |
487 | (lc($s->{saname}) gt lc($saname)))) { | | 487 | (lc($s->{saname}) gt lc($saname)))) { |
488 | $s->warning("SEE ALSO: `.Xr $s->{saname} ", | | 488 | $s->warning("SEE ALSO: `.Xr $s->{saname} ", |
489 | "$s->{sasection}' should be after ", | | 489 | "$s->{sasection}' should be after ", |
490 | "`.Xr $saname $sasection'") if $opt_a; | | 490 | "`.Xr $saname $sasection'") if $opt_a; |
491 | } | | 491 | } |
492 | if ($s->{sarest} ne ",") { | | 492 | if ($s->{sarest} ne ",") { |
493 | $s->warning("SEE ALSO: .Xr not separated ", | | 493 | $s->warning("SEE ALSO: .Xr not separated ", |
494 | "by comma, but `$s->{sarest}'") if $opt_a; | | 494 | "by comma, but `$s->{sarest}'") if $opt_a; |
495 | } | | 495 | } |
496 | $s->{saname} = $saname; | | 496 | $s->{saname} = $saname; |
497 | $s->{sasection} = $sasection; | | 497 | $s->{sasection} = $sasection; |
498 | $s->{sarest} = $sarest; | | 498 | $s->{sarest} = $sarest; |
499 | } | | 499 | } |
500 | if (/^\.Rs(?:\s+|$)/o) { | | 500 | if (/^\.Rs(?:\s+|$)/o) { |
501 | if ($s->{sarest} ne "") { | | 501 | if ($s->{sarest} ne "") { |
502 | $s->warning("SEE ALSO: Not necessary to ", | | 502 | $s->warning("SEE ALSO: Not necessary to ", |
503 | "separate .Xr from .Rs by ", | | 503 | "separate .Xr from .Rs by ", |
504 | "`$s->{sarest}'") if $opt_a; | | 504 | "`$s->{sarest}'") if $opt_a; |
505 | } | | 505 | } |
506 | $s->{sarest} = ""; | | 506 | $s->{sarest} = ""; |
507 | } | | 507 | } |
508 | } | | 508 | } |
509 | if ($s->{in_section} == SECTION_AUTHORS) { | | 509 | if ($s->{in_section} == SECTION_AUTHORS) { |
510 | if (/^\.An / && not /^\.An -(no|)split/) { | | 510 | if (/^\.An / && not /^\.An -(no|)split/) { |
511 | $s->{an_found} = 1; | | 511 | $s->{an_found} = 1; |
512 | } | | 512 | } |
513 | } | | 513 | } |
514 | | | 514 | |
515 | if (/^\.Fn.*,.+/o) { | | 515 | if (/^\.Fn.*,.+/o) { |
516 | $s->warning("possible .Fn misuse: `$_'") if $opt_f; | | 516 | $s->warning("possible .Fn misuse: `$_'") if $opt_f; |
517 | } | | 517 | } |
518 | if (OPENBSD) { | | 518 | if (OPENBSD) { |
519 | if (/^(?:[<>])/o or /[^\\][<>]/o) { | | 519 | if (/^(?:[<>])/o or /[^\\][<>]/o) { |
520 | $s->warning("use \*(Lt \*(Gt (or .Aq) ", | | 520 | $s->warning("use \*(Lt \*(Gt (or .Aq) ", |
521 | "instead of < >: `$_'") if $opt_H; | | 521 | "instead of < >: `$_'") if $opt_H; |
522 | } | | 522 | } |
523 | } | | 523 | } |
524 | if (NETBSD) { | | 524 | if (NETBSD) { |
525 | if (/^(?:[<>&])/o or /[^\\][<>&]/o) { | | 525 | if (/^(?:[<>&])/o or /[^\\][<>&]/o) { |
526 | $s->warning("use \*[Lt] \*[Gt] (or .Aq) \*[Am] ", | | 526 | $s->warning("use \*[Lt] \*[Gt] (or .Aq) \*[Am] ", |
527 | "instead of < > &: `$_'") if $opt_H; | | 527 | "instead of < > &: `$_'") if $opt_H; |
528 | } | | 528 | } |
529 | } | | 529 | } |
530 | | | 530 | |
531 | if (/\b(Free|Net|Open)BSD\b/o | | 531 | if (/\b(Free|Net|Open)BSD\b/o |
532 | and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o | | 532 | and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o |
533 | and not /\bOpenBSD\::.*3p\b/o | | 533 | and not /\bOpenBSD\::.*3p\b/o |
534 | and not /\/pub\/OpenBSD\//o | | 534 | and not /\/pub\/OpenBSD\//o |
535 | and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { | | 535 | and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { |
536 | $s->warning("verbose mention of `$1BSD' instead of " | | 536 | $s->warning("verbose mention of `$1BSD' instead of " |
537 | . "`$short{$1}': `$_'") if $opt_X; | | 537 | . "`$short{$1}': `$_'") if $opt_X; |
538 | } | | 538 | } |
539 | if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { | | 539 | if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { |
540 | $s->warning("`.Bx $1' found -- use $short{$1} instead") | | 540 | $s->warning("`.Bx $1' found -- use $short{$1} instead") |
541 | if $opt_X; | | 541 | if $opt_X; |
542 | } | | 542 | } |
543 | if (/^\.Lb\s+(\S+)/o) { | | 543 | if (/^\.Lb\s+(\S+)/o) { |
544 | if (not $libraries{$1}) { | | 544 | if (not $libraries{$1}) { |
545 | $s->warning("Unknown library `$1' used as Lb argument") if $opt_l; | | 545 | $s->warning("Unknown library `$1' used as Lb argument") if $opt_l; |
546 | } | | 546 | } |
547 | } | | 547 | } |
548 | if (/^\.Os\s+(.+)/o) { | | 548 | if (/^\.Os\s+(.+)/o) { |
549 | $s->warning(".Os used with argument `$1'") if $opt_o; | | 549 | $s->warning(".Os used with argument `$1'") if $opt_o; |
550 | } | | 550 | } |
551 | | | 551 | |
552 | if (/^\.Nd.*\.$/o) { | | 552 | if (/^\.Nd.*\.$/o) { |
553 | $s->warning(".Nd ends with a dot: `$_'") if $opt_n; | | 553 | $s->warning(".Nd ends with a dot: `$_'") if $opt_n; |
554 | } | | 554 | } |
555 | | | 555 | |
556 | if (/(\w\w)\.\s+[A-Z]/o and not /^.%T/ and not $s->{inliteral}) { | | 556 | if (/(\w\w)\.\s+[A-Z]/o and not /^.%T/ and not $s->{inliteral}) { |
557 | if ("$1" ne "St") { | | 557 | if ("$1" ne "St") { |
558 | $s->warning("new sentence, new line: `$_'") if $opt_p; | | 558 | $s->warning("new sentence, new line: `$_'") if $opt_p; |
559 | } | | 559 | } |
560 | } | | 560 | } |
561 | if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o | | 561 | if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o |
562 | and not /\s\.\.\.$/o and not /\\&.$/o) { | | 562 | and not /\s\.\.\.$/o and not /\\&.$/o) { |
563 | $s->warning("punctuation in format string ", | | 563 | $s->warning("punctuation in format string ", |
564 | "without space: `$_'") if $opt_p; | | 564 | "without space: `$_'") if $opt_p; |
565 | } | | 565 | } |
566 | if (/^\./o and /Ns [\.();,\[\]\{\}:]/o) { | | 566 | if (/^\./o and /Ns [\.();,\[\]\{\}:]/o) { |
567 | $s->warning("possible Ns abuse: `$_'") if $opt_p; | | 567 | $s->warning("possible Ns abuse: `$_'") if $opt_p; |
568 | } | | 568 | } |
569 | if ((/^([^\.]\w+)\(\)/o or /^[^\.].*\s(\w+)\(\)/o) and not $s->{inliteral}) { | | 569 | if ((/^([^\.]\w+)\(\)/o or /^[^\.].*\s(\w+)\(\)/o) and not $s->{inliteral}) { |
570 | $s->warning("use .Fn or .Xr for functions: `$1()'") if $opt_p; | | 570 | $s->warning("use .Fn or .Xr for functions: `$1()'") if $opt_p; |
571 | } | | 571 | } |
572 | | | 572 | |
573 | my $destruct = $_; | | 573 | my $destruct = $_; |
574 | if ($s->{mandoc_p}) { | | 574 | if ($s->{mandoc_p}) { |
575 | $destruct =~ s/\\\&([\w\.])/$1/o; | | 575 | $destruct =~ s/\\\&([\w\.])/$1/o; |
576 | if ($destruct =~ /^\.Xr\s+([\w\:\.\-\+\/]+)\s+($esections_re)(.*)/o) { | | 576 | if ($destruct =~ /^\.Xr\s+([\w\:\.\-\+\/]+)\s+($esections_re)(.*)/o) { |
577 | $s->debug("Xref to $1($2) found: `$_'"); | | 577 | $s->debug("Xref to $1($2) found: `$_'"); |
578 | $s->verify_xref($1, $2, "", ""); | | 578 | $s->verify_xref($1, $2, "", ""); |
579 | if ($3 =~ /^\S/o) { | | 579 | if ($3 =~ /^\S/o) { |
580 | $s->warning("No space after section number in Xref: `$_'") if $opt_x; | | 580 | $s->warning("No space after section number in Xref: `$_'") if $opt_x; |
581 | } | | 581 | } |
582 | } elsif ($destruct =~ /^\.Xr/o) { | | 582 | } elsif ($destruct =~ /^\.Xr/o) { |
583 | $s->warning("Weird Xref found: `$_'") if $opt_x; | | 583 | $s->warning("Weird Xref found: `$_'") if $opt_x; |
584 | } | | 584 | } |
585 | } else { | | 585 | } else { |
586 | $destruct =~ s/\\f.//go; | | 586 | $destruct =~ s/\\f.//go; |
587 | if ($destruct !~ /^\.\\\"/o) { | | 587 | if ($destruct !~ /^\.\\\"/o) { |
588 | while ($destruct =~ s/([-\w.]+)\s*\(($esections_re)\)//o) { | | 588 | while ($destruct =~ s/([-\w.]+)\s*\(($esections_re)\)//o) { |
589 | $s->debug("possible Xref to $1($2) found: `$_'"); | | 589 | $s->debug("possible Xref to $1($2) found: `$_'"); |
590 | $s->verify_xref($1, $2, "possible ", ": `$_'"); | | 590 | $s->verify_xref($1, $2, "possible ", ": `$_'"); |
591 | # so that we have a chance to find more than one | | 591 | # so that we have a chance to find more than one |
592 | # per line | | 592 | # per line |
593 | $destruct =~ s/(\w+)\s*\(($sections_re)\)//o; | | 593 | $destruct =~ s/(\w+)\s*\(($sections_re)\)//o; |
594 | } | | 594 | } |
595 | } | | 595 | } |
596 | } | | 596 | } |
597 | | | 597 | |
598 | if (/^\.Dd/o and not /^\.Dd\s+$valid_date_re/o) { | | 598 | if (/^\.Dd/o and not /^\.Dd\s+$valid_date_re/o) { |
599 | $s->warning("Invalid date found: `$_'") if $opt_d; | | 599 | $s->warning("Invalid date found: `$_'") if $opt_d; |
600 | } | | 600 | } |
601 | | | 601 | |
602 | if (/^\.Bd\b.*-literal\b/o) { | | 602 | if (/^\.Bd\b.*-literal\b/o) { |
603 | $s->{inliteral} = 1; | | 603 | $s->{inliteral} = 1; |
604 | } | | 604 | } |
605 | if ($s->{inliteral} == 1) { | | 605 | if ($s->{inliteral} == 1) { |
606 | if (/^\.Ed\b/o) { | | 606 | if (/^\.Ed\b/o) { |
607 | $s->{inliteral} = 0; | | 607 | $s->{inliteral} = 0; |
608 | } | | 608 | } |
609 | } elsif (/^$/o) { | | 609 | } elsif (/^$/o) { |
610 | $s->warning("Paragraph problem: empty line -- ", | | 610 | $s->warning("Paragraph problem: empty line -- ", |
611 | "use .Pp for paragraphs") if $opt_P; | | 611 | "use .Pp for paragraphs") if $opt_P; |
612 | } | | 612 | } |
613 | if ($s->{lastline} =~ /^\.Pp/o and /^(\.Ss|\.Pp)/o) { | | 613 | if ($s->{lastline} =~ /^\.Pp/o and /^(\.Ss|\.Pp)/o) { |
614 | $s->warning("Paragraph problem: $1 after .Pp") if $opt_P; | | 614 | $s->warning("Paragraph problem: $1 after .Pp") if $opt_P; |
615 | } | | 615 | } |
616 | if (/^\.Pp/o and $s->{lastline} =~ /^(\.S[Ssh])/o) { | | 616 | if (/^\.Pp/o and $s->{lastline} =~ /^(\.S[Ssh])/o) { |
617 | $s->warning("Paragraph problem: .Pp after $1") if $opt_P; | | 617 | $s->warning("Paragraph problem: .Pp after $1") if $opt_P; |
618 | } | | 618 | } |
619 | | | 619 | |
620 | # Check whether the list of possible errors for a function is | | 620 | # Check whether the list of possible errors for a function is |
621 | # sorted alphabetically. | | 621 | # sorted alphabetically. |
622 | # | | 622 | # |
623 | # Error names should not be sorted across different lists. | | 623 | # Error names should not be sorted across different lists. |
624 | # (see bind(2) for an example.) | | 624 | # (see bind(2) for an example.) |
625 | # | | 625 | # |
626 | /^\.Bl\s+/o and $s->{last_error_name} = ""; | | 626 | /^\.Bl\s+/o and $s->{last_error_name} = ""; |
627 | | | 627 | |
628 | if ($s->{current_section_header} eq "ERRORS" and | | 628 | if ($s->{current_section_header} eq "ERRORS" and |
629 | /^\.It\s+(Bq\s+)?(Er\s+)?(E[\w_]+)$/o) { | | 629 | /^\.It\s+(Bq\s+)?(Er\s+)?(E[\w_]+)$/o) { |
630 | my $current_error_name = $3; | | 630 | my $current_error_name = $3; |
631 | | | 631 | |
632 | if ($s->{last_error_name} eq $current_error_name) { | | 632 | if ($s->{last_error_name} eq $current_error_name) { |
633 | $s->warning("Duplicate item for ", | | 633 | $s->warning("Duplicate item for ", |
634 | $current_error_name, ".") if $opt_e; | | 634 | $current_error_name, ".") if $opt_e; |
635 | } elsif ($current_error_name lt $s->{last_error_name}) { | | 635 | } elsif ($current_error_name lt $s->{last_error_name}) { |
636 | $s->warning("$s->{last_error_name} and ", | | 636 | $s->warning("$s->{last_error_name} and ", |
637 | "$current_error_name are not in ", | | 637 | "$current_error_name are not in ", |
638 | "alphabetical order.") if $opt_e; | | 638 | "alphabetical order.") if $opt_e; |
639 | } | | 639 | } |
640 | $s->{last_error_name} = $current_error_name; | | 640 | $s->{last_error_name} = $current_error_name; |
641 | } | | 641 | } |
642 | | | 642 | |
643 | $s->{lastline} = $_; | | 643 | $s->{lastline} = $_; |
644 | return "$_\n"; | | 644 | return "$_\n"; |
645 | } | | 645 | } |
646 | | | 646 | |
647 | sub finish | | 647 | sub finish |
648 | { | | 648 | { |
649 | my ($s) = @_; | | 649 | my ($s) = @_; |
650 | | | 650 | |
651 | if (NETBSD and not $s->{nxrcsidseen}) { | | 651 | if (NETBSD and not $s->{nxrcsidseen}) { |
652 | $s->warning("Missing RCS Id") if $opt_r; | | 652 | $s->warning("Missing RCS Id") if $opt_r; |
653 | } | | 653 | } |
654 | if (OPENBSD and not $s->{oxrcsidseen}) { | | 654 | if (OPENBSD and not $s->{oxrcsidseen}) { |
655 | $s->warning("Missing RCS Id") if $opt_r; | | 655 | $s->warning("Missing RCS Id") if $opt_r; |
656 | } | | 656 | } |
657 | | | 657 | |
658 | if ($s->{lastline} =~ /^\.Pp/o) { | | 658 | if ($s->{lastline} =~ /^\.Pp/o) { |
659 | $s->warning("Paragraph problem: .Pp at EOF") if $opt_P; | | 659 | $s->warning("Paragraph problem: .Pp at EOF") if $opt_P; |
660 | } | | 660 | } |
661 | | | 661 | |
662 | end_of_section($s); | | 662 | end_of_section($s); |
663 | | | 663 | |
664 | # if (not ($fn =~ /$section$/)) { | | 664 | # if (not ($fn =~ /$section$/)) { |
665 | # $s->warning("section doesn't match (internal value: $section)"); | | 665 | # $s->warning("section doesn't match (internal value: $section)"); |
666 | # } | | 666 | # } |
667 | if ($s->{mandoc_p}) { | | 667 | if ($s->{mandoc_p}) { |
668 | foreach my $i (qw(NAME SYNOPSIS DESCRIPTION)) { | | 668 | foreach my $i (qw(NAME SYNOPSIS DESCRIPTION)) { |
669 | if (not ($s->{shseen}{$i})) { | | 669 | if (not ($s->{shseen}{$i})) { |
670 | $s->warning("missing $i section") if $opt_S; | | 670 | $s->warning("missing $i section") if $opt_S; |
671 | } | | 671 | } |
672 | } | | 672 | } |
673 | } | | 673 | } |
674 | } | | 674 | } |
675 | | | 675 | |
676 | package main; | | 676 | package main; |
677 | | | 677 | |
678 | sub handle_file | | 678 | sub handle_file |
679 | { | | 679 | { |
680 | my $parser = Parser->new($_[0]); | | 680 | my $parser = Parser->new($_[0]); |
681 | | | 681 | |
682 | while ($_ = $parser->next_line) { | | 682 | while ($_ = $parser->next_line) { |
683 | $parser->process_and_save_line($_); | | 683 | $parser->process_and_save_line($_); |
684 | } | | 684 | } |
685 | | | 685 | |
686 | $parser->finish; | | 686 | $parser->finish; |
687 | $parser->close; | | 687 | $parser->close; |
688 | if ($Parser::opt_F and $parser->{changes}) { | | 688 | if ($Parser::opt_F and $parser->{changes}) { |
689 | open OUT, ">$_[0].new" or | | 689 | open OUT, ">$_[0].new" or |
690 | die "can't open output file `$_[0].new'"; | | 690 | die "can't open output file `$_[0].new'"; |
691 | for my $l (@{$parser->{all}}) { | | 691 | for my $l (@{$parser->{all}}) { |
692 | print OUT $l | | 692 | print OUT $l |
693 | } | | 693 | } |
694 | close OUT; | | 694 | close OUT; |
695 | system("mv -i $_[0].new $_[0]"); | | 695 | system("mv -i $_[0].new $_[0]"); |
696 | } | | 696 | } |
697 | } | | 697 | } |
698 | | | 698 | |
699 | Parser->handle_options; | | 699 | Parser->handle_options; |
700 | foreach my $file (@ARGV) { | | 700 | foreach my $file (@ARGV) { |
701 | handle_file($file); | | 701 | handle_file($file); |
702 | } | | 702 | } |