plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

checkman.awk (12137B)


      1 # Usage: cd $PLAN9; awk -f dist/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 
      9 BEGIN {
     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 	Skipdirs["CVS"] = 1
     26 
     27 	# allow references to pages provded
     28 	# by the underlying Unix system
     29 	Omitman["awk(1)"] = 1
     30 	Omitman["bash(1)"] = 1
     31 	Omitman["chmod(1)"] = 1
     32 	Omitman["compress(1)"] = 1
     33 	Omitman["cp(1)"] = 1
     34 	Omitman["egrep(1)"] = 1
     35 	Omitman["gs(1)"] = 1
     36 	Omitman["gv(1)"] = 1
     37 	Omitman["lex(1)"] = 1
     38 	Omitman["lp(1)"] = 1
     39 	Omitman["lpr(1)"] = 1
     40 	Omitman["mail(1)"] = 1
     41 	Omitman["make(1)"] = 1
     42 	Omitman["nm(1)"] = 1
     43 	Omitman["prof(1)"] = 1
     44 	Omitman["pwd(1)"] = 1
     45 	Omitman["qiv(1)"] = 1
     46 	Omitman["sftp(1)"] = 1
     47 	Omitman["sh(1)"] = 1
     48 	Omitman["ssh(1)"] = 1
     49 	Omitman["stty(1)"] = 1
     50 	Omitman["tex(1)"] = 1
     51 	Omitman["unutf(1)"] = 1
     52 	Omitman["vnc(1)"] = 1
     53 	Omitman["xterm(1)"] = 1
     54 
     55 	Omitman["access(2)"] = 1
     56 	Omitman["brk(2)"] = 1
     57 	Omitman["chdir(2)"] = 1
     58 	Omitman["close(2)"] = 1
     59 	Omitman["connect(2)"] = 1
     60 	Omitman["fork(2)"] = 1
     61 	Omitman["gethostname(2)"] = 1
     62 	Omitman["getpid(2)"] = 1
     63 	Omitman["getuid(2)"] = 1
     64 	Omitman["open(2)"] = 1
     65 	Omitman["pipe(2)"] = 1
     66 	Omitman["ptrace(2)"] = 1
     67 	Omitman["rmdir(2)"] = 1
     68 	Omitman["send(2)"] = 1
     69 	Omitman["signal(2)"] = 1
     70 	Omitman["sigprocmask(2)"] = 1
     71 	Omitman["socketpair(2)"] = 1
     72 	Omitman["unlink(2)"] = 1
     73 
     74 	Omitman["abort(3)"] = 1
     75 	Omitman["assert(3)"] = 1
     76 	Omitman["fprintf(3)"] = 1
     77 	Omitman["fscanf(3)"] = 1
     78 	Omitman["fopen(3)"] = 1
     79 	Omitman["isalpha(3)"] = 1
     80 	Omitman["malloc(3)"] = 1
     81 	Omitman["perror(3)"] = 1
     82 	Omitman["remove(3)"] = 1
     83 	Omitman["sin(3)"] = 1
     84 	Omitman["strerror(3)"] = 1
     85 
     86 	Omitman["core(5)"] = 1
     87 	Omitman["passwd(5)"] = 1
     88 
     89 	Omitman["signal(7)"] = 1
     90 
     91 	Omitman["cron(8)"] = 1
     92 	Omitman["mount(8)"] = 1
     93 
     94 	# don't need documentation for these in bin
     95 	Omitted[".cvsignore"] = 1
     96 	Omitted["Getdir"] = 1
     97 	Omitted["Irc"] = 1
     98 	Omitted["Juke"] = 1
     99 	Omitted["ajuke"] = 1
    100 	Omitted["goodmk"] = 1
    101 	Omitted["jukefmt"] = 1
    102 	Omitted["jukeget"] = 1
    103 	Omitted["jukeindex"] = 1
    104 	Omitted["jukeinfo"] = 1
    105 	Omitted["jukeplay"] = 1
    106 	Omitted["jukeput"] = 1
    107 	Omitted["jukesearch"] = 1
    108 	Omitted["jukesongfile"] = 1
    109 	Omitted["m4ainfo"] = 1
    110 	Omitted["mp3info"] = 1
    111 	Omitted["notes"] = 1
    112 	Omitted["tcolors"] = 1
    113 	Omitted["tref"] = 1
    114 	Omitted["unutf"] = 1
    115 	Omitted["volume"] = 1
    116 	Omitted["vtdump"] = 1
    117 	Omitted["netfilelib.rc"] = 1
    118 
    119 	# not for users
    120 	Omittedlib["creadimage"] = 1
    121 	Omittedlib["pixelbits"] = 1
    122 	Omittedlib["bouncemouse"] = 1
    123 	Omittedlib["main"] = 1	# in libthread
    124 	
    125 	Omittedlib["opasstokey"] = 1	# in libauthsrv
    126 
    127 	# functions provided for -lthread_db
    128 	Omittedlib["ps_get_thread_area"] = 1
    129 	Omittedlib["ps_getpid"] = 1
    130 	Omittedlib["ps_lcontinue"] = 1
    131 	Omittedlib["ps_lgetfpregs"] = 1
    132 	Omittedlib["ps_lgetregs"] = 1
    133 	Omittedlib["ps_lsetfpregs"] = 1
    134 	Omittedlib["ps_lsetregs"] = 1
    135 	Omittedlib["ps_lstop"] = 1
    136 	Omittedlib["ps_pcontinue"] = 1
    137 	Omittedlib["ps_pdread"] = 1
    138 	Omittedlib["ps_pdwrite"] = 1
    139 	Omittedlib["ps_pglobal_lookup"] = 1
    140 	Omittedlib["ps_pstop"] = 1
    141 	Omittedlib["ps_ptread"] = 1
    142 	Omittedlib["ps_ptwrite"] = 1
    143 
    144 	# libmach includes a small dwarf and elf library
    145 	Omittedlib["corecmdfreebsd386"] = 1
    146 	Omittedlib["corecmdlinux386"] = 1
    147 	Omittedlib["coreregsfreebsd386"] = 1
    148 	Omittedlib["coreregslinux386"] = 1
    149 	Omittedlib["coreregsmachopower"] = 1
    150 	Omittedlib["crackelf"] = 1
    151 	Omittedlib["crackmacho"] = 1
    152 	Omittedlib["dwarfaddrtounit"] = 1
    153 	Omittedlib["dwarfclose"] = 1
    154 	Omittedlib["dwarfenum"] = 1
    155 	Omittedlib["dwarfenumunit"] = 1
    156 	Omittedlib["dwarfget1"] = 1
    157 	Omittedlib["dwarfget128"] = 1
    158 	Omittedlib["dwarfget128s"] = 1
    159 	Omittedlib["dwarfget2"] = 1
    160 	Omittedlib["dwarfget4"] = 1
    161 	Omittedlib["dwarfget8"] = 1
    162 	Omittedlib["dwarfgetabbrev"] = 1
    163 	Omittedlib["dwarfgetaddr"] = 1
    164 	Omittedlib["dwarfgetn"] = 1
    165 	Omittedlib["dwarfgetnref"] = 1
    166 	Omittedlib["dwarfgetstring"] = 1
    167 	Omittedlib["dwarflookupfn"] = 1
    168 	Omittedlib["dwarflookupname"] = 1
    169 	Omittedlib["dwarflookupnameinunit"] = 1
    170 	Omittedlib["dwarflookupsubname"] = 1
    171 	Omittedlib["dwarflookuptag"] = 1
    172 	Omittedlib["dwarfnextsym"] = 1
    173 	Omittedlib["dwarfnextsymat"] = 1
    174 	Omittedlib["dwarfopen"] = 1
    175 	Omittedlib["dwarfpctoline"] = 1
    176 	Omittedlib["dwarfseeksym"] = 1
    177 	Omittedlib["dwarfskip"] = 1
    178 	Omittedlib["dwarfunwind"] = 1
    179 	Omittedlib["elfclose"] = 1
    180 	Omittedlib["elfdl386mapdl"] = 1
    181 	Omittedlib["elfinit"] = 1
    182 	Omittedlib["elfmachine"] = 1
    183 	Omittedlib["elfmap"] = 1
    184 	Omittedlib["elfopen"] = 1
    185 	Omittedlib["elfsection"] = 1
    186 	Omittedlib["elfsym"] = 1
    187 	Omittedlib["elfsymlookup"] = 1
    188 	Omittedlib["elftype"] = 1
    189 	Omittedlib["machoclose"] = 1
    190 	Omittedlib["machoinit"] = 1
    191 	Omittedlib["machoopen"] = 1
    192 	Omittedlib["stabsym"] = 1
    193 	Omittedlib["symdwarf"] = 1
    194 	Omittedlib["symelf"] = 1
    195 	Omittedlib["symmacho"] = 1
    196 	Omittedlib["symstabs"] = 1
    197 	Omittedlib["elfcorelinux386"] = 1
    198 	Omittedlib["linux2ureg386"] = 1
    199 	Omittedlib["ureg2linux386"] = 1
    200 	Omittedlib["coreregs"] = 1	# haven't documented mach yet
    201 	Omittedlib["regdesc"] = 1
    202 
    203 	Omittedlib["auth_attr"] = 1	# not happy about this
    204 
    205 	Omittedlib["ndbnew"] = 1		# private to library
    206 	Omittedlib["ndbsetval"] = 1
    207 
    208 	Renamelib["chanalt"] = "alt"
    209 	Renamelib["channbrecv"] = "nbrecv"
    210 	Renamelib["channbrecvp"] = "nbrecvp"
    211 	Renamelib["channbrecvul"] = "nbrecvul"
    212 	Renamelib["channbsend"] = "nbsend"
    213 	Renamelib["channbsendp"] = "nbsendp"
    214 	Renamelib["channbsendul"] = "nbsendul"
    215 	Renamelib["chanrecv"] = "recv"
    216 	Renamelib["chanrecvp"] = "recvp"
    217 	Renamelib["chanrecvul"] = "recvul"
    218 	Renamelib["chansend"] = "send"
    219 	Renamelib["chansendp"] = "sendp"
    220 	Renamelib["chansendul"] = "sendul"
    221 	Renamelib["threadyield"] = "yield"
    222 
    223 	Renamelib["fmtcharstod"] = "charstod"
    224 	Renamelib["fmtstrtod"] = "strtod"
    225 
    226 	Renamelib["regcomp9"] = "regcomp"
    227 	Renamelib["regcomplit9"] = "regcomplit"
    228 	Renamelib["regcompnl9"] = "regcompnl"
    229 	Renamelib["regerror9"] = "regerror"
    230 	Renamelib["regexec9"] = "regexec"
    231 	Renamelib["regsub9"] = "regsub"
    232 	Renamelib["rregexec9"] = "rregexec"
    233 	Renamelib["rregsub9"] = "rregsub"
    234 
    235 	lastline = "XXX";
    236 	lastfile = FILENAME;
    237 }
    238 
    239 func getnmlist(lib,    cmd)
    240 {
    241 	cmd = "nm -g " lib
    242 	while (cmd | getline) {
    243 		if (($2 == "T" || $2 == "L") && $3 !~ "^_"){
    244 			sym = $3
    245 			sub("^p9", "", sym)
    246 			if(sym in Renamelib)
    247 				List[Renamelib[sym]] = lib " as " sym
    248 			else
    249 				List[sym] = lib
    250 		}
    251 	}
    252 	close(cmd)
    253 }
    254 
    255 
    256 func getindex(dir,    fname)
    257 {
    258 	fname = dir "/INDEX"
    259 	while ((getline < fname) > 0)
    260 		Index[$1] = dir
    261 	close(fname)
    262 }
    263 
    264 func getbinlist(dir,    cmd, subdirs, nsd)
    265 {
    266 	cmd = "ls -p -l " dir
    267 	nsd = 0
    268 	while (cmd | getline) {
    269 		if ($1 ~ /^d/) {
    270 			if (!($10 in Skipdirs))
    271 				subdirs[++nsd] = $10
    272 		} else if ($10 !~ "^_")
    273 			List[$10] = dir
    274 	}
    275 	for ( ; nsd > 0 ; nsd--)
    276 		getbinlist(dir "/" subdirs[nsd])
    277 	close(cmd)
    278 }
    279 
    280 func clearindex(    i)
    281 {
    282 	for (i in Index)
    283 		delete Index[i]
    284 }
    285 
    286 func clearlist(    i)
    287 {
    288 	for (i in List)
    289 		delete List[i]
    290 }
    291 
    292 
    293 FNR==1	{
    294 	if(lastline == ""){
    295 		# screws up troff headers
    296 		print lastfile ":$ is a blank line"
    297 	}
    298 
    299 	n = length(FILENAME)
    300 	nam = FILENAME
    301 	if(nam ~ /\.html$/)
    302 		next
    303 	if(nam !~ /^man\/man(.*)\/(.*)\.(.*)$/){
    304 		print "nam", nam, "not of form [0-9][0-9]?/*"
    305 		next
    306 	}
    307 	nam = substr(nam, 8)
    308 	gsub("[/.]", " ", nam);
    309 	n = split(nam, a)
    310 	sec = a[1]
    311 	name = a[2]
    312 	section = a[3]
    313 	if($1 != ".TH" || NF != 3)
    314 		print "First line of", FILENAME, "not a proper .TH"
    315 	else if(($2 != toupper(name) || substr($3, 1, length(sec)) != sec || $3 != toupper(section)) \
    316 			&& ($2!="INTRO" || name!="0intro") \
    317 			&& (name !~ /^9/ || $2!=toupper(substr(name, 2)))){
    318 		print ".TH of", FILENAME, "doesn't match filename"
    319 	}else
    320 		Pages[tolower($2) "(" tolower($3) ")"] = 1
    321 	Sh = 0
    322 }
    323 
    324 { lastline=$0; lastfile=FILENAME; }
    325 
    326 $1 == ".SH" {
    327 	if(inex)
    328 		print "Unterminated .EX in", FILENAME, ":", $0
    329 	inex = 0;
    330 	if (substr($2, 1, 1) == "\"") {
    331 		if (NF == 2) {
    332 			print "Unneeded quote in", FILENAME, ":", $0
    333 			$2 = substr($2, 2, length($2)-2)
    334 		} else if (NF == 3) {
    335 			$2 = substr($2, 2) substr($3, 1, length($3)-1)
    336 			NF = 2
    337 		}
    338 	}
    339 	if(Sh == 0 && $2 != "NAME")
    340 		print FILENAME, "has no .SH NAME"
    341 	w = Weight[$2]
    342 	if (w) {
    343 		if (w < Sh)
    344 			print "Heading", $2, "out of order in", FILENAME
    345 		Sh += w
    346 	}
    347 	sh = $2
    348 }
    349 
    350 $1 == ".EX" {
    351 		if(inex)
    352 			print "Nested .EX in", FILENAME ":" FNR, ":", $0
    353 		inex = 1
    354 }
    355 
    356 $1 == ".EE" {
    357 	if(!inex)
    358 		print "Bad .EE in", FILENAME ":" FNR ":", $0
    359 	inex = 0;
    360 }
    361 
    362 $1 == ".TF" {
    363 	smallspace = 1
    364 }
    365 
    366 $1 == ".PD" || $1 == ".SH" || $1 == ".SS" || $1 == ".TH" {
    367 	smallspace = 0
    368 }
    369 
    370 $1 == ".RE" {
    371 	lastre = 1
    372 }
    373 
    374 $1 == ".PP" {
    375 	if(smallspace && !lastre)
    376 		print "Possible missing .PD at " FILENAME ":" FNR
    377 	smallspace = 0
    378 }
    379 
    380 $1 != ".RE" {
    381 	lastre = 0
    382 }
    383 
    384 sh == "BUGS" && $1 == ".br" {
    385 	print FILENAME ":" FNR ": .br in BUGS"
    386 }
    387 
    388 sh == "SOURCE" && $1 ~ /^\\\*9\// {
    389 	s = ENVIRON["PLAN9"] substr($1, 4)
    390 	Sources[s] = 1
    391 }
    392 
    393 sh == "SOURCE" && $2 ~ /^\\\*9\// {
    394 	s = ENVIRON["PLAN9"] substr($2, 4)
    395 	Sources[s] = 1
    396 }
    397 
    398 sh == "SOURCE" && $1 ~ /^\// {
    399 	Sources[$1] = 1
    400 }
    401 
    402 sh == "SOURCE" && $2 ~ /^\// {
    403 	Sources[$2] = 1
    404 }
    405 
    406 $0 ~ /^\.[A-Z].*\([1-9]\)/ {
    407 		if ($1 == ".IR" && $3 ~ /\([0-9]\)/) {
    408 			name = $2
    409 			section = $3
    410 		}else if ($1 == ".RI" && $2 == "(" && $4 ~ /\([0-9]\)/) {
    411 			name = $3
    412 			section = $4
    413 		}else if ($1 == ".IR" && $3 ~ /9.\([0-9]\)/) {
    414 			name = $2
    415 			section = "9"
    416 		}else if ($1 == ".RI" && $2 == "(" && $4 ~ /9.\([0-9]\)/) {
    417 			name = $3
    418 			section = "9"
    419 		} else {
    420 			if ($1 == ".HR" && $3 == "\"Section")
    421 				next;
    422 			print "Possible bad cross-reference format in", FILENAME ":" FNR
    423 			print $0
    424 			next
    425 		}
    426 		gsub(/[^0-9]/, "", section)
    427 		Refs[toupper(name) "(" section ")"]++
    428 }
    429 
    430 END {
    431 	if(lastline == ""){
    432 		print lastfile ":$ is a blank line"
    433 	}
    434 
    435 	print "Checking Source References"
    436 	cmd = "xargs -n 100 ls -d 2>&1 >/dev/null | sed 's/^ls: /	/; s/: .*//'"
    437 	for (i in Sources) {
    438 		print i |cmd
    439 	}
    440 	close(cmd)
    441 	print ""
    442 	print "Checking Cross-Referenced Pages"
    443 	for (i in Refs) {
    444 		if (!(tolower(i) in Pages) && !(tolower(i) in Omitman)){
    445 			b = tolower(i)
    446 			gsub("\\(", " \\(", b)
    447 			gsub("\\)", "\\)", b)
    448 			split(tolower(i), a, "/")
    449 			print "egrep -in '^\\.IR.*" b "' $PLAN9/man/man*/* # Need " tolower(i) |"sort"
    450 		}
    451 	}
    452 	close("sort")
    453 	print ""
    454 	print "Checking commands"
    455 	getindex("man/man1")
    456 	getindex("man/man4")
    457 	getindex("man/man7")
    458 	getindex("man/man8")
    459 	getbinlist("bin")
    460 	for (i in List) {
    461 		if (!(i in Index) && !(i in Omitted))
    462 			print "Need", i, "(in " List[i] ")" |"sort"
    463 	}
    464 	close("sort")
    465 	print ""
    466 	for (i in List) {
    467 		if (!(i in Index) && (i in Omitted))
    468 			print "Omit", i, "(in " List[i] ")" |"sort"
    469 	}
    470 	close("sort")
    471 	clearindex()
    472 	clearlist()
    473 	print ""
    474 	print "Checking libraries"
    475 	getindex("man/man3")
    476 	getnmlist("lib/lib9.a")
    477 	getnmlist("lib/lib9p.a")
    478 	getnmlist("lib/lib9pclient.a")
    479 	getnmlist("lib/libString.a")
    480 	getnmlist("lib/libauth.a")
    481 	getnmlist("lib/libauthsrv.a")
    482 	getnmlist("lib/libbin.a")
    483 	getnmlist("lib/libbio.a")
    484 	getnmlist("lib/libcomplete.a")
    485 	# getnmlist("lib/libcontrol.a")
    486 	getnmlist("lib/libdisk.a")
    487 	getnmlist("lib/libdraw.a")
    488 	getnmlist("lib/libflate.a")
    489 	getnmlist("lib/libframe.a")
    490 	getnmlist("lib/libgeometry.a")
    491 	getnmlist("lib/libhtml.a")
    492 	# getnmlist("lib/libhttpd.a")
    493 	getnmlist("lib/libip.a")
    494 	getnmlist("lib/libmach.a")
    495 	# getnmlist("lib/libmemdraw.a")
    496 	# getnmlist("lib/libmemlayer.a")
    497 	getnmlist("lib/libmp.a")
    498 	getnmlist("lib/libmux.a")
    499 	getnmlist("lib/libndb.a")
    500 	getnmlist("lib/libplumb.a")
    501 	getnmlist("lib/libregexp9.a")
    502 	getnmlist("lib/libsec.a")
    503 	getnmlist("lib/libthread.a")
    504 	# getnmlist("lib/libventi.a")
    505 	for (i in List) {
    506 		if (!(i in Index) && !(i in Omittedlib))
    507 			print "Need", List[i], i |"sort"
    508 			# print "Need", i, "(in " List[i] ")" |"sort"
    509 	}
    510 	close("sort")
    511 	print ""
    512 	for (i in List) {
    513 		if (!(i in Index) && (i in Omittedlib))
    514 			print "Omit", List[i], i |"sort"
    515 			# print "Omit", i, "(in " List[i] ")" |"sort"
    516 	}
    517 	close("sort")
    518 }
    519