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 Omitted["411"] = 1 25 Omitted["Kill"] = 1 26 Omitted["cb"] = 1 27 Omitted["edmail"] = 1 28 Omitted["mousereset"] = 1 29 Omitted["postalias"] = 1 30 Omitted["mksacfs"] = 1 31 Omitted["sacfs"] = 1 32 Omitted["stock"] = 1 33 Omitted["eg"] = 1 34 Omitted["i"] = 1 35 Omitted["netlib_find"] = 1 36 Omitted["uuencode"] = 1 37 Omitted["uudecode"] = 1 38 Omitted["P"] = 1 39 Omitted["charon"] = 1 40 Omitted["tcp17032"] = 1 41 Omitted["tcp17033"] = 1 42 Omitted["tcp666"] = 1 43 Omitted["tcp667"] = 1 44 Omitted["tcp7330"] = 1 45 Omitted["tcp22"] = 1 46 Omitted["tcp79"] = 1 47 Omitted["tcp1723"] = 1 48 Omitted["pump"] = 1 49 Omitted["allmail"] = 1 50 51 Omittedlib["brk_"] = 1 52 Omittedlib["creadimage"] = 1 53 Omittedlib["main"] = 1 54 Omittedlib["opasstokey"] = 1 55 Omittedlib["oseek"] = 1 56 Omittedlib["sysr1"] = 1 57} 58 59FNR==1 { 60 n = length(FILENAME) 61 seclen = 0 62 if (substr(FILENAME, 2, 1) == "/") 63 seclen = 1 64 else if (substr(FILENAME, 3, 1) == "/") 65 seclen = 2 66 if(seclen == 0) 67 print "FILENAME", FILENAME, "not of form [0-9][0-9]?/*" 68 else if(!(substr(FILENAME, seclen+2, n-seclen-1) ~ /^[A-Z]+(.html)?$/)){ 69 section = substr(FILENAME, 1, seclen) 70 name = substr(FILENAME, seclen+2, n-seclen-1) 71 if($1 != ".TH" || NF != 3) 72 print "First line of", FILENAME, "not a proper .TH" 73 else if($2 != toupper(name) || substr($3, 1, seclen) != section){ 74 if($2!="INTRO" || name!="0intro") 75 print ".TH of", FILENAME, "doesn't match filename" 76 }else 77 Pages[section "/" $2] = 1 78 } 79 Sh = 0 80 } 81 82$1 == ".SH" { 83 if(inex) 84 print "Unterminated .EX in", FILENAME, ":", $0 85 inex = 0; 86 if (substr($2, 1, 1) == "\"") { 87 if (NF == 2) { 88 print "Unneeded quote in", FILENAME, ":", $0 89 $2 = substr($2, 2, length($2)-2) 90 } else if (NF == 3) { 91 $2 = substr($2, 2) substr($3, 1, length($3)-1) 92 NF = 2 93 } 94 } 95 w = Weight[$2] 96 if (w) { 97 if (w < Sh) 98 print "Heading", $2, "out of order in", FILENAME 99 Sh += w 100 } 101} 102 103$1 == ".EX" { 104 if(inex) 105 print "Nested .EX in", FILENAME, ":", $0 106 inex = 1 107} 108 109$1 == ".EE" { 110 if(!inex) 111 print "Bad .EE in", FILENAME, ":", $0 112 inex = 0; 113} 114 115$0 ~ /^\.[A-Z].*\([1-9]\)/ { 116 if ($1 == ".IR" && $3 ~ /\([0-9]\)/) { 117 name = $2 118 section = $3 119 }else if ($1 == ".RI" && $2 == "(" && $4 ~ /\([0-9]\)/) { 120 name = $3 121 section = $4 122 }else if ($1 == ".IR" && $3 ~ /9.\([0-9]\)/) { 123 name = $2 124 section = "9" 125 }else if ($1 == ".RI" && $2 == "(" && $4 ~ /9.\([0-9]\)/) { 126 name = $3 127 section = "9" 128 } else { 129 print "Possible bad cross-reference format in", FILENAME ":" FNR 130 print $0 131 next 132 } 133 gsub(/[^0-9]/, "", section) 134 Refs[section "/" toupper(name)]++ 135} 136 137END { 138 print "Checking Cross-Referenced Pages" 139 for (i in Refs) { 140 if (!(i in Pages)) 141 print "Need", tolower(i) 142 } 143 print "" 144 print "Checking commands" 145 getindex("/sys/man/1") 146 getindex("/sys/man/4") 147 getindex("/sys/man/7") 148 getindex("/sys/man/8") 149 Skipdirs["X11"] = 1 150 Skipdirs["ape"] = 1 151 Skipdirs["aux"] = 1 152 Skipdirs["c++"] = 1 153 Skipdirs["fb"] = 1 154 Skipdirs["odraw"] = 1 155 Skipdirs["pub"] = 1 156 Skipdirs["games"] = 1 157 Skipdirs["lml"] = 1 158 Skipdirs["type1"] = 1 159 Skipdirs["service.alt"] = 1 160 getbinlist("/386/bin") 161 getbinlist("/rc/bin") 162 for (i in List) { 163 if (!(i in Index) && !(i in Omitted)) 164 print "Need", i, "(in " List[i] ")" 165 } 166 print "" 167 for (i in List) { 168 if (!(i in Index) && (i in Omitted)) 169 print "Omit", i, "(in " List[i] ")" 170 } 171 clearindex() 172 clearlist() 173 print "" 174 print "Checking libraries" 175 getindex("/sys/man/2") 176 getnmlist("/386/lib/libauth.a") 177 getnmlist("/386/lib/libbio.a") 178 getnmlist("/386/lib/libc.a") 179 getnmlist("/386/lib/libdebugmalloc.a") 180 getnmlist("/386/lib/libdraw.a") 181 getnmlist("/386/lib/libframe.a") 182 getnmlist("/386/lib/libgeometry.a") 183 getnmlist("/386/lib/libip.a") 184 getnmlist("/386/lib/libmach.a") 185 getnmlist("/386/lib/libmemdraw.a") 186 getnmlist("/386/lib/libmemlayer.a") 187 getnmlist("/386/lib/libmp.a") 188 getnmlist("/386/lib/libndb.a") 189 getnmlist("/386/lib/libplumb.a") 190 getnmlist("/386/lib/libregexp.a") 191 getnmlist("/386/lib/libsec.a") 192 getnmlist("/386/lib/libstdio.a") 193 getnmlist("/386/lib/libthread.a") 194 for (i in List) { 195 if (!(i in Index) && !(i in Omittedlib)) 196 print "Need", i, "(in " List[i] ")" 197 } 198 print "" 199 for (i in List) { 200 if (!(i in Index) && (i in Omittedlib)) 201 print "Omit", i, "(in " List[i] ")" 202 } 203} 204 205func getindex(dir, fname) 206{ 207 fname = dir "/INDEX" 208 while ((getline < fname) > 0) 209 Index[$1] = dir 210 close(fname) 211} 212 213func getbinlist(dir, cmd, subdirs, nsd) 214{ 215 cmd = "ls -p -l " dir 216 nsd = 0 217 while (cmd | getline) { 218 if ($1 ~ /^d/) { 219 if (!($10 in Skipdirs)) 220 subdirs[++nsd] = $10 221 } else if ($10 !~ "^_") 222 List[$10] = dir 223 } 224 for ( ; nsd > 0 ; nsd--) 225 getbinlist(dir "/" subdirs[nsd]) 226 close(cmd) 227} 228 229func getnmlist(lib, cmd) 230{ 231 cmd = "nm -g -h " lib 232 while (cmd | getline) { 233 if (($1 == "T" || $1 == "L") && $2 !~ "^_") 234 List[$2] = lib 235 } 236 close(cmd) 237} 238 239func clearindex( i) 240{ 241 for (i in Index) 242 delete Index[i] 243} 244 245func clearlist( i) 246{ 247 for (i in List) 248 delete List[i] 249} 250