Tue Jul 30 18:46:29 2013 UTC ()
Make Bq and Er optional for errors.


(wiz)
diff -r1.34 -r1.35 pkgsrc/textproc/mdoclint/files/mdoclint

cvs diff -r1.34 -r1.35 pkgsrc/textproc/mdoclint/files/Attic/mdoclint (switch to unified diff)

--- pkgsrc/textproc/mdoclint/files/Attic/mdoclint 2013/07/30 18:37:56 1.34
+++ pkgsrc/textproc/mdoclint/files/Attic/mdoclint 2013/07/30 18:46:29 1.35
@@ -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
31use strict; 31use strict;
32use warnings; 32use warnings;
33 33
34$| = 1; 34$| = 1;
35 35
36package Parser; 36package Parser;
37use Getopt::Std; 37use Getopt::Std;
38 38
39use constant { 39use 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
46use vars qw( 46use 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
54my $arch=`uname -m`; 54my $arch=`uname -m`;
55chomp($arch); 55chomp($arch);
56my $options="AaDdeFfHhlmnOoPprSsvwXx"; 56my $options="AaDdeFfHhlmnOoPprSsvwXx";
57 57
58sub usage 58sub 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";
63mdoclint: verify man page correctness 63mdoclint: verify man page correctness
64usage: mdoclint [-$options] file ... 64usage: 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
88Default is $default if no flag is specified. 88Default is $default if no flag is specified.
89EOF 89EOF
90 exit(0); 90 exit(0);
91} 91}
92 92
93 93
94my %short = ( 94my %short = (
95 "Free" => ".Fx", 95 "Free" => ".Fx",
96 "Net" => ".Nx", 96 "Net" => ".Nx",
97 "Open" => ".Ox" 97 "Open" => ".Ox"
98); 98);
99 99
100my %libraries = ( 100my %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
159my %sections; 159my %sections;
160my $arches_re; 160my $arches_re;
161my $sections_re; 161my $sections_re;
162my $esections_re; 162my $esections_re;
163my $valid_date_re; 163my $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
232sub debug 232sub 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
238sub warning 238sub 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
248my $order = " !\"#\$\%&'()*+,-./:;<=>?[\\]^_{|}~". 248my $order = " !\"#\$\%&'()*+,-./:;<=>?[\\]^_{|}~".
249 "0123456789". 249 "0123456789".
250 "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; 250 "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
251 251
252sub forder { 252sub 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
265sub handle_options 265sub 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
284sub verify_xref 284sub 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
305sub new 305sub 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
334sub next_line 334sub 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
345sub close 345sub close
346{ 346{
347 my ($self) = @_; 347 my ($self) = @_;
348 348
349 close($self->{file}); 349 close($self->{file});
350} 350}
351 351
352sub parse_macro_args 352sub 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
370sub end_of_section 370sub 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
388sub set_section_header 388sub 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
423sub process_and_save_line 423sub 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
436sub process_line 436sub 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
658sub finish 658sub 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
687package main; 687package main;
688 688
689sub handle_file 689sub 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
710Parser->handle_options; 710Parser->handle_options;
711foreach my $file (@ARGV) { 711foreach my $file (@ARGV) {
712 handle_file($file); 712 handle_file($file);
713} 713}