xref: /inferno-os/man/lib/checkman.awk (revision cd17ce433410c01516d7ba8f052a6c5b67b0e2d5)
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