# classdoc.awk # # This awk script tries to produce a manual page from a C++ header file. # The idea is to make the documentation more readable, without maintaining # a separate file. Typical usage: # # gawk -f classdoc.awk list.H | nroff -man # # Although the result may not be exactly as intended, nothing in the file # (except #if, #ifdef, #ifndef, #endif) is supposed to be thrown away. # Major problem: comments associated with stuff that is saved (typedef, #define, # etc.), is not saved but appears with some unrelated code. # Improvemnts are gratefully accepted. # # Author: Dag Michael Bruck, Department of Automatic Control, Lund Institute # of Technology, Box 118, S-221 00 Lund, SWEDEN. E-mail: dag@control.lth.se # # Version: 2.5 Last change: 1990-05-15 # FNR == 1 { "basename " FILENAME " .hh" | getline ShortName; print ".TH","CDF C++" print ".SH", ShortName Section = "None"; SubSect = "None"; ContinueStat = 0; } # # Stop class ducumentation # /CLASSDOC[ \t]+OFF/ { while ($0 !~ /CLASSDOC[ \t]+ON/) getline; getline; } # # #define macro, placed at end of manual page # $1 == "#define" { $0 = dropfirst($0); match($0, /[A-Za-z0-9_]+(\([^\)]*\))?/); save("define", substr($0, RSTART, RLENGTH)); eatcontinuation(); next; } # # #include files, placed at end # $1 == "#include" { save("include", substr($2, 2, length($2)-2)); next; } # # Drop some cpp directives # $1 == "#if" { next; } $1 == "#ifdef" { next; } $1 == "#ifndef" { next; } $1 == "#else" { next; } $1 == "#elif" { next; } $1 == "#endif" { next; } $1 == "#error" { next; } # # Extrnal declarations, placed at end # $1 == "extern" { save("extern", dropfirst($0)); next; } # # Typedef declaration, placed at end # $1 == "typedef" { save("typedef", dropfirst($0)); next; } # # Class declarations, place at end # $1 ~ /^class$|^struct$/ && $2 ~ /;$/ { save("classdecl", $1 " " substr($2, 1, length($2)-1)); next; } # # C++ comment (the /* ... */ variant is not recognized) # $1 ~ /^\/\// { if (!(Section ~ /Description|Class|Code/)) section("Description", "DESCRIPTION"); if (InComment == 0) { if (Section == "Description") print ".fi\n.ft R\n.PP"; else print ".fi\n.ft R\n.sp 0.1v\n.RS 0.25i"; }; if (NF == 1) print ".PP"; else { match($0, /\/\/[ ]*/); if (SubSect != "Private" && SubSect != "Protected") print substr($0, RSTART+RLENGTH); } InComment = 1; next; } # # Class definition # $1 ~ /^class$/ && $2 !~ /;$/ && Section != "Class" { section("Class", "CLASS " $2); if (NF > 4) { subsect("Base", "Base class"); print ".fi\n.ft R"; for (i=4; i < NF; i++) print $i; print ".nf\n.ft B"; }; next; } # # Struct definition - almost a class # $1 ~ /^struct$/ && $2 !~ /;$/ && Section != "Class" { section("Class", "STRUCT " $2); subsect("Public", "Public members"); next; } # # End of class definition # $1 == "};" { Section = "None"; SubSect = "None"; InComment = 0; next; } # # Friend declaration, only in classes # $1 == "friend" { subsect("Friend", "Friends"); print dropfirst($0); next; } # # Public, protected and private parts of a class # /public:/ { subsect("Public", "Public members"); next; } /protected:/ { subsect("Protected", "Protected members, see header file"); next; } /private:/ { subsect("Private", "Private members, see header file"); next; } # # Everything else inside a class (not comments) # Section == "Class" { if (InComment == 1) print ".RE\n.PP\n.nf\n.ft B"; if (SubSect != "Private" && SubSect != "Protected" && NF > 0) print substr($0, index($0, $1)); if (match($0, /,[ \t]*$/)) { if (ContinueStat == 0) print ".RS 1i\n.ft B"; ContinueStat = 1; } else if (ContinueStat == 1) { print ".RE\n.ft B"; ContinueStat = 0; } InComment = 0; next; } # # Blank lines # NF == 0 { print ".PP" if (Section == "Code") print ".nf\n.ft B"; next; } # # Everything else (outside classes) # { if (Section != "Code") section("Code", ""); if (InComment == 1) { print ".RE\n.PP\n.nf\n.ft B"; InComment = 0; }; # print; next; } # # Post-processing: list class declarations, external declarations, # macro definitions and includec files. # END { if (issaved("classdecl")) { print ".SH CLASS DECLARATIONS\n.nf"; printsaved("classdecl"); } if (issaved("extern")) { print ".SH EXTERNAL DECLARATIONS\n.nf"; printsaved("extern"); } if (issaved("typedef")) { print ".SH TYPE DEFINITIONS\n.nf"; printsaved("typedef"); } if (issaved("define")) { print ".SH DEFINED MACROS\n.nf"; printsaved("define"); } if (issaved("include")) { print ".SH INCLUDED FILES\n.nf"; printsaved("include"); } } # # dropfirst(str) - returns string without its first field # function dropfirst(str) { if (match(str, /^[ \t]*[^ \t]*[ \t]+/)) return substr(str, RLENGTH+1); else return str; } # # save, ... - functions for saving text in an area, printing it, etc. # function save(area, str) { TextCount[area]++; TextArea[area, TextCount[area]] = str; } function issaved(area) { return TextCount[area] > 0; } function printsaved(area, i) { for (i = 1; i <= TextCount[area]; i++) print TextArea[area, i]; } # # section(sect, heading) - change section, no subsection # function section(sect, heading) { if (sect != Section) { Section = sect; print ".SH", heading; print ".nf\n.ft B"; InComment = 0; } SubSect = "None"; } # # subsect(subs, heading) - change subsection # function subsect(subs, heading) { if (subs != SubSect) { SubSect = subs; print ".SH", heading; print ".nf\n.ft B"; InComment = 0; } } # # eatcontinuation() - eat continuation lines (preceding line ended in \) # function eatcontinuation() { while ($0 ~ /\\$/) getline; }