Date: Wed, 26 Jul 1995 00:27:46 +0200 From: Wolfram Schneider <w@cs.tu-berlin.de> To: current@freebsd.org Subject: Manual page checker Message-ID: <199507252227.AAA06375@localhost.cs.tu-berlin.de>
next in thread | raw e-mail | index | archive | help
$ ./manck.pl /usr/share/man/man2/*
/usr/share/man/man2/execve.2.gz
No entry for `exit' in section 2 (mandir /usr/share/man)
/usr/share/man/cat3/exit.3.gz (source: /usr/share/man/man3/exit.3.gz)
/usr/share/man/man2/fsync.2.gz
No entry for `update' in section 8 (mandir /usr/share/man)
/usr/share/man/man2/getegid.2.gz
No entry for `setgid' in section 3 (mandir /usr/share/man)
/usr/share/man/cat2/setgid.2.gz (source: /usr/share/man/man2/setgid.2.gz)
[...]
/usr/share/man/man2/quotactl.2.gz
ufs/quota.h: include does not exist in: /usr/include /usr/local/include
[...]
$ ./manck.pl /usr/share/man/man1/tic.1.gz
/usr/share/man/man1/tic.1.gz
/usr/lib/terminfo: file does not exist
/usr/lib/terminfo/terminfo.src: file does not exist
No entry for `infocmp' in section 1M (mandir /usr/share/man)
No entry for `term' in section 4 (mandir /usr/share/man)
/usr/share/man/cat5/term.5.gz (source: /usr/share/man/man5/term.5.gz)
No entry for `termcap' in section 4 (mandir /usr/share/man)
/usr/share/man/cat3/termcap.3.gz (source: /usr/share/man/man3/termcap.3.gz)
No entry for `terminfo' in section 4 (mandir /usr/share/man)
/usr/share/man/cat5/terminfo.5.gz (source: /usr/share/man/man5/terminfo.5.gz)
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# manck.pl
# manck.1
#
echo x - manck.pl
sed 's/^X//' >manck.pl << 'END-of-manck.pl'
X:
Xeval "exec perl -S $0 $*"
X if $running_under_some_shell;
X
X#
X# Copyright (c) 1995 Wolfram Schneider <wosch@cs.tu-berlin.de>
X# All rights reserved. Alle Rechte vorbehalten.
X#
X# $Id: manck.pl,v 1.5 1995/07/25 22:21:05 w Exp w $
X#
X# manck - check manual pages
X
Xsub var {
X $ENV{'PATH'} = '/bin:/usr/bin';
X
X $path = '/bin:/sbin:/usr/bin:/usr/sbin';
X @man = ('/usr/bin/man', '-w');
X
X $manpath = '/usr/share/man';
X $incpath = '/usr/include:/usr/local/include';
X
X #$manpath = '/usr/tmp/man';
X
X $ext = '.gz';
X $zcat = 'gzcat';
X
X # 0: only errors 1: some more information 2: verbose
X $debug = 0;
X
X require "stat.pl";
X $| = 1;
X}
X
Xsub usage {
X
X warn <<EOF;
Xusage: manck [-d|-debug] [-d|-debug] [-h|-help] [-bin path]
X [-i|-include includepath] [-M mandir] [manpages ...]
XEOF
X exit 1;
X}
X
Xsub parse {
X local(*argv) = @_;
X
X while ($_ = $argv[0], /^-/) {
X shift @argv;
X last if /^--$/;
X if (/^--?(d|debug)$/) { $debug++ }
X elsif (/^--?(h|help|\?)$/) { &usage }
X elsif (/^--?(b|bin)$/) { exit(&bin($argv[0] || $path)); }
X elsif (/^-M$/) { $manpath = $argv[0]; shift @argv;
X $manpath =~ s=/+$==; }
X elsif (/^-r$/) {
X require "find.pl";
X eval 'sub wanted {
X $name =~ /^$manpath(\/man.*)?\/[^.\/]+\.[^\/]+$/ &&
X &manpage($name);
X }';
X $wanted = 1;
X #&find($manpath);
X }
X elsif (/^-i|-include$/) { $incpath = $argv[0]; shift @argv; }
X
X else { &usage }
X }
X
X @include = split(/:/, $incpath);
X
X # use absolute path
X if ($manpath !~ "^/") {
X $manpath = ($ENV{'PWD'} || `pwd`) . '/' . $manpath;
X $manpath =~ s/\n//g;
X }
X
X &find($manpath) if $wanted;
X}
X
X
X#
X# check if binaries in $path have their own manpages
X# use `man -w program'
X#
Xsub bin {
X local($path) = @_;
X local($dir);
X
X # dup
X open(SAVEOUT, ">&STDOUT");
X open(SAVEERR, ">&STDERR");
X
X # swap stdin and stdout
X # close stdout, redirect stderr to old stdout
X close STDOUT;
X open(STDERR, ">&SAVEOUT");
X
X foreach $dir (split(/:/, $path)) {
X warn "$dir\n";
X opendir(DIR, $dir) || die "opendir: $dir $!\n";
X foreach (readdir(DIR)) {
X next if $_ eq '.';
X next if $_ eq '..';
X
X system @man, $_; # call man(1)
X }
X closedir DIR;
X }
X
X # restore stdout
X open(STDOUT, ">&SAVEOUT");
X open(STDERR, ">&SAVEERR");
X}
X
X
X
X%sh = (
X'AUTHOR', 0,
X'AUTHORS', 0,
X'BUGS', 0,
X'CAVEATS', 0,
X'COMPATIBILITY', 0,
X'DESCRIPTION', 0,
X'DIAGNOSTICS', 0,
X'ENVIRONMENT', 0,
X'ERRORS', 0,
X'EXAMPLE', 0,
X'EXAMPLES', 0,
X'FILES', '&files',
X'HISTORY', 0,
X'NAME', 0,
X'NOTES', 0,
X'OPTIONS', 0,
X'RETURN VALUE', 0,
X'RETURN VALUES', 0,
X'SEE ALSO', '&see_also',
X'STANDARDS', 0,
X'SYNOPSIS', '&synopsis',
X );
X
X#
X# parse single manpage
X# and analyze
X#
Xsub manpage {
X local($file) = @_;
X local(@stat, $do, @list);
X
X # cache
X @stat = stat($file);
X if (defined $cached_file{$stat[$ST_DEV],$stat[$ST_INO]}) {
X &err("$file already visit: " .
X "$cached_file{$stat[$ST_DEV],$stat[$ST_INO]}\n") if $debug > 1;
X return 1;
X }
X $cached_file{$stat[$ST_DEV],$stat[$ST_INO]} = $file;
X
X if ($file =~ /$ext$/o) {
X $file = "$zcat $file |";
X }
X open(MANPAGE, "$file") || do {
X warn "open: $file $!\n";
X return 0;
X };
X
X
X while(<MANPAGE>) {
X next if /^\.\\\"/o; #" comment
X
X if (/^\.S[hH]\s+/o) { # .SH or .Sh
X # start action $do with following lines (until next .SH)
X eval $do;
X
X # reset action and array
X $do = ''; @list = ();
X
X $name = $_;
X $name =~ s/^\.S[hH]\s+\"?//; #"
X $name =~ s/\"?\s*$//; #"
X
X if ($sh{$name}) {
X &err("parse $name\n") if $debug > 0;
X $do = $sh{$name}; # save action
X
X } elsif (defined $sh{$name}) {
X &err("defined $name\n") if $debug > 1;
X } else {
X &err("undef $name\n") if $debug > 0;
X }
X } elsif ($do) {
X # \fBcurs_kernel\fR
X s=\\f[BRPI]==g;
X
X push(@list, $_);
X }
X }
X eval $do; # last .SH in file
X close MANPAGE;
X}
X
X#
X# locate manpage,
X# may be from cache or with stat
X#
Xsub find_manpage {
X local($manpage, $section) = @_;
X
X # failed from cache
X if (defined $cached_mp{$manpage,$section} &&
X !$cached_mp{$manpage,$section}) {
X &err("man $section $manpage failed\n");
X return 0;
X }
X
X # cache
X &err("CACHE $manpage\n")
X if $debug > 2 && $cached_mp{$manpage,$section};
X return 1
X if $cached_mp{$manpage,$section};
X
X $cached_mp{$manpage,$section} = 1;
X
X # test if manpage exist
X if (-e "$manpath/man$section/$manpage.$section" ||
X -e "$manpath/man$section/$manpage.$section$ext") {
X return 1;
X }
X
X # may be wrong section, eg. '3X' instead '3'
X if ($section =~ /^(.).$/ && -d "$manpath/man$1" &&
X (-e "$manpath/man$1/$manpage.$1" ||
X -e "$manpath/man$1/$manpage.$1$ext")) {
X return 1 if $debug < 1;
X &err("manpage `$manpage' is in section `$1' and not $section\n");
X }
X
X # try with man(1)
X print "@man $section $manpage\n" if $debug > 1;
X open(SAVEERR, ">&STDERR"); close STDERR;
X system @man, $section, $manpage; # call man(1) with section
X open(STDERR, ">&SAVEERR");
X return 1 unless $?;
X &err("No entry for `$manpage' in section $section (mandir $manpath)\n");
X
X # second try with man(1), without explicit section
X print "@man $manpage\n" if $debug > 1;
X open(SAVEERR, ">&STDERR"); close STDERR;
X system @man, $manpage; # call man(1) whithout section
X open(STDERR, ">&SAVEERR");
X return 1 unless $?;
X
X # manpage not found
X return 0;
X}
X
X# print error messages
Xsub err {
X if (!$cache_err{$file}) {
X local($f) = $file; $f =~ s/^$zcat\s//; $f =~ s/\s+\|$//;
X print "$f\n";
X $cache_err{$file} = 1;
X }
X print @_;
X}
X
X#
X# .SH SEE ALSO
X# test if manpages exist
X#
Xsub see_also {
X foreach (@list) {
X s/\s+$//; # strip ending blanks
X s/\"//g; # remove '"'
X
X #if (/^$/) {
X # &err("stop SEE ALSO empty line\n") if $debug > 1;
X # return;
X #}
X
X foreach (split(/,/)) {
X s/^\s+//;
X
X # BSD
X if (/^\.(Xr|Fn)\s+(\S+)\s+(\S+)/o) {
X &find_manpage($2, $3) && $debug > 1 &&
X &err("found manpage: $3 $2\n");
X
X }
X # GNU
X elsif (/^(\.[BI]R\s)?\s*(\S+)\s*\(\s*(\S+)\s*\)/o) {
X &find_manpage($2, $3) && $debug > 1 &&
X &err("fond manpage: $3 $2\n");
X }
X # Doku follow, break
X elsif (/^\.(sp|Rs|LP|br|TP|RB|PP|Pp|%)/o ||
X /^RFC/o) {
X &err("stop SEE ALSO: $_\n") if $debug > 1;
X return;
X }
X
X # Hm
X elsif (/^\.(Bl|It)/) {
X &err("skip: `$_'\n") if $debug > 0;
X }
X
X # Garbage
X else {
X &err("unknown: `$_'\n") if $debug > 0;
X }
X }
X }
X}
X
X#
X# .SH FILES
X# test if files exist
X#
Xsub files {
X foreach (@list) {
X next if /^\.(Bl|El|\\\")/;
X
X # .TP \w'/etc/manpath.config'u+2n
X s/\s\\w'([^\']+)'.*/ $1/; #"
X
X if (s=.*\s(\S+)\s*$=$1= && /\//) {
X s/\s+$//;
X s/[\s\'\"].*//; # "
X
X next unless $_;
X next if $debug < 1 && !/^\//;
X
X &err("test -e $_\n") if $debug > 1;
X if (! -e $_) {
X # spool/temp files
X return 1 if $debug < 1 && /[X?*\]\#]$/o;
X return 1 if $debug < 1 && /[\$\[\?]/;
X
X &err("$_: file does not exist\n");
X }
X }
X }
X}
X
X#
X# .SH SYNOPSIS
X# test for include files
X#
Xsub synopsis {
X local($inc);
X
X foreach (@list) {
X if (/\#include\s+[<"](\S+)[>"]/) { #
X if ($cached_file{$1}) {
X &err("CACHED file: $1\n") if $debug > 2;
X next;
X }
X
X $cached_file{$1} = 1;
X
X &err("$1: include does not exist in: @include\n")
X unless &include_test($1);
X }
X }
X}
X
Xsub include_test {
X foreach $inc (@include) {
X &err("test -f $inc/$1\n") if $debug > 1;
X return 1
X if -f "$inc/$1";
X }
X return 0;
X}
X
X
X##
X## Main
X##
X# read enviroment
X&var;
X
X# check /usr/share/man if no arguments given
Xpush(@ARGV, '-M', $manpath) if $#ARGV < 0;
X
X# parse
X&parse(*ARGV);
X&usage if $#ARGV < 0 && !$wanted;
X
X# check single manpages
Xforeach (@ARGV) { &manpage($_); }
X
END-of-manck.pl
echo x - manck.1
sed 's/^X//' >manck.1 << 'END-of-manck.1'
X.\"
X.\" Copyright (c) 1995 Wolfram Schneider <wosch@cs.tu-berlin.de>
X.\" All rights reserved. Alle Rechte vorbehalten.
X.\"
X.\" $Id: manck.1,v 1.2 1995/07/25 22:03:33 w Exp $
X.\"
X.\" manck - check manual pages
X.Dd July 25, 1995
X.Os FreeBSD 2.2
X.Dt MANCK 1
X.Sh NAME
X.Nm manck
X.Nd check manual pages
X.Sh SYNOPSIS
X.Nm manck
X.Op Fl d
X.Op Fl h \&| Ns Fl \&?
X.Op Fl help
X.Op Fl bin Ar path
X.Op Fl i \&| Ns Fl include Ar includepath
X.Op Fl M Ar mandir
X.Op Ar manpages ...
X.Sh DESCRIPTION
X.Nm Manck
Xcheck manual pages. Currently supported section FILES, SEE ALSO, and
XSYNOPSIS.
X
X.Pp
XThe options are as follows:
X
X.Bl -tag -width 10n -offset indent
X.It Fl d \&| Ns Fl debug
XBe more verbose about what will be done. For a single
X.Fl d
Xoption, print more errors and warnings. If the option
X.Fl d
Xhas been specified at least twice, print verbose errors and warnings.
XOne
X.Fl d
Xis recommend for carefully review.
X
X.It Fl h \&| Ns Fl \&?
X.It Fl help
XGive a help on the command usage and exit.
X
X.It Fl i \&| Ns Fl include Ar includepath
XPath where include files located.
XColons in
X.Ar includepath
Xallowed. Default /usr/include:/usr/local/include.
X
X.It Fl M Ar mandir
XUse
X.Ar mandir
Xas directory, where manpages located.
X.It Fl bin Ar path
XLook for binaries in
X.Ar path
Xwhithout manpage. Colons in
X.Ar path
Xallowed. Default /bin:/sbin:/usr/bin:/usr/sbin
X
X.It Fl r
XTraverse recursive mandir (default /usr/share/man).
X.El
X
X.Sh EXAMPLES
X.Pp
X.Dl $ manck -bin
X.Pp
XTest if all binaries in /bin:/sbin:/usr/bin:/usr/sbin have their own
Xmanpages
X
X.Pp
X.Dl $ manck -M /usr/share/man /usr/share/man/man1/z*
X.Pp
XCheck all manpages with leading 'z' in /usr/share/man/man1.
X
X.Pp
X.Dl $ manck -r
X.Pp
XCheck recursive all manpages in /usr/share/man.
X
X.Sh FILES
X.Bl -tag -width /usr/share/man -compact
X.Pa /usr/share/man
Xdirectory for manual pages.
X.El
X
X.Sh ENVIROMENT
X.Bl -tag -width ENVIROMENT
X.Pa MANPATH
Xenviroment variable for man(1).
X
X.El
X
X.Sh SEE ALSO
X.Xr man 1 ,
X.Xr hier 7 .
X
X.Sh HISTORY
X.Nm manck
Xappeared in late July 1995.
X
X.Sh AUTHOR
XWolfram Schneider <wosch@cs.tu-berlin.de>
X
END-of-manck.1
exit
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199507252227.AAA06375>
