mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
519 lines
12 KiB
Awk
519 lines
12 KiB
Awk
# Usage: cd $PLAN9; awk -f dist/checkman.awk man?/*.?
|
|
#
|
|
# Checks:
|
|
# - .TH is first line, and has proper name section number
|
|
# - sections are in order NAME, SYNOPSIS, DESCRIPTION, EXAMPLES,
|
|
# FILES, SOURCE, SEE ALSO, DIAGNOSTICS, BUGS
|
|
# - there's a manual page for each cross-referenced page
|
|
|
|
BEGIN {
|
|
|
|
# .SH sections should come in the following order
|
|
|
|
Weight["NAME"] = 1
|
|
Weight["SYNOPSIS"] = 2
|
|
Weight["DESCRIPTION"] = 4
|
|
Weight["EXAMPLE"] = 8
|
|
Weight["EXAMPLES"] = 16
|
|
Weight["FILES"] = 32
|
|
Weight["SOURCE"] = 64
|
|
Weight["SEE ALSO"] = 128
|
|
Weight["DIAGNOSTICS"] = 256
|
|
Weight["SYSTEM CALLS"] = 512
|
|
Weight["BUGS"] = 1024
|
|
|
|
Skipdirs["CVS"] = 1
|
|
|
|
# allow references to pages provded
|
|
# by the underlying Unix system
|
|
Omitman["awk(1)"] = 1
|
|
Omitman["bash(1)"] = 1
|
|
Omitman["chmod(1)"] = 1
|
|
Omitman["compress(1)"] = 1
|
|
Omitman["cp(1)"] = 1
|
|
Omitman["egrep(1)"] = 1
|
|
Omitman["gs(1)"] = 1
|
|
Omitman["gv(1)"] = 1
|
|
Omitman["lex(1)"] = 1
|
|
Omitman["lp(1)"] = 1
|
|
Omitman["lpr(1)"] = 1
|
|
Omitman["mail(1)"] = 1
|
|
Omitman["make(1)"] = 1
|
|
Omitman["nm(1)"] = 1
|
|
Omitman["prof(1)"] = 1
|
|
Omitman["pwd(1)"] = 1
|
|
Omitman["qiv(1)"] = 1
|
|
Omitman["sftp(1)"] = 1
|
|
Omitman["sh(1)"] = 1
|
|
Omitman["ssh(1)"] = 1
|
|
Omitman["stty(1)"] = 1
|
|
Omitman["tex(1)"] = 1
|
|
Omitman["unutf(1)"] = 1
|
|
Omitman["vnc(1)"] = 1
|
|
Omitman["xterm(1)"] = 1
|
|
|
|
Omitman["access(2)"] = 1
|
|
Omitman["brk(2)"] = 1
|
|
Omitman["chdir(2)"] = 1
|
|
Omitman["close(2)"] = 1
|
|
Omitman["connect(2)"] = 1
|
|
Omitman["fork(2)"] = 1
|
|
Omitman["gethostname(2)"] = 1
|
|
Omitman["getpid(2)"] = 1
|
|
Omitman["getuid(2)"] = 1
|
|
Omitman["open(2)"] = 1
|
|
Omitman["pipe(2)"] = 1
|
|
Omitman["ptrace(2)"] = 1
|
|
Omitman["rmdir(2)"] = 1
|
|
Omitman["send(2)"] = 1
|
|
Omitman["signal(2)"] = 1
|
|
Omitman["sigprocmask(2)"] = 1
|
|
Omitman["socketpair(2)"] = 1
|
|
Omitman["unlink(2)"] = 1
|
|
|
|
Omitman["abort(3)"] = 1
|
|
Omitman["assert(3)"] = 1
|
|
Omitman["fprintf(3)"] = 1
|
|
Omitman["fscanf(3)"] = 1
|
|
Omitman["fopen(3)"] = 1
|
|
Omitman["isalpha(3)"] = 1
|
|
Omitman["malloc(3)"] = 1
|
|
Omitman["perror(3)"] = 1
|
|
Omitman["remove(3)"] = 1
|
|
Omitman["sin(3)"] = 1
|
|
Omitman["strerror(3)"] = 1
|
|
|
|
Omitman["core(5)"] = 1
|
|
Omitman["passwd(5)"] = 1
|
|
|
|
Omitman["signal(7)"] = 1
|
|
|
|
Omitman["cron(8)"] = 1
|
|
Omitman["mount(8)"] = 1
|
|
|
|
# don't need documentation for these in bin
|
|
Omitted[".cvsignore"] = 1
|
|
Omitted["Getdir"] = 1
|
|
Omitted["Irc"] = 1
|
|
Omitted["Juke"] = 1
|
|
Omitted["ajuke"] = 1
|
|
Omitted["goodmk"] = 1
|
|
Omitted["jukefmt"] = 1
|
|
Omitted["jukeget"] = 1
|
|
Omitted["jukeindex"] = 1
|
|
Omitted["jukeinfo"] = 1
|
|
Omitted["jukeplay"] = 1
|
|
Omitted["jukeput"] = 1
|
|
Omitted["jukesearch"] = 1
|
|
Omitted["jukesongfile"] = 1
|
|
Omitted["m4ainfo"] = 1
|
|
Omitted["mp3info"] = 1
|
|
Omitted["notes"] = 1
|
|
Omitted["tcolors"] = 1
|
|
Omitted["tref"] = 1
|
|
Omitted["unutf"] = 1
|
|
Omitted["volume"] = 1
|
|
Omitted["vtdump"] = 1
|
|
Omitted["netfilelib.rc"] = 1
|
|
|
|
# not for users
|
|
Omittedlib["creadimage"] = 1
|
|
Omittedlib["pixelbits"] = 1
|
|
Omittedlib["bouncemouse"] = 1
|
|
Omittedlib["main"] = 1 # in libthread
|
|
|
|
Omittedlib["opasstokey"] = 1 # in libauthsrv
|
|
|
|
# functions provided for -lthread_db
|
|
Omittedlib["ps_get_thread_area"] = 1
|
|
Omittedlib["ps_getpid"] = 1
|
|
Omittedlib["ps_lcontinue"] = 1
|
|
Omittedlib["ps_lgetfpregs"] = 1
|
|
Omittedlib["ps_lgetregs"] = 1
|
|
Omittedlib["ps_lsetfpregs"] = 1
|
|
Omittedlib["ps_lsetregs"] = 1
|
|
Omittedlib["ps_lstop"] = 1
|
|
Omittedlib["ps_pcontinue"] = 1
|
|
Omittedlib["ps_pdread"] = 1
|
|
Omittedlib["ps_pdwrite"] = 1
|
|
Omittedlib["ps_pglobal_lookup"] = 1
|
|
Omittedlib["ps_pstop"] = 1
|
|
Omittedlib["ps_ptread"] = 1
|
|
Omittedlib["ps_ptwrite"] = 1
|
|
|
|
# libmach includes a small dwarf and elf library
|
|
Omittedlib["corecmdfreebsd386"] = 1
|
|
Omittedlib["corecmdlinux386"] = 1
|
|
Omittedlib["coreregsfreebsd386"] = 1
|
|
Omittedlib["coreregslinux386"] = 1
|
|
Omittedlib["coreregsmachopower"] = 1
|
|
Omittedlib["crackelf"] = 1
|
|
Omittedlib["crackmacho"] = 1
|
|
Omittedlib["dwarfaddrtounit"] = 1
|
|
Omittedlib["dwarfclose"] = 1
|
|
Omittedlib["dwarfenum"] = 1
|
|
Omittedlib["dwarfenumunit"] = 1
|
|
Omittedlib["dwarfget1"] = 1
|
|
Omittedlib["dwarfget128"] = 1
|
|
Omittedlib["dwarfget128s"] = 1
|
|
Omittedlib["dwarfget2"] = 1
|
|
Omittedlib["dwarfget4"] = 1
|
|
Omittedlib["dwarfget8"] = 1
|
|
Omittedlib["dwarfgetabbrev"] = 1
|
|
Omittedlib["dwarfgetaddr"] = 1
|
|
Omittedlib["dwarfgetn"] = 1
|
|
Omittedlib["dwarfgetnref"] = 1
|
|
Omittedlib["dwarfgetstring"] = 1
|
|
Omittedlib["dwarflookupfn"] = 1
|
|
Omittedlib["dwarflookupname"] = 1
|
|
Omittedlib["dwarflookupnameinunit"] = 1
|
|
Omittedlib["dwarflookupsubname"] = 1
|
|
Omittedlib["dwarflookuptag"] = 1
|
|
Omittedlib["dwarfnextsym"] = 1
|
|
Omittedlib["dwarfnextsymat"] = 1
|
|
Omittedlib["dwarfopen"] = 1
|
|
Omittedlib["dwarfpctoline"] = 1
|
|
Omittedlib["dwarfseeksym"] = 1
|
|
Omittedlib["dwarfskip"] = 1
|
|
Omittedlib["dwarfunwind"] = 1
|
|
Omittedlib["elfclose"] = 1
|
|
Omittedlib["elfdl386mapdl"] = 1
|
|
Omittedlib["elfinit"] = 1
|
|
Omittedlib["elfmachine"] = 1
|
|
Omittedlib["elfmap"] = 1
|
|
Omittedlib["elfopen"] = 1
|
|
Omittedlib["elfsection"] = 1
|
|
Omittedlib["elfsym"] = 1
|
|
Omittedlib["elfsymlookup"] = 1
|
|
Omittedlib["elftype"] = 1
|
|
Omittedlib["machoclose"] = 1
|
|
Omittedlib["machoinit"] = 1
|
|
Omittedlib["machoopen"] = 1
|
|
Omittedlib["stabsym"] = 1
|
|
Omittedlib["symdwarf"] = 1
|
|
Omittedlib["symelf"] = 1
|
|
Omittedlib["symmacho"] = 1
|
|
Omittedlib["symstabs"] = 1
|
|
Omittedlib["elfcorelinux386"] = 1
|
|
Omittedlib["linux2ureg386"] = 1
|
|
Omittedlib["ureg2linux386"] = 1
|
|
Omittedlib["coreregs"] = 1 # haven't documented mach yet
|
|
Omittedlib["regdesc"] = 1
|
|
|
|
Omittedlib["auth_attr"] = 1 # not happy about this
|
|
|
|
Omittedlib["ndbnew"] = 1 # private to library
|
|
Omittedlib["ndbsetval"] = 1
|
|
|
|
Renamelib["chanalt"] = "alt"
|
|
Renamelib["channbrecv"] = "nbrecv"
|
|
Renamelib["channbrecvp"] = "nbrecvp"
|
|
Renamelib["channbrecvul"] = "nbrecvul"
|
|
Renamelib["channbsend"] = "nbsend"
|
|
Renamelib["channbsendp"] = "nbsendp"
|
|
Renamelib["channbsendul"] = "nbsendul"
|
|
Renamelib["chanrecv"] = "recv"
|
|
Renamelib["chanrecvp"] = "recvp"
|
|
Renamelib["chanrecvul"] = "recvul"
|
|
Renamelib["chansend"] = "send"
|
|
Renamelib["chansendp"] = "sendp"
|
|
Renamelib["chansendul"] = "sendul"
|
|
Renamelib["threadyield"] = "yield"
|
|
|
|
Renamelib["fmtcharstod"] = "charstod"
|
|
Renamelib["fmtstrtod"] = "strtod"
|
|
|
|
Renamelib["regcomp9"] = "regcomp"
|
|
Renamelib["regcomplit9"] = "regcomplit"
|
|
Renamelib["regcompnl9"] = "regcompnl"
|
|
Renamelib["regerror9"] = "regerror"
|
|
Renamelib["regexec9"] = "regexec"
|
|
Renamelib["regsub9"] = "regsub"
|
|
Renamelib["rregexec9"] = "rregexec"
|
|
Renamelib["rregsub9"] = "rregsub"
|
|
|
|
lastline = "XXX";
|
|
lastfile = FILENAME;
|
|
}
|
|
|
|
func getnmlist(lib, cmd)
|
|
{
|
|
cmd = "nm -g " lib
|
|
while (cmd | getline) {
|
|
if (($2 == "T" || $2 == "L") && $3 !~ "^_"){
|
|
sym = $3
|
|
sub("^p9", "", sym)
|
|
if(sym in Renamelib)
|
|
List[Renamelib[sym]] = lib " as " sym
|
|
else
|
|
List[sym] = lib
|
|
}
|
|
}
|
|
close(cmd)
|
|
}
|
|
|
|
|
|
func getindex(dir, fname)
|
|
{
|
|
fname = dir "/INDEX"
|
|
while ((getline < fname) > 0)
|
|
Index[$1] = dir
|
|
close(fname)
|
|
}
|
|
|
|
func getbinlist(dir, cmd, subdirs, nsd)
|
|
{
|
|
cmd = "ls -p -l " dir
|
|
nsd = 0
|
|
while (cmd | getline) {
|
|
if ($1 ~ /^d/) {
|
|
if (!($10 in Skipdirs))
|
|
subdirs[++nsd] = $10
|
|
} else if ($10 !~ "^_")
|
|
List[$10] = dir
|
|
}
|
|
for ( ; nsd > 0 ; nsd--)
|
|
getbinlist(dir "/" subdirs[nsd])
|
|
close(cmd)
|
|
}
|
|
|
|
func clearindex( i)
|
|
{
|
|
for (i in Index)
|
|
delete Index[i]
|
|
}
|
|
|
|
func clearlist( i)
|
|
{
|
|
for (i in List)
|
|
delete List[i]
|
|
}
|
|
|
|
|
|
FNR==1 {
|
|
if(lastline == ""){
|
|
# screws up troff headers
|
|
print lastfile ":$ is a blank line"
|
|
}
|
|
|
|
n = length(FILENAME)
|
|
nam = FILENAME
|
|
if(nam ~ /\.html$/)
|
|
next
|
|
if(nam !~ /^man\/man(.*)\/(.*)\.(.*)$/){
|
|
print "nam", nam, "not of form [0-9][0-9]?/*"
|
|
next
|
|
}
|
|
nam = substr(nam, 8)
|
|
gsub("[/.]", " ", nam);
|
|
n = split(nam, a)
|
|
sec = a[1]
|
|
name = a[2]
|
|
section = a[3]
|
|
if($1 != ".TH" || NF != 3)
|
|
print "First line of", FILENAME, "not a proper .TH"
|
|
else if(($2 != toupper(name) || substr($3, 1, length(sec)) != sec || $3 != toupper(section)) \
|
|
&& ($2!="INTRO" || name!="0intro") \
|
|
&& (name !~ /^9/ || $2!=toupper(substr(name, 2)))){
|
|
print ".TH of", FILENAME, "doesn't match filename"
|
|
}else
|
|
Pages[tolower($2) "(" tolower($3) ")"] = 1
|
|
Sh = 0
|
|
}
|
|
|
|
{ lastline=$0; lastfile=FILENAME; }
|
|
|
|
$1 == ".SH" {
|
|
if(inex)
|
|
print "Unterminated .EX in", FILENAME, ":", $0
|
|
inex = 0;
|
|
if (substr($2, 1, 1) == "\"") {
|
|
if (NF == 2) {
|
|
print "Unneeded quote in", FILENAME, ":", $0
|
|
$2 = substr($2, 2, length($2)-2)
|
|
} else if (NF == 3) {
|
|
$2 = substr($2, 2) substr($3, 1, length($3)-1)
|
|
NF = 2
|
|
}
|
|
}
|
|
if(Sh == 0 && $2 != "NAME")
|
|
print FILENAME, "has no .SH NAME"
|
|
w = Weight[$2]
|
|
if (w) {
|
|
if (w < Sh)
|
|
print "Heading", $2, "out of order in", FILENAME
|
|
Sh += w
|
|
}
|
|
sh = $2
|
|
}
|
|
|
|
$1 == ".EX" {
|
|
if(inex)
|
|
print "Nested .EX in", FILENAME ":" FNR, ":", $0
|
|
inex = 1
|
|
}
|
|
|
|
$1 == ".EE" {
|
|
if(!inex)
|
|
print "Bad .EE in", FILENAME ":" FNR ":", $0
|
|
inex = 0;
|
|
}
|
|
|
|
$1 == ".TF" {
|
|
smallspace = 1
|
|
}
|
|
|
|
$1 == ".PD" || $1 == ".SH" || $1 == ".SS" || $1 == ".TH" {
|
|
smallspace = 0
|
|
}
|
|
|
|
$1 == ".RE" {
|
|
lastre = 1
|
|
}
|
|
|
|
$1 == ".PP" {
|
|
if(smallspace && !lastre)
|
|
print "Possible missing .PD at " FILENAME ":" FNR
|
|
smallspace = 0
|
|
}
|
|
|
|
$1 != ".RE" {
|
|
lastre = 0
|
|
}
|
|
|
|
sh == "BUGS" && $1 == ".br" {
|
|
print FILENAME ":" FNR ": .br in BUGS"
|
|
}
|
|
|
|
sh == "SOURCE" && $1 ~ /^\\\*9\// {
|
|
s = ENVIRON["PLAN9"] substr($1, 4)
|
|
Sources[s] = 1
|
|
}
|
|
|
|
sh == "SOURCE" && $2 ~ /^\\\*9\// {
|
|
s = ENVIRON["PLAN9"] substr($2, 4)
|
|
Sources[s] = 1
|
|
}
|
|
|
|
sh == "SOURCE" && $1 ~ /^\// {
|
|
Sources[$1] = 1
|
|
}
|
|
|
|
sh == "SOURCE" && $2 ~ /^\// {
|
|
Sources[$2] = 1
|
|
}
|
|
|
|
$0 ~ /^\.[A-Z].*\([1-9]\)/ {
|
|
if ($1 == ".IR" && $3 ~ /\([0-9]\)/) {
|
|
name = $2
|
|
section = $3
|
|
}else if ($1 == ".RI" && $2 == "(" && $4 ~ /\([0-9]\)/) {
|
|
name = $3
|
|
section = $4
|
|
}else if ($1 == ".IR" && $3 ~ /9.\([0-9]\)/) {
|
|
name = $2
|
|
section = "9"
|
|
}else if ($1 == ".RI" && $2 == "(" && $4 ~ /9.\([0-9]\)/) {
|
|
name = $3
|
|
section = "9"
|
|
} else {
|
|
if ($1 == ".HR" && $3 == "\"Section")
|
|
next;
|
|
print "Possible bad cross-reference format in", FILENAME ":" FNR
|
|
print $0
|
|
next
|
|
}
|
|
gsub(/[^0-9]/, "", section)
|
|
Refs[toupper(name) "(" section ")"]++
|
|
}
|
|
|
|
END {
|
|
if(lastline == ""){
|
|
print lastfile ":$ is a blank line"
|
|
}
|
|
|
|
print "Checking Source References"
|
|
cmd = "xargs -n 100 ls -d 2>&1 >/dev/null | sed 's/^ls: / /; s/: .*//'"
|
|
for (i in Sources) {
|
|
print i |cmd
|
|
}
|
|
close(cmd)
|
|
print ""
|
|
print "Checking Cross-Referenced Pages"
|
|
for (i in Refs) {
|
|
if (!(tolower(i) in Pages) && !(tolower(i) in Omitman)){
|
|
b = tolower(i)
|
|
gsub("\\(", " \\(", b)
|
|
gsub("\\)", "\\)", b)
|
|
split(tolower(i), a, "/")
|
|
print "egrep -in '^\\.IR.*" b "' $PLAN9/man/man*/* # Need " tolower(i) |"sort"
|
|
}
|
|
}
|
|
close("sort")
|
|
print ""
|
|
print "Checking commands"
|
|
getindex("man/man1")
|
|
getindex("man/man4")
|
|
getindex("man/man7")
|
|
getindex("man/man8")
|
|
getbinlist("bin")
|
|
for (i in List) {
|
|
if (!(i in Index) && !(i in Omitted))
|
|
print "Need", i, "(in " List[i] ")" |"sort"
|
|
}
|
|
close("sort")
|
|
print ""
|
|
for (i in List) {
|
|
if (!(i in Index) && (i in Omitted))
|
|
print "Omit", i, "(in " List[i] ")" |"sort"
|
|
}
|
|
close("sort")
|
|
clearindex()
|
|
clearlist()
|
|
print ""
|
|
print "Checking libraries"
|
|
getindex("man/man3")
|
|
getnmlist("lib/lib9.a")
|
|
getnmlist("lib/lib9p.a")
|
|
getnmlist("lib/lib9pclient.a")
|
|
getnmlist("lib/libString.a")
|
|
getnmlist("lib/libauth.a")
|
|
getnmlist("lib/libauthsrv.a")
|
|
getnmlist("lib/libbin.a")
|
|
getnmlist("lib/libbio.a")
|
|
getnmlist("lib/libcomplete.a")
|
|
# getnmlist("lib/libcontrol.a")
|
|
getnmlist("lib/libdisk.a")
|
|
getnmlist("lib/libdraw.a")
|
|
getnmlist("lib/libflate.a")
|
|
getnmlist("lib/libframe.a")
|
|
getnmlist("lib/libgeometry.a")
|
|
getnmlist("lib/libhtml.a")
|
|
# getnmlist("lib/libhttpd.a")
|
|
getnmlist("lib/libip.a")
|
|
getnmlist("lib/libmach.a")
|
|
# getnmlist("lib/libmemdraw.a")
|
|
# getnmlist("lib/libmemlayer.a")
|
|
getnmlist("lib/libmp.a")
|
|
getnmlist("lib/libmux.a")
|
|
getnmlist("lib/libndb.a")
|
|
getnmlist("lib/libplumb.a")
|
|
getnmlist("lib/libregexp9.a")
|
|
getnmlist("lib/libsec.a")
|
|
getnmlist("lib/libthread.a")
|
|
# getnmlist("lib/libventi.a")
|
|
for (i in List) {
|
|
if (!(i in Index) && !(i in Omittedlib))
|
|
print "Need", List[i], i |"sort"
|
|
# print "Need", i, "(in " List[i] ")" |"sort"
|
|
}
|
|
close("sort")
|
|
print ""
|
|
for (i in List) {
|
|
if (!(i in Index) && (i in Omittedlib))
|
|
print "Omit", List[i], i |"sort"
|
|
# print "Omit", i, "(in " List[i] ")" |"sort"
|
|
}
|
|
close("sort")
|
|
}
|
|
|