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>