blob: 947888dcb5acb516dd4e7fe1952654d4fe3c8dc0 [file] [log] [blame]
rsc02f38ca2005-01-04 22:33:11 +00001# 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
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 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
rsc83c45062005-02-11 19:43:43 +000041 Omitman["make(1)"] = 1
rsc02f38ca2005-01-04 22:33:11 +000042 Omitman["nm(1)"] = 1
43 Omitman["prof(1)"] = 1
44 Omitman["pwd(1)"] = 1
rscc8b63422005-01-13 04:49:19 +000045 Omitman["qiv(1)"] = 1
rsc11f10a62005-05-07 22:32:24 +000046 Omitman["sftp(1)"] = 1
rsc02f38ca2005-01-04 22:33:11 +000047 Omitman["sh(1)"] = 1
48 Omitman["ssh(1)"] = 1
rscc8b63422005-01-13 04:49:19 +000049 Omitman["stty(1)"] = 1
rsc02f38ca2005-01-04 22:33:11 +000050 Omitman["tex(1)"] = 1
51 Omitman["unutf(1)"] = 1
rsc83c45062005-02-11 19:43:43 +000052 Omitman["vnc(1)"] = 1
rsc02f38ca2005-01-04 22:33:11 +000053 Omitman["xterm(1)"] = 1
54
55 Omitman["access(2)"] = 1
56 Omitman["brk(2)"] = 1
rscc8b63422005-01-13 04:49:19 +000057 Omitman["chdir(2)"] = 1
rsc02f38ca2005-01-04 22:33:11 +000058 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
rsc02f38ca2005-01-04 22:33:11 +000086 Omitman["core(5)"] = 1
87 Omitman["passwd(5)"] = 1
88
89 Omitman["signal(7)"] = 1
90
91 Omitman["cron(8)"] = 1
rsc98deccf2005-07-19 11:04:21 +000092 Omitman["mount(8)"] = 1
rsc02f38ca2005-01-04 22:33:11 +000093
94 # don't need documentation for these in bin
95 Omitted[".cvsignore"] = 1
96 Omitted["Getdir"] = 1
rsc83c45062005-02-11 19:43:43 +000097 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
rscc8b63422005-01-13 04:49:19 +0000112 Omitted["tcolors"] = 1
113 Omitted["tref"] = 1
114 Omitted["unutf"] = 1
rsc83c45062005-02-11 19:43:43 +0000115 Omitted["volume"] = 1
rscc8b63422005-01-13 04:49:19 +0000116 Omitted["vtdump"] = 1
rsc98deccf2005-07-19 11:04:21 +0000117 Omitted["netfilelib.rc"] = 1
rsc02f38ca2005-01-04 22:33:11 +0000118
119 # not for users
120 Omittedlib["creadimage"] = 1
121 Omittedlib["pixelbits"] = 1
122 Omittedlib["bouncemouse"] = 1
123 Omittedlib["main"] = 1 # in libthread
rsc83c45062005-02-11 19:43:43 +0000124
125 Omittedlib["opasstokey"] = 1 # in libauthsrv
rsc02f38ca2005-01-04 22:33:11 +0000126
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
rsc83c45062005-02-11 19:43:43 +0000197 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
rsc02f38ca2005-01-04 22:33:11 +0000207
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"
rscc8b63422005-01-13 04:49:19 +0000234
235 lastline = "XXX";
236 lastfile = FILENAME;
rsc02f38ca2005-01-04 22:33:11 +0000237}
238
rsc9e50a7d2005-03-21 17:28:14 +0000239func 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
256func getindex(dir, fname)
257{
258 fname = dir "/INDEX"
259 while ((getline < fname) > 0)
260 Index[$1] = dir
261 close(fname)
262}
263
264func 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
280func clearindex( i)
281{
282 for (i in Index)
283 delete Index[i]
284}
285
286func clearlist( i)
287{
288 for (i in List)
289 delete List[i]
290}
291
292
rsc02f38ca2005-01-04 22:33:11 +0000293FNR==1 {
rscc8b63422005-01-13 04:49:19 +0000294 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
rsc02f38ca2005-01-04 22:33:11 +0000322}
323
rscc8b63422005-01-13 04:49:19 +0000324{ lastline=$0; lastfile=FILENAME; }
325
rsc02f38ca2005-01-04 22:33:11 +0000326$1 == ".SH" {
rscc8b63422005-01-13 04:49:19 +0000327 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
rsc02f38ca2005-01-04 22:33:11 +0000337 }
rscc8b63422005-01-13 04:49:19 +0000338 }
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
rsc02f38ca2005-01-04 22:33:11 +0000348}
349
350$1 == ".EX" {
351 if(inex)
352 print "Nested .EX in", FILENAME ":" FNR, ":", $0
353 inex = 1
354}
355
356$1 == ".EE" {
rscc8b63422005-01-13 04:49:19 +0000357 if(!inex)
358 print "Bad .EE in", FILENAME ":" FNR ":", $0
359 inex = 0;
rsc02f38ca2005-01-04 22:33:11 +0000360}
361
362$1 == ".TF" {
rscc8b63422005-01-13 04:49:19 +0000363 smallspace = 1
rsc02f38ca2005-01-04 22:33:11 +0000364}
365
366$1 == ".PD" || $1 == ".SH" || $1 == ".SS" || $1 == ".TH" {
rscc8b63422005-01-13 04:49:19 +0000367 smallspace = 0
rsc02f38ca2005-01-04 22:33:11 +0000368}
369
370$1 == ".RE" {
rscc8b63422005-01-13 04:49:19 +0000371 lastre = 1
rsc02f38ca2005-01-04 22:33:11 +0000372}
373
374$1 == ".PP" {
rscc8b63422005-01-13 04:49:19 +0000375 if(smallspace && !lastre)
376 print "Possible missing .PD at " FILENAME ":" FNR
377 smallspace = 0
rsc02f38ca2005-01-04 22:33:11 +0000378}
379
380$1 != ".RE" {
rscc8b63422005-01-13 04:49:19 +0000381 lastre = 0
382}
383
384sh == "BUGS" && $1 == ".br" {
385 print FILENAME ":" FNR ": .br in BUGS"
386}
387
388sh == "SOURCE" && $1 ~ /^\\\*9\// {
389 s = ENVIRON["PLAN9"] substr($1, 4)
390 Sources[s] = 1
391}
392
393sh == "SOURCE" && $2 ~ /^\\\*9\// {
394 s = ENVIRON["PLAN9"] substr($2, 4)
395 Sources[s] = 1
rsc02f38ca2005-01-04 22:33:11 +0000396}
397
398sh == "SOURCE" && $1 ~ /^\// {
rscc8b63422005-01-13 04:49:19 +0000399 Sources[$1] = 1
rsc02f38ca2005-01-04 22:33:11 +0000400}
401
402sh == "SOURCE" && $2 ~ /^\// {
rscc8b63422005-01-13 04:49:19 +0000403 Sources[$2] = 1
rsc02f38ca2005-01-04 22:33:11 +0000404}
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 {
rsc83c45062005-02-11 19:43:43 +0000420 if ($1 == ".HR" && $3 == "\"Section")
421 next;
rsc02f38ca2005-01-04 22:33:11 +0000422 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
430END {
rscc8b63422005-01-13 04:49:19 +0000431 if(lastline == ""){
432 print lastfile ":$ is a blank line"
433 }
434
rsc02f38ca2005-01-04 22:33:11 +0000435 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")
rsc83c45062005-02-11 19:43:43 +0000480 getnmlist("lib/libauth.a")
481 getnmlist("lib/libauthsrv.a")
rsc02f38ca2005-01-04 22:33:11 +0000482 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")
rsc83c45062005-02-11 19:43:43 +0000499 getnmlist("lib/libndb.a")
rsc02f38ca2005-01-04 22:33:11 +0000500 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