tcheckman.awk - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tcheckman.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