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 if(Sh == 0 && $2 != "NAME") 96 print FILENAME, "has no .SH NAME" 97 w = Weight[$2] 98 if (w) { 99 if (w < Sh) 100 print "Heading", $2, "out of order in", FILENAME 101 Sh += w 102 } 103} 104 105$1 == ".EX" { 106 if(inex) 107 print "Nested .EX in", FILENAME, ":", $0 108 inex = 1 109} 110 111$1 == ".EE" { 112 if(!inex) 113 print "Bad .EE in", FILENAME, ":", $0 114 inex = 0; 115} 116 117$1 == ".TF" { 118 smallspace = 1 119} 120 121$1 == ".PD" || $1 == ".SH" || $1 == ".SS" || $1 == ".TH" { 122 smallspace = 0 123} 124 125$1 == ".RE" { 126 lastre = 1 127} 128 129$1 == ".PP" { 130 if(smallspace && !lastre) 131 print "Possible missing .PD at " FILENAME ":" FNR 132 smallspace = 0 133} 134 135$1 != ".RE" { 136 lastre = 0 137} 138 139$0 ~ /^\.[A-Z].*\([1-9]\)/ { 140 if ($1 == ".IR" && $3 ~ /\([0-9]\)/) { 141 name = $2 142 section = $3 143 }else if ($1 == ".RI" && $2 == "(" && $4 ~ /\([0-9]\)/) { 144 name = $3 145 section = $4 146 }else if ($1 == ".IR" && $3 ~ /9.\([0-9]\)/) { 147 name = $2 148 section = "9" 149 }else if ($1 == ".RI" && $2 == "(" && $4 ~ /9.\([0-9]\)/) { 150 name = $3 151 section = "9" 152 } else { 153 print "Possible bad cross-reference format in", FILENAME ":" FNR 154 print $0 155 next 156 } 157 gsub(/[^0-9]/, "", section) 158 Refs[section "/" toupper(name)]++ 159} 160 161END { 162 print "Checking Cross-Referenced Pages" 163 for (i in Refs) { 164 if (!(i in Pages)) 165 print "Need", tolower(i) 166 } 167 print "" 168 print "Checking commands" 169 getindex("/sys/man/1") 170 getindex("/sys/man/4") 171 getindex("/sys/man/7") 172 getindex("/sys/man/8") 173 Skipdirs["X11"] = 1 174 Skipdirs["ape"] = 1 175 Skipdirs["aux"] = 1 176 Skipdirs["c++"] = 1 177 Skipdirs["fb"] = 1 178 Skipdirs["odraw"] = 1 179 Skipdirs["pub"] = 1 180 Skipdirs["games"] = 1 181 Skipdirs["lml"] = 1 182 Skipdirs["type1"] = 1 183 Skipdirs["service.alt"] = 1 184 getbinlist("/386/bin") 185 getbinlist("/rc/bin") 186 for (i in List) { 187 if (!(i in Index) && !(i in Omitted)) 188 print "Need", i, "(in " List[i] ")" 189 } 190 print "" 191 for (i in List) { 192 if (!(i in Index) && (i in Omitted)) 193 print "Omit", i, "(in " List[i] ")" 194 } 195 clearindex() 196 clearlist() 197 print "" 198 print "Checking libraries" 199 getindex("/sys/man/2") 200 getnmlist("/386/lib/libauth.a") 201 getnmlist("/386/lib/libbio.a") 202 getnmlist("/386/lib/libc.a") 203 getnmlist("/386/lib/libdebugmalloc.a") 204 getnmlist("/386/lib/libdraw.a") 205 getnmlist("/386/lib/libframe.a") 206 getnmlist("/386/lib/libgeometry.a") 207 getnmlist("/386/lib/libip.a") 208 getnmlist("/386/lib/libmach.a") 209 getnmlist("/386/lib/libmemdraw.a") 210 getnmlist("/386/lib/libmemlayer.a") 211 getnmlist("/386/lib/libmp.a") 212 getnmlist("/386/lib/libndb.a") 213 getnmlist("/386/lib/libplumb.a") 214 getnmlist("/386/lib/libregexp.a") 215 getnmlist("/386/lib/libsec.a") 216 getnmlist("/386/lib/libstdio.a") 217 getnmlist("/386/lib/libthread.a") 218 for (i in List) { 219 if (!(i in Index) && !(i in Omittedlib)) 220 print "Need", i, "(in " List[i] ")" 221 } 222 print "" 223 for (i in List) { 224 if (!(i in Index) && (i in Omittedlib)) 225 print "Omit", i, "(in " List[i] ")" 226 } 227} 228 229func getindex(dir, fname) 230{ 231 fname = dir "/INDEX" 232 while ((getline < fname) > 0) 233 Index[$1] = dir 234 close(fname) 235} 236 237func getbinlist(dir, cmd, subdirs, nsd) 238{ 239 cmd = "ls -p -l " dir 240 nsd = 0 241 while (cmd | getline) { 242 if ($1 ~ /^d/) { 243 if (!($10 in Skipdirs)) 244 subdirs[++nsd] = $10 245 } else if ($10 !~ "^_") 246 List[$10] = dir 247 } 248 for ( ; nsd > 0 ; nsd--) 249 getbinlist(dir "/" subdirs[nsd]) 250 close(cmd) 251} 252 253func getnmlist(lib, cmd) 254{ 255 cmd = "nm -g -h " lib 256 while (cmd | getline) { 257 if (($1 == "T" || $1 == "L") && $2 !~ "^_") 258 List[$2] = lib 259 } 260 close(cmd) 261} 262 263func clearindex( i) 264{ 265 for (i in Index) 266 delete Index[i] 267} 268 269func clearlist( i) 270{ 271 for (i in List) 272 delete List[i] 273} 274