diff options
author | wiz <wiz@pkgsrc.org> | 2009-03-01 21:25:39 +0000 |
---|---|---|
committer | wiz <wiz@pkgsrc.org> | 2009-03-01 21:25:39 +0000 |
commit | d5222d76c56a5bef0e6f4d385ebf700209de04f9 (patch) | |
tree | bc1b2cf846e474070f436bd99158a24640b19188 /textproc | |
parent | 286da06cb3452625f231bcd6bf1cb02e44615cdb (diff) | |
download | pkgsrc-d5222d76c56a5bef0e6f4d385ebf700209de04f9.tar.gz |
Initial import of mdoclint-1.0:
mdoclint is a tool to verify that man pages follow the conventions
for NetBSD (and most other BSDs) regarding structure and macro
usage.
Diffstat (limited to 'textproc')
-rw-r--r-- | textproc/mdoclint/DESCR | 3 | ||||
-rw-r--r-- | textproc/mdoclint/Makefile | 35 | ||||
-rw-r--r-- | textproc/mdoclint/PLIST | 3 | ||||
-rwxr-xr-x | textproc/mdoclint/files/TODO | 24 | ||||
-rwxr-xr-x | textproc/mdoclint/files/mdoclint | 589 | ||||
-rwxr-xr-x | textproc/mdoclint/files/mdoclint.1 | 157 |
6 files changed, 811 insertions, 0 deletions
diff --git a/textproc/mdoclint/DESCR b/textproc/mdoclint/DESCR new file mode 100644 index 00000000000..a9b84e75b7e --- /dev/null +++ b/textproc/mdoclint/DESCR @@ -0,0 +1,3 @@ +mdoclint is a tool to verify that man pages follow the conventions +for NetBSD (and most other BSDs) regarding structure and macro +usage. diff --git a/textproc/mdoclint/Makefile b/textproc/mdoclint/Makefile new file mode 100644 index 00000000000..e6a0a56e4e7 --- /dev/null +++ b/textproc/mdoclint/Makefile @@ -0,0 +1,35 @@ +# $NetBSD: Makefile,v 1.1.1.1 2009/03/01 21:25:39 wiz Exp $ + +DISTNAME= mdoclint-1.0 +CATEGORIES= textproc +MASTER_SITES= # none +DISTFILES= # none + +MAINTAINER= wiz@NetBSD.org +#HOMEPAGE= # +COMMENT= Tool for verifying man pages + +PKG_DESTDIR_SUPPORT= user-destdir +INSTALLATION_DIRS= bin ${PKGMANDIR}/man1 + +WRKSRC= ${WRKDIR} +NO_CHECKSUM= yes +NO_BUILD= yes +USE_LANGUAGES= # none +USE_TOOLS+= perl:run + +SUBST_CLASSES+= perl +SUBST_STAGE.perl= do-configure +SUBST_FILES.perl= mdoclint +SUBST_SED.perl+= -e 's,@PERL5@,${PERL5},g' +SUBST_MESSAGE.perl= Fixing path to perl. + +do-extract: + cd ${FILESDIR} && cp mdoclint* ${WRKSRC}/ + +do-install: + ${INSTALL_SCRIPT} ${WRKSRC}/mdoclint ${DESTDIR}${PREFIX}/bin + ${INSTALL_MAN} ${FILESDIR}/mdoclint.1 \ + ${DESTDIR}${PREFIX}/${PKGMANDIR}/man1 + +.include "../../mk/bsd.pkg.mk" diff --git a/textproc/mdoclint/PLIST b/textproc/mdoclint/PLIST new file mode 100644 index 00000000000..429ae76fe56 --- /dev/null +++ b/textproc/mdoclint/PLIST @@ -0,0 +1,3 @@ +@comment $NetBSD: PLIST,v 1.1.1.1 2009/03/01 21:25:39 wiz Exp $ +bin/mdoclint +man/man1/mdoclint.1 diff --git a/textproc/mdoclint/files/TODO b/textproc/mdoclint/files/TODO new file mode 100755 index 00000000000..c53b319940d --- /dev/null +++ b/textproc/mdoclint/files/TODO @@ -0,0 +1,24 @@ +# $NetBSD: TODO,v 1.1.1.1 2009/03/01 21:25:39 wiz Exp $ +. check for font changes in .Bd -literal (.Fd, .No, ...) +. add checks for only allowed values after .Bl/.Bd/... +. compare internal with external section name +. complain if NULL is used without .Dv +. complain if error values are used without .Er +[. Nm doesn't need an argument, most of the time (?)] +. .Nm "": remove if not needed +. count correct matching of .Bd/.Ed, .Rs/.Re and similar +. check AUTHORS sections for usage of .An name Aq email@host +. recognize more section headers? +. check .Rs/.Re contents? +. empty lines in .Bd -literal ignored -- groff ignores them, too... +. ignore .Bd -literal for most checks (.Nm/.Xr, new sentence, new line, ...) +. ignore matching braces in macro arguments +. fix bogus report if no .Xr, but .Rs in SEE ALSO section +. recognize which sections should be in a particular type of manpage + (like RETURN VALUES in 2&3, EXIT STATUS in 1&8 et al.) +. check paths pointed at by .Pa directives? +. sort in WARNS and ERRS and add switches for those two +. complain about `,', `;' and similar on beginning of line +. complain about ',' after last .Nm entry +. complain about NULL without .Dv +. complain about -1 (not \-1) diff --git a/textproc/mdoclint/files/mdoclint b/textproc/mdoclint/files/mdoclint new file mode 100755 index 00000000000..304618ab7ba --- /dev/null +++ b/textproc/mdoclint/files/mdoclint @@ -0,0 +1,589 @@ +#!@PERL5@ +# +# $OpenBSD: mdoclint,v 1.13 2008/12/31 10:55:11 espie Exp $ +# $NetBSD: mdoclint,v 1.1.1.1 2009/03/01 21:25:39 wiz Exp $ +# +# Copyright (c) 2001-2009 Thomas Klausner +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR, THOMAS KLAUSNER, +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +use strict; +use warnings; + +$| = 1; + +package Parser; +use Getopt::Std; + +use constant { + OPENBSD => 0, + NETBSD => 1 +}; + +use vars qw( + $opt_a $opt_D $opt_d $opt_e $opt_F $opt_f $opt_H $opt_h $opt_m + $opt_n $opt_o $opt_P $opt_p $opt_r $opt_S $opt_s $opt_v + $opt_X $opt_x +); + + +my $arch=`uname -m`; +chomp($arch); +my $options="aDdeFfHhmnoPprSsvXx"; + +sub usage + { + my $default = OPENBSD ? "-aDdfHmnoPprSsXx" : "-aDdefHmnoPprSsXx"; + + print STDERR <<"EOF"; +mdoclint: verify man page correctness +usage: mdoclint [-$options] file ... + -a warn about SEE ALSO section problems + -D warn about bad casing and archs in .Dt + -d warn about bad date strings (in .Dd only) + -e warn about unsorted errors (for functions) + -F fix whitespace problems (asks before overwriting) + -f warn about possible incorrect .Fn syntax + -H warn about characters that produce problems in HTML output + -h display this help text + -m warn about man pages that are not in mdoc(7) format + -n warn about .Nd's ending in '.' + -o warn about non-empty .Os strings + -P warn about paragraph problems + -p warn about punctuation problems + -r warn about missing RCS Id + -S warn about any .Sh weirdness + -s warn about whitespace problems + -v verbose output + -X warn about explicit mentions of FreeBSD, NetBSD, or OpenBSD + -x warn about cross-references with missing targets +Default is $default if no flag is specified. +EOF + exit(0); +} + + +my %short = ( + "Free" => ".Fx", + "Net" => ".Nx", + "Open" => ".Ox" +); + +# constants to build +my %sections; +my $arches_re; +my $sections_re; +my $esections_re; +my $valid_date_re; +# and the code that builds them +{ + my @sections = ( + "NAME", + NETBSD ? "LIBRARY" : undef, + "SYNOPSIS", + "DESCRIPTION", + NETBSD ? "EXIT STATUS" : undef, + "RETURN VALUES", + "ENVIRONMENT", + "FILES", + "EXAMPLES", + "DIAGNOSTICS", + "ERRORS", + "SEE ALSO", + "STANDARDS", + "HISTORY", + "AUTHORS", + "CAVEATS", + "BUGS", + NETBSD ? "SECURITY CONSIDERATIONS" : undef + ); + + my $i = 1; + for my $sh (@sections) { + if (defined $sh) { + $sections{$sh} = $i++; + } + } + my @arches; + if (OPENBSD) { + @arches = + (qw(alpha amd64 arm armish aviion cats hp300 hppa + hppa64 i386 landisk luna88k mac68k macppc mvme68k + mvme88k sgi socppc sparc sparc64 vax zaurus)); + } + if (NETBSD) { + @arches = + (qw(acorn26 acorn32 algor alpha amiga arc atari + bebox cats cesfic cobalt dreamcast evbarm evbmips + evbsh3 evbsh5 hp300 hp700 hpcarm hpcmips hpcsh + i386 ibmnws luna68k mac68k macppc mipsco mmeye + mvme68k mvmeppc netwinder news68k newsmips next68k + pc532 playstation2 pmax pmppc prep sandpoint sbmips + sgimips shark sparc sparc64 sun2 sun3 vax walnut + x68k x86_64)); + } + my $a = join('|', @arches); + $arches_re = qr{(?:$a)}o; + if (OPENBSD) { + $sections_re = qr{(?:3p|[1-9])}o; + $esections_re = qr{(?:3p|[0-9])}o; + } + if (NETBSD) { + $sections_re = qr{[1-9]}o; + $esections_re = qr{[0-9]}o; + } + if (OPENBSD) { + $valid_date_re = qr{\$Mdocdate\b}; + } + if (NETBSD) { + $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[012345678])$}o; + } +} + +sub debug +{ + my $self = shift; + print STDOUT "debug: $self->{fn}:$self->{ln}: @_\n" if $opt_v; +} + +sub warning +{ + my $self = shift; + print STDOUT "$self->{fn}:$self->{current_section_header}:$self->{ln}: ", join('', @_), "\n"; +} + +sub handle_options +{ + getopts($options); + $opt_h and usage(); + + # default to all warnings if no flag is set + unless ($opt_a or $opt_D or $opt_d or $opt_e or $opt_f or $opt_H + or $opt_m or $opt_n or $opt_o or $opt_P or $opt_p or $opt_r + or $opt_S or $opt_s or $opt_X or $opt_x) { + $opt_a = $opt_D = $opt_d = $opt_f = $opt_H = $opt_m = + $opt_n = $opt_o = $opt_P = $opt_p = $opt_r = $opt_S = + $opt_s = $opt_X = $opt_x = 1; + $opt_e = 1 if NETBSD; + } +} + + +sub verify_xref +{ + my ($self, $page, $section, $pre, $post) = @_; + if ("$page.$section" eq $self->{fn}) { + $self->warning("Xref to itself (use .Nm instead)"); + } + # try to find corresponding man page + for my $dir ("/usr/share/man", + OPENBSD ? "/usr/X11R6/man" : "/usr/X11R7/man") { + for my $a ("", $arch) { + for my $page ("cat$section/$a/$page.0", + "man$section/$a/$page.$section") { + return 1 if -f "$dir/$page"; + } + } + } + return 1 if -f "./$page.$section"; + + $self->warning($pre."trailing Xref to $page($section)$post"); + return 0; +} + +sub new +{ + my ($class, $fn) = @_; + + my $o = { + mandoc_p => 1, + all => '', + lastline => '', + changes => 0, + oxrcsidseen => 0, + nxrcsidseen => 0, + lastsh => 0, + sasection => 0, + saname => '', + sarest => ',', + insa => 0, + inliteral => 0, + shseen => {}, + last_error_name => '', + current_section_header => '', + fn => $fn + }; + open my $input, '<', $fn or die "can't open input file $fn"; + $o->{file} = $input; + $o->{ln} = 0; + bless $o, $class; +} + +sub next_line +{ + my ($self) = @_; + + my $l = readline($self->{file}); + if (defined $l) { + $self->{ln}++; + } + return $l; +} + +sub close +{ + my ($self) = @_; + + close($self->{file}); +} + +sub parse_macro_args +{ + my ($s, $string) = @_; + my $_ = $string; + my @params = (); + while (!/^$/) { + if (s/^\"(.*?)\"\s*//) { + push(@params, $1); + } elsif (s/^(\S+)\s*//) { + push(@params, $1); + } + } + if (@params > 9 and OPENBSD) { + $s->warning("$string holds >9 parameters"); + } + return @params; +} + +sub set_section_header +{ + my ($s, $section_header) = @_; + $section_header = join(' ', $s->parse_macro_args($section_header)); + if ($section_header eq 'SEE ALSO') { + $s->{insa} = 1; + } elsif ($s->{insa} == 1) { + if (not $s->{sarest} eq "") { + $s->warning("unneeded characters at end of ", + "SEE ALSO: ", "`$s->{sarest}'") if $opt_a; + # to avoid a second warning at EOF + $s->{sarest} = ""; + } + # finished SEE ALSO section + $s->{insa} = 2; + } + if ($opt_S) { + if (not $sections{$section_header}) { + $s->warning("unknown section header: ", + "`$section_header'"); + } else { + if ($s->{lastsh} >= $sections{$section_header}) { + $s->warning("section header ", + "`$section_header' in wrong order"); + } + $s->{shseen}->{$section_header} = 1; + $s->{lastsh} = $sections{$section_header}; + } + } + if ($s->{lastline} =~ /^\.Pp/o) { + $s->warning("Paragraph problem: section header after .Pp"); + } + + $s->{current_section_header} = $section_header; +} + +sub process_line +{ + my ($s, $_) = @_; + chomp; + # always cut trailing spaces + if (/\s+$/o) { + $s->warning("trailing space: `$_'") if $opt_s; + s/\s+$//o; + $s->{changes} = 1; + } + if (/\$OpenBSD\b.*\$/o) { + $s->{oxrcsidseen} = 1; + # nothing else to do + return; + } + if (/\$NetBSD\b.*\$/o) { + $s->{nxrcsidseen} = 1; + # nothing else to do + return; + } + # comments + if (/^\.\\\"/) { + return; + } + if (/^\.TH\s+/o) { + $s->warning("not mandoc") if $opt_m; + $s->{mandoc_p} = 0; +# /^.TH\s*[\w-_".]+\s*([1-9])/; +# $section = $1; + return; + } +# if (/^.Dt\s*[\w-_".]+\s*([1-9])/) { +# $section = $1; +# } + if ($opt_D and /^\.Dt\s+/o) { + if (! /^\.Dt\s+(?:[A-Z\d._-]+)\s+$sections_re(?:\s+$arches_re)?$/o) { + $s->warning("bad .Dt: `$_'"); + } + } + + if ($s->{mandoc_p}) { + if (/^\.Sh\s+(.*)$/o) { + $s->set_section_header($1); + return; + } + } else { + if (/^\.SH\s+(.*)$/o) { + $s->set_section_header($1); + return; + } + } + + if ($opt_a) { + if ($s->{insa} == 1) { + if (/^\.Xr\s+(\S+)\s+($sections_re)\s?(.*)?$/o) { + my ($saname, $sasection, $sarest) = ($1, $2, $3); + $saname =~ s/^\\&//o; + if ($s->{sasection} gt $sasection + or ($s->{sasection} eq $sasection and + ($s->{saname} cmp $saname) > 0)) { + $s->warning("SEE ALSO: `.Xr $s->{saname} $s->{sasection}' should " + . "be after `.Xr $saname $sasection'"); + } + if ($s->{sarest} ne ",") { + $s->warning("SEE ALSO: .Xr not separated by ". + "comma, but `$s->{sarest}'"); + } + $s->{saname} = $saname; + $s->{sasection} = $sasection; + $s->{sarest} = $sarest; + } + if (/^\.Rs(?:\s+|$)/o) { + if ($s->{sarest} ne "") { + $s->warning("SEE ALSO: Not necessary to separate". + " .Xr from .Rs by `$s->{sarest}'"); + } + $s->{sarest} = ""; + } + } + } + + if ($opt_f and /^\.Fn.*,.+/o) { + $s->warning("possible .Fn misuse: `$_'"); + } + if (OPENBSD) { + if ($opt_H and (/^(?:[<>])/o or /[^\\][<>]/o)) { + $s->warning("use \*(Lt \*(Gt (or .Aq) ", + "instead of < >: `$_'"); + } + } + if (NETBSD) { + if ($opt_H and (/^(?:[<>&])/o or /[^\\][<>&]/o)) { + $s->warning("use \*[Lt] \*[Gt] (or .Aq) \*[Am] ", + "instead of < > &: `$_'"); + } + } + + if ($opt_X) { + if (/\b(Free|Net|Open)BSD\b/o + and not /\b(?:www|ftp)\.(?:Free|Net|Open)BSD\.org\b/o + and not /\bOpenBSD\::.*3p\b/o + and not /\/pub\/OpenBSD\//o + and not /\@(?:Free|Net|Open)BSD\.(?i:org)\b/o) { + $s->warning("verbose mention of `$1BSD' instead of " + . "`$short{$1}': `$_'"); + } + if (/^\./o and (/Bx (Open)/o or /Bx (Free)/o or /Bx (Net)/o)) { + $s->warning("`.Bx $1' found -- use $short{$1} instead"); + } + } + if ($opt_o) { + if (/^\.Os\s+(.+)/o) { + $s->warning(".Os used with argument `$1'"); + } + } + + if ($opt_n) { + if (/^\.Nd.*\.$/o) { + $s->warning(".Nd ends with a dot: `$_'"); + } + } + if ($opt_p) { + if (/\w\w\.\s+[A-Z]/o) { + $s->warning("new sentence, new line: `$_'"); + } + if (/^\... .*[^\s][\.();,\[\]\{\}:]$/o + and not /\s\.\.\.$/o and not /\\&.$/o) { + $s->warning("punctuation in format string ", + "without space: `$_'"); + } + if (/^\./o and /Ns [\.();,\[\]\{\}:]/o) { + $s->warning("possible Ns abuse: `$_'"); + } + if (/(\w+)\(\)/o) { + $s->warning("use .Fn or .Xr for functions: `$1()'"); + } + } + if ($opt_x) { + if ($s->{mandoc_p}) { + my $destruct = $_; + $destruct =~ s/\\\&([\w\.])/$1/o; + if ($destruct =~ /^\.Xr\s+([\w\:\.\-\+\/]+)\s+($esections_re)(.*)/o) { + $s->debug("Xref to $1($2) found: `$_'"); + $s->verify_xref($1, $2, "", ""); + if ($3 =~ /^\S/o) { + $s->warning("No space after section number in Xref: `$_'"); + } + } elsif ($destruct =~ /^\.Xr/o) { + $s->warning("Weird Xref found: `$_'"); + } + } else { + my $destruct = $_; + $destruct =~ s/\\f.//go; + if ($destruct !~ /^\.\\\"/o) { + while ($destruct =~ s/([-\w.]+)\s*\(($esections_re)\)//o) { + $s->debug("possible Xref to $1($2) found: `$_'"); + $s->verify_xref($1, $2, "possible ", ": `$_'"); + # so that we have a chance to find more than one + # per line + $destruct =~ s/(\w+)\s*\(($sections_re)\)//o; + } + } + } + } + if ($opt_d) { + if (/^\.Dd/o and not /^\.Dd\s+$valid_date_re/o) { + $s->warning("Invalid date found: `$_'"); + } + } + + if ($opt_P) { + if (/^\.Bd\b.*-literal\b/o) { + $s->{inliteral} = 1; + } + if ($s->{inliteral} == 1) { + if (/^\.Ed\b/o) { + $s->{inliteral} = 0; + } + } elsif (/^$/o) { + $s->warning("Paragraph problem: empty line -- ", + "use .Pp for paragraphs"); + } + if ($s->{lastline} =~ /^\.Pp/o and /^(\.Ss|\.Pp)/o) { + $s->warning("Paragraph problem: $1 after .Pp"); + } + if (/^\.Pp/o and $s->{lastline} =~ /^(\.S[Ssh])/o) { + $s->warning("Paragraph problem: .Pp after $1"); + } + } + + # Check whether the list of possible errors for a function is + # sorted alphabetically. + # + if ($opt_e) { + # Error names should not be sorted across different lists. + # (see bind(2) for an example.) + # + /^\.Bl\s+/o and $s->{last_error_name} = ""; + + if ($s->{current_section_header} eq "ERRORS" and + /^\.It\s+Bq\s+Er\s+(E[\w_]+)$/o) { + my $current_error_name = $1; + + if ($s->{last_error_name} eq $current_error_name) { + $s->warning("Duplicate item for " + . "$current_error_name."); + } elsif ($current_error_name lt $s->{last_error_name}) { + $s->warning("$s->{last_error_name} and " + . "$current_error_name are not in " + . "alphabetical order."); + } + $s->{last_error_name} = $current_error_name; + } + } + + $s->{lastline} = $_; + $s->{all} .= "$_\n"; +} + +sub finish +{ + my ($s) = @_; + + if (NETBSD and not $s->{nxrcsidseen}) { + $s->warning("Missing RCS Id") if $opt_r; + } + if (OPENBSD and not $s->{oxrcsidseen}) { + $s->warning("Missing RCS Id") if $opt_r; + } + + if ($opt_P and $s->{lastline} =~ /^\.Pp/o) { + $s->warning("Paragraph problem: .Pp at EOF"); + } + + if ($opt_a and $s->{insa} > 0 and not $s->{sarest} eq "") { + $s->warning("unneeded characters at end of SEE ALSO: `$s->{sarest}'"); + } + +# if (not ($fn =~ /$section$/)) { +# $s->warning("section doesn't match (internal value: $section)"); +# } + if ($s->{mandoc_p} and $opt_S) { + foreach my $i (qw (NAME SYNOPSIS DESCRIPTION)) { + if (not ($s->{shseen}{$i})) { + $s->warning("missing $i section"); + } + } + } +} + +package main; + +sub handle_file +{ + my $parser = Parser->new($_[0]); + + while (my $_ = $parser->next_line) { + $parser->process_line($_); + } + + $parser->finish; + $parser->close; + if ($Parser::opt_F and $parser->{changes}) { + open OUT, ">$_[0].new" or + die "can't open output file `$_[0].new'"; + print OUT $parser->{all}; + close OUT; + system("mv -i $_[0].new $_[0]"); + } +} + +Parser->handle_options; +foreach my $file (@ARGV) { + handle_file($file); +} diff --git a/textproc/mdoclint/files/mdoclint.1 b/textproc/mdoclint/files/mdoclint.1 new file mode 100755 index 00000000000..0c51b88aaf8 --- /dev/null +++ b/textproc/mdoclint/files/mdoclint.1 @@ -0,0 +1,157 @@ +.\" $OpenBSD: mdoclint.1,v 1.5 2008/11/23 17:07:36 jmc Exp $ +.\" $NetBSD: mdoclint.1,v 1.1.1.1 2009/03/01 21:25:39 wiz Exp $ +.\" +.\" Copyright (c) 2001-2008 Thomas Klausner +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR, THOMAS KLAUSNER, +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd November 21, 2008 +.Dt MDOCLINT 1 +.Os +.Sh NAME +.Nm mdoclint +.Nd man page verifier +.Sh SYNOPSIS +.Nm +.Op Fl aDdeFfHhmnoPprSsvXx +.Ar +.Sh DESCRIPTION +.Nm +is a man page verifier. +It tries to automatically find as many common +errors that occur when writing man pages as possible. +If no flags are given, +.Fl aDdefHmnoPprSsXx +is assumed (that is, everything except +.Fl Fhv ) . +.Pp +The options are as follows: +.Bl -tag -width xxxx -compact +.It Fl a +Warn about some possible problems in the +.Sx SEE ALSO +section, like incorrect order (correct order: first by section +numbers, then by name), or incorrect or superfluous punctuation +between or after the cross-references. +.It Fl D +Warn about bad casing and architectures in the .Dt macro. +.It Fl d +Warn about bad date strings (in the .Dd macro). +.It Fl e +Warn about unsorted errors (for functions). +.It Fl F +Fix whitespace problems (see also +.Fl s ) . +.It Fl f +Warn about possible .Fn abuse; its arguments should be put in +.Sq \&" +separately, not together and separated by commas. +Those will be automatically added by mdoc. +.It Fl H +Show warnings for characters that might generate problems in +HTML output: +.Sq \*[Lt] , +.Sq \*[Gt] , +and +.Sq \*[Am] . +Replace a pair of angle quotes with the .Aq macro. +Otherwise, the replacements are +.Dq \e*[Lt] , +.Dq \e*[Gt] , +and +.Dq \e*[Am] . +.It Fl h +Display usage. +.It Fl m +Warn if man page is not in +.Xr mdoc 7 +format. +.It Fl n +Warn when the .Nd macro's argument ends in a dot, that is +.Sq \&. . +.It Fl o +Warn when the .Os macro has an argument (it shouldn't have one at +least in the base system, because on +.Nx +the current version is default). +.It Fl P +Warn about paragraph problems, like empty lines or .Pp macros before +section macros like .Ss and .Sh. +.It Fl p +Warn about possible punctuation problems at the end of macro arguments, +abuse of .Ns to get punctuation directly next to a word, +and sentences not starting on a new line. +.It Fl r +Warn about missing RCS Id. +.It Fl S +Warn about any unknown sections or about a section that comes in the +wrong order (see +.Xr mdoc 7 ) . +.It Fl s +Warn about superfluous whitespace at the end of line. +.It Fl v +Verbose output. +.It Fl X +Warn about explicit mentions of the words +.Dq FreeBSD , +.Dq NetBSD , +and +.Dq OpenBSD , +which should be replaced by .Fx, .Nx, and .Ox respectively. +Also notices occurrences of +.Dq \&.Bx Free , +.Dq \&.Bx Net , +and +.Dq \&.Bx Open , +for which the same applies. +.It Fl x +Warn about cross-references whose target is missing, cross-references +to itself, or plain bogus cross-references. +.Pp +For +.Dq .Xr name X , +the following files are checked: +.Pa /usr/share/man/manX/name.X , +.Pa /usr/share/man/manX/`uname -m`/name.X , +and +.Pa ./name.X . +.El +.Sh SEE ALSO +.Xr mdoc 7 , +.Xr mdoc.samples 7 +.Sh AUTHORS +.An Thomas Klausner +.Aq wiz@netbsd.org +.Sh BUGS +The +.Fl o +and +.Fl p +flags currently produce too many bogus warnings. +.Pp +The +.Fl x +flag sometimes erroneously warns about xrefs to man pages for +machine-dependent drivers that are not for the architecture +.Nm +is running on. |