1# Usage: awk -f checkman.awk man?/*.? 2# 3# Checks: 4# - .TH is first line, and has proper name section number 5# - sections are in order NAME, SYNOPSIS, DESCRIPTION, EXAMPLES, 6# FILES, SOURCE, SEE ALSO, DIAGNOSTICS, BUGS 7# - there's a manual page for each cross-referenced page 8 9BEGIN { 10 11# .SH sections should come in the following order 12 13 Weight["NAME"] = 1 14 Weight["SYNOPSIS"] = 2 15 Weight["DESCRIPTION"] = 4 16 Weight["EXAMPLE"] = 8 17 Weight["EXAMPLES"] = 16 18 Weight["FILES"] = 32 19 Weight["SOURCE"] = 64 20 Weight["SEE ALSO"] = 128 21 Weight["DIAGNOSTICS"] = 256 22 Weight["SYSTEM CALLS"] = 512 23 Weight["BUGS"] = 1024 24} 25 26FNR==1 { 27 n = length(FILENAME) 28 seclen = 0 29 if (substr(FILENAME, 2, 1) == "/") 30 seclen = 1 31 else if (substr(FILENAME, 3, 1) == "/") 32 seclen = 2 33 if(seclen == 0) 34 print "FILENAME", FILENAME, "not of form [0-9][0-9]?/*" 35 else if(!(substr(FILENAME, seclen+2, n-seclen-1) ~ /^[A-Z]+$/)){ 36 section = substr(FILENAME, 1, seclen) 37 name = substr(FILENAME, seclen+2, n-seclen-1) 38 if($1 != ".TH" || NF != 3) 39 print "First line of", FILENAME, "not a proper .TH" 40 else if($2 != toupper(name) || substr($3, 1, seclen) != section){ 41 if($2!="INTRO" || name!="0intro") 42 print ".TH of", FILENAME, "doesn't match filename" 43 }else 44 Pages[section "/" $2] = 1 45 } 46 Sh = 0 47 } 48 49$1 == ".SH" { 50 if(inex) 51 print "Unterminated .EX in", FILENAME, ":", $0 52 inex = 0; 53 if (substr($2, 1, 1) == "\"") { 54 if (NF == 2) { 55 print "Unneeded quote in", FILENAME, ":", $0 56 $2 = substr($2, 2, length($2)-2) 57 } else if (NF == 3) { 58 $2 = substr($2, 2) substr($3, 1, length($3)-1) 59 NF = 2 60 } 61 } 62 w = Weight[$2] 63 if (w) { 64 if (w < Sh) 65 print "Heading", $2, "out of order in", FILENAME 66 Sh += w 67 } 68} 69 70$1 == ".EX" { 71 if(inex) 72 print "Nested .EX in", FILENAME, ":", $0 73 inex = 1 74} 75 76$1 == ".EE" { 77 if(!inex) 78 print "Bad .EE in", FILENAME, ":", $0 79 inex = 0; 80} 81 82$0 ~ /^\..*\([0-9]\)/ { 83 if ($1 == ".IR" && $3 ~ /\([0-9]\)/) { 84 name = $2 85 section = $3 86 }else if ($1 == ".RI" && $2 == "(" && $4 ~ /\([0-9]\)/) { 87 name = $3 88 section = $4 89 }else if ($1 == ".IR" && $3 ~ /9.\([0-9]\)/) { 90 name = $2 91 section = "9" 92 }else if ($1 == ".RI" && $2 == "(" && $4 ~ /9.\([0-9]\)/) { 93 name = $3 94 section = "9" 95 } else { 96 print "Possible bad cross-reference format in", FILENAME 97 print $0 98 next 99 } 100 gsub(/[^0-9]/, "", section) 101 Refs[section "/" toupper(name)]++ 102} 103 104END { 105 print "Checking Cross-Referenced Pages" 106 for (i in Refs) { 107 if (!(i in Pages)) 108 print "Need", tolower(i) 109 } 110 print "" 111 print "Checking commands" 112 getindex("/usr/inferno/doc/man/1") 113 getindex("/usr/inferno/doc/man/8") 114 Skipdirs["lib"] = 1 115 getbinlist("/usr/inferno/dis") 116 for (i in List) { 117 if (!(i in Index)) 118 print "Need", i, "(in " List[i] ")" 119 } 120 clearindex() 121 clearlist() 122 print "" 123 print "Checking libraries" 124 getindex("/usr/inferno/doc/man/2") 125 getbinlist("/usr/inferno/dis/lib") 126 for (i in List) { 127 if (!(i in Index)) 128 print "Need", i, "(in " List[i] ")" 129 } 130} 131 132func getindex(dir, fname) 133{ 134 fname = dir "/INDEX" 135 while ((getline < fname) > 0) 136 Index[$1] = dir 137 close(fname) 138} 139 140func getindex9(dir, fname) 141{ 142 fname = dir "/INDEX" 143 while ((getline < fname) > 0) 144 if($2 ~ "(getflags|picopen|getcmap)") 145 Index[$1] = dir 146 close(fname) 147} 148 149func getbinlist(dir, cmd, subdirs, nsd) 150{ 151 cmd = "ls -p -l " dir 152 nsd = 0 153 while (cmd | getline) { 154 if ($1 ~ /^d/) { 155 if (!($10 in Skipdirs)) 156 subdirs[++nsd] = $10 157 } else { 158 sub(".dis", "", $10) 159 List[$10] = dir 160 } 161 } 162 for ( ; nsd > 0 ; nsd--) 163 getbinlist(dir "/" subdirs[nsd]) 164 close(cmd) 165} 166 167func getnmlist(lib, cmd) 168{ 169 cmd = "nm -g -h " lib 170 while (cmd | getline) { 171 if (($1 == "T" || $1 == "L") && $2 !~ "^_") 172 List[$2] = lib 173 } 174 close(cmd) 175} 176 177func clearindex( i) 178{ 179 for (i in Index) 180 delete Index[i] 181} 182 183func clearlist( i) 184{ 185 for (i in List) 186 delete List[i] 187} 188