home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / GENMAN.ZIP / GENMAN.AWK < prev    next >
Text File  |  1993-03-13  |  15KB  |  678 lines

  1. #
  2. # Awk program that takes as input a C++ header file and outputs
  3. # a UNIX style man page.
  4. #
  5. # The contents of this file are public domain.
  6. # Author: Bob Mastors
  7. #         Epoch Systems, Inc.
  8. #         6/90
  9. #      Version 2
  10.  
  11. BEGIN {
  12.     library= "UNKNOWN"
  13.     sourcefilecount= 1
  14.     definecount= 1
  15.     constcount= 1
  16.     includecount= 1
  17.     typedefcount= 1
  18.     enumcount= 1
  19.     structcount= 1
  20.     externcount= 0
  21.     classcount= 0
  22.     doccount= 0
  23.     lp_indent= "    "
  24.     bold= ""
  25.  
  26.     sourcefile[0]=  "%h" "source files"
  27.     define[0]=      "%h" "defined macros"
  28.     const[0]=       "%h" "constants"
  29.     include[0]=     "%h" "included files"
  30.     typedef[0]=     "%h" "type definitions"
  31.     enum[0]=        "%h" "enumerations"
  32.     struct[0]=      "%h" "structures"
  33.     }
  34.  
  35. /^#define/ {
  36.     tmp= substr( $0, 8 )
  37.     tmp= strip_white( tmp )
  38.     gsub( "\\\\$", "", tmp );
  39.     define[ definecount++ ] = tmp
  40.     }
  41.  
  42. /^const/ {
  43.     tmp= substr( $0, 6 )
  44.     tmp= strip_white( tmp )
  45.     gsub( "//", "", tmp );
  46.     const[ constcount++ ] = tmp
  47.     }
  48.  
  49. /^#include/ {
  50.     tmp= substr( $0, 9 )
  51.     tmp= strip_white( tmp )
  52.     include[ includecount++ ] = tmp
  53.     }
  54.  
  55. /^extern/ {
  56.     tmp= substr( $0, 7 )
  57.     tmp= strip_white( tmp )
  58.     extern[ externcount++ ] = tmp
  59.     }
  60.  
  61. /^typedef/ {
  62.     tmp= substr( $0, 8 )
  63.     tmp= strip_white( tmp )
  64.     typedef[ typedefcount++ ] = tmp
  65.     }
  66.  
  67. /^enum/ {
  68.     tmp= substr( $0, 5 )
  69.     gsub( "{", "", tmp );
  70.     tmp= strip_white( tmp )
  71.     enum[ enumcount++ ] = tmp
  72.     while( (getline tmp) > 0 )
  73.         {
  74.         gsub( "{", "", tmp );
  75.         gsub( ",", " ", tmp );
  76.         gsub( "//", "", tmp );
  77.         tmp= strip_white( tmp )
  78.         if( tmp ~ "} *;" )
  79.             break;
  80.     if( length(tmp) > 0 )
  81.         enum[ enumcount++ ] = "%@" tmp
  82.         }
  83.     }
  84.  
  85. /^struct/ {
  86.     process_struct( $0 )
  87.     }
  88.  
  89. /^class/ {
  90.     process_class( $0 )
  91.     classcount++
  92.     }
  93.  
  94. /^\/\// {
  95.     tmp= substr( $0, 4 )
  96.     striptmp= strip_white( tmp )
  97.     if( gsub( "^\.FILE", "", striptmp ) == 1 )
  98.         {
  99.         striptmp= strip_white( striptmp )
  100.         sourcefile[ sourcefilecount++ ] = striptmp
  101.         }
  102.     else
  103.     if( gsub( "^\.LIBRARY", "", striptmp ) == 1 )
  104.         {
  105.         striptmp= strip_white( striptmp )
  106.         library= tolower( striptmp )
  107.         }
  108.     else
  109.     if( gsub( "^\.NAME", "", striptmp ) == 1 )
  110.         {
  111.         namehead= strip_white( striptmp )
  112.         }
  113.     else
  114.     if( gsub( "^\.HEADER", "", striptmp ) == 1 )
  115.         {
  116.         striptmp= strip_white( striptmp )
  117.     header= toupper( striptmp )
  118.         }
  119.     else
  120.     if( gsub( "^\.INCLUDE", "", striptmp ) == 1 )
  121.         {
  122.         includefile= strip_white( striptmp )
  123.         }
  124.     else
  125.     if( gsub( "^\.SECTION", "", striptmp ) == 1 )
  126.         {
  127.     if( doccount > 0 )
  128.             doc[ doccount++ ]= ".SK"
  129.         striptmp= strip_white( striptmp )
  130.         striptmp= toupper( striptmp )
  131.         doc[ doccount++ ]= "%h" striptmp
  132.         doc_flag= "true"
  133.         }
  134.     else if( doc_flag == "true" )
  135.         {
  136.         doc[ doccount++ ]= tmp
  137.         }
  138.     }
  139.  
  140. NF == 0 {
  141.     if( doc_flag == "true" )
  142.     {
  143.         doc_flag= ""
  144.     }
  145.     }
  146.  
  147. END {
  148.     # get the modify date of the file
  149.     if( length(mtime) == 0 )
  150.     {
  151.     "ls -l " FILENAME | getline tmp
  152.     date= substr( tmp, 33, 12 );
  153.     }
  154.     else
  155.     {
  156.     mtime " " FILENAME | getline date
  157.     }
  158.  
  159.     # If .NAME not specified, then make one up
  160.     if( length( namehead ) == 0 )
  161.     namehead=  FILENAME " - ???"
  162.  
  163.     # Make a name for the man page from the first word in the
  164.     # NAME section.
  165.     pos= match( namehead, "[ ,]" );
  166.     if( pos == 0 )
  167.     titlename= namehead
  168.     else
  169.     titlename= substr( namehead, 1, pos-1 )
  170.     titlename= toupper(titlename)
  171.  
  172.     # If .HEADER not specified then use C++
  173.     if( length( header ) == 0 )
  174.         header= "C++"
  175.  
  176.     # If .LIBRARY not specified then use c++
  177.     if( length( library ) == 0 )
  178.         library= "c++"
  179.  
  180.     # Start the formatting and print the title and name
  181.     format_start( titlename, library, header, date, namehead );
  182.  
  183.     # print the synopsis header
  184.     format_line( "%h" "SYNOPSIS" )
  185.     format_line( ".BO" )
  186.     format_line( ".NF" )
  187.  
  188.     if( length( includefile ) == 0 )
  189.         includefile= tolower(FILENAME);
  190.     format_line( "#include <" includefile  ">" )
  191.     format_line( ".SK" )
  192.  
  193.     output_class()
  194.     output_section( extern )
  195.  
  196.     format_line( ".NB" )
  197.     format_line( ".FI" )
  198.  
  199.     output_section( doc )
  200.  
  201.     format_line( ".NF" )
  202.     if( structcount > 1 ) output_section( struct )
  203.     if( enumcount > 1 ) output_section( enum )
  204.     if( typedefcount > 1 ) output_section( typedef )
  205.     if( constcount > 1 ) output_section( const )
  206.     if( definecount > 1 ) output_section( define )
  207.     if( includecount > 1 ) output_section( include )
  208.     if( sourcefilecount > 1 ) output_section( sourcefile )
  209.  
  210.     output_summarys()
  211.  
  212.     # end the formatting
  213.     format_end()
  214.     }
  215.  
  216. # Call to process a class.  Pass the name of the class.
  217. function process_class( name,    inputstr,ii,bers )
  218.     {
  219.     privatecount= 1
  220.     publiccount= 1
  221.     protectedcount= 1
  222.     indent_level= "%@"
  223.  
  224.     # We do not record the curly braces surrounding the class
  225.     # but we record all others.
  226.  
  227.     # If an open curly brace on the "class" line then incriment the
  228.     # indent level.
  229.     # Also see if k&r style curly brace alignment.
  230.     if( name ~ ".*{.*" )
  231.     {
  232.     indent_level= "%@"
  233.     style= "k&r"
  234.     sub( "{", "", name );
  235.     }
  236.     else
  237.     style= "custom"
  238.  
  239.     # record the name
  240.     name= strip_white( name )
  241.     class[ classcount, "head", 0 ]= name
  242.  
  243.     # get lines of input until EOF
  244.     ii= "private"
  245.     while( (getline inputstr) > 0 )
  246.         {
  247.         # just get the token(s), ignore blank lines
  248.         inputstr= strip_white( inputstr )
  249.     if( length(inputstr) == 0 )
  250.         continue;
  251.  
  252.         # see if should adjust the indent level
  253.     if( style == "k&r" )
  254.         {
  255.         if( inputstr ~ "}.*" )
  256.             {
  257.             indent_level= substr( indent_level, 3 )
  258.             if( length(indent_level) == 2 )
  259.             {
  260.                     break;
  261.             }
  262.             }
  263.         }
  264.     else
  265.         {
  266.         if( inputstr ~ ".*{.*" )
  267.             {
  268.             indent_level= indent_level "%@"
  269.  
  270.         if( length(indent_level) == 4 )
  271.             continue;
  272.             }
  273.         else
  274.         if( inputstr ~ "}.*" )
  275.             {
  276.             if( length(indent_level) == 4 )
  277.                     break;
  278.         }
  279.         }
  280.  
  281.         # public members follow
  282.         if( inputstr ~ "public *:" )
  283.             ii= "public"
  284.  
  285.         # private members follow
  286.         else if( inputstr ~ "private *:" )
  287.             ii= "private"
  288.  
  289.         # protected members follow
  290.         else if( inputstr  ~ "protected *:" )
  291.             ii= "protected"
  292.  
  293.         else
  294.             {
  295.             gsub( "//", "  ", inputstr )
  296.         tmp= indent_level inputstr
  297.         if( ii == "private" )
  298.         class[ classcount, "private", privatecount++ ]= tmp
  299.         else
  300.         if( ii == "public" )
  301.         class[ classcount, "public", publiccount++ ]= tmp
  302.         else
  303.         if( ii == "protected" )
  304.         class[ classcount, "protected", protectedcount++ ]= tmp
  305.             }
  306.  
  307.         # see if should adjust the indent level
  308.     if( style == "k&r" )
  309.         {
  310.         if( inputstr ~ ".*{.*" )
  311.             {
  312.             indent_level= indent_level "%@"
  313.             }
  314.         }
  315.     else
  316.         {
  317.         if( inputstr ~ "}.*" )
  318.             {
  319.             indent_level= substr( indent_level, 3 )
  320.             if( length(indent_level) == 2 )
  321.                     break;
  322.             }
  323.         }
  324.     }
  325.  
  326.     class[ classcount, "public", 0 ]= publiccount
  327.     class[ classcount, "protected", 0 ]= protectedcount
  328.     class[ classcount, "private", 0 ]= privatecount
  329.     }
  330.  
  331. # processes a structure
  332. function process_struct( tmp,     style,indent_level )
  333.     {
  334.     indent_level= ""
  335.  
  336.     if( tmp ~ ".*{.*" )
  337.     style= "k&r"
  338.     else
  339.     style= "custom"
  340.  
  341.     do
  342.         {
  343.         tmp= strip_white( tmp )
  344.         gsub( "//", "  ", tmp );
  345.  
  346.     if( style == "k&r" )
  347.         {
  348.         if( tmp ~ "}.*" )
  349.             {
  350.             indent_level= substr( indent_level, 3 )
  351.             if( length(indent_level) == 0 )
  352.             {
  353.             struct[ structcount++ ] = indent_level tmp
  354.                     break;
  355.             }
  356.             }
  357.         struct[ structcount++ ] = indent_level tmp
  358.         if( tmp ~ ".*{.*" )
  359.             {
  360.             indent_level= indent_level "%@"
  361.             }
  362.         }
  363.     else
  364.         {
  365.         if( tmp ~ ".*{.*" )
  366.             {
  367.             indent_level= indent_level "%@"
  368.             }
  369.         struct[ structcount++ ] = indent_level tmp
  370.         if( tmp ~ "}.*" )
  371.             {
  372.             indent_level= substr( indent_level, 3 )
  373.             if( length(indent_level) == 0 )
  374.                     break;
  375.             }
  376.         }
  377.  
  378.         }while( (getline tmp) > 0 )
  379.     }
  380.  
  381. #
  382. # Outputs the specified array.
  383. #
  384. function output_section( data,   tmp,xx )
  385.     {
  386.     # Traverse the list of lines.
  387.     xx= 0
  388.     while( xx in data )
  389.     {
  390.     format_line( data[xx] )
  391.     xx++
  392.         }
  393.     if( xx != 0 )
  394.         format_line( ".SK" )
  395.     }
  396.  
  397. # Special funtion for printing out classes because the class
  398. # was built as a multi-dimensional array.
  399. function output_class(   xx,hd,cname)
  400.     {
  401.     # for each class
  402.     for( xx= 0; xx < classcount; xx++ )
  403.     {
  404.     # output the name of the class
  405.     format_line( class[ xx, "head", 0 ] )
  406.     format_line( ".SK" )
  407.  
  408.     output_part_class( "%@" "Public members", "public", xx );
  409.     output_part_class( "%@" "Protected members", "protected", xx );
  410.     output_part_class( "%@" "Private members", "private", xx );
  411.     }
  412.     }
  413.  
  414. # Prints the specified portion of the class.
  415. function output_part_class( header, idname, idnum,     yy,amount )
  416.     {
  417.     # get the number of items
  418.     amount= class[ idnum, idname, 0 ];
  419.     if( amount == 1 )
  420.         return;
  421.  
  422.     # output the header
  423.     format_line( header )
  424.  
  425.     for( yy= 1; yy < amount; yy++ )
  426.     {
  427.     format_line( class[ idnum, idname, yy ] );
  428.     }
  429.     format_line( ".SK" )
  430.     }
  431.  
  432. # Call to get the function summarys from the source files and print them
  433. function output_summarys(   data,title,xx,datacount,titlecount )
  434.     {
  435.     # just return if no source files listed
  436.     if( sourcefilecount == 1 )
  437.         return;
  438.  
  439.     # print the header
  440.     format_line( "%h" "SUMMARY" )
  441.  
  442.     # number of descriptions found
  443.     descriptioncount= 0;
  444.  
  445.     # walk the list of source files
  446.     for( xx = 1; xx < sourcefilecount; xx++ )
  447.         {
  448.         # loop reading each line of the source file
  449.     while( (getline inputstr <sourcefile[xx]) > 0 )
  450.             {
  451.             # see if the start of the function summary
  452.         if( inputstr == "// Description:" )
  453.         {
  454.         if( descriptioncount > 0 )
  455.             format_line( ".SK" );
  456.         descriptioncount++
  457.  
  458.         # number of lines to output for this description
  459.         datacount= 0;
  460.         titlecount= 0;
  461.  
  462.                 # loop reading the summary
  463.         while( (getline inputstr <sourcefile[xx]) > 0 )
  464.             {
  465.                     # see if all done with this description
  466.             if( inputstr ~ "^[\t ]+[:{].*" )
  467.             {
  468.             # output what we collected for the description
  469.             format_line( ".BO" )
  470.             for( yy= 0; yy < titlecount; yy++ )
  471.                 format_line( title[yy] );
  472.             format_line( ".NB" )
  473.             for( yy= 0; yy < datacount; yy++ )
  474.                 format_line( data[yy] );
  475.             break;
  476.             }
  477.  
  478.                     # strip the comment and leading whitespace
  479.             if( gsub( "//[\t ]*", "", inputstr ) != 0 )
  480.             {
  481.                         # only keep lines not ending in :
  482.             if( inputstr !~ ".*:$" )
  483.                 {
  484.                             # save the line of data
  485.                 data[ datacount++ ] = "%@" inputstr
  486.                 }
  487.             }
  488.             else
  489.             {
  490.                         # only keep lines that are not blank
  491.             if( length( inputstr ) )
  492.                 {
  493.                             # save the line of the function name
  494.                 title[ titlecount++ ] = inputstr
  495.                 }
  496.             }
  497.             }
  498.         }
  499.         }
  500.     }
  501.     }
  502.  
  503. # strips leading and trailing whitespace from the specified string and
  504. # returns the string
  505. function strip_white( data )
  506.     {
  507.     gsub( "^[\t ]+", "", data )
  508.     gsub( "[\t ]+$", "", data )
  509.     return data
  510.     }
  511.  
  512. # This routine takes a line of data and converts it into
  513. # the appropriate format for the output device.
  514. #
  515. # Documentation of imbedded formatting commands.
  516. #   .FI on a line by itself means turn on fill mode
  517. #   .NF on a line by itself means turn off fill mode
  518. #   .BO on a line by itself means turn on bold mode
  519. #   .NB on a line by itself means turn off bold mode
  520. #   .SK on a line by itself means skip a line
  521. #   %h means the rest of the line is a section header
  522. #   %@ means indent one level
  523. function format_line( data )
  524.     {
  525.     # This section is for producing troff output.
  526.     if( device == "troff" )
  527.     {
  528.     # see if a special formatting command
  529.     if( length(data) == 3 )
  530.         {
  531.         if( data == ".FI" )
  532.         {
  533.         print ".fi"
  534.         nofill= ""
  535.         return;
  536.         }
  537.         else
  538.         if( data == ".NF" )
  539.         {
  540.         print ".nf"
  541.         nofill= "\n.nf"
  542.         return;
  543.         }
  544.         else
  545.         if( data == ".BO" )
  546.         {
  547.         bold= ".B \n"
  548.         return;
  549.         }
  550.         else
  551.         if( data == ".NB" )
  552.         {
  553.         bold= ""
  554.         return;
  555.         }
  556.         else
  557.         if( data == ".SK" )
  558.         {
  559.         print ".PP"
  560.         return;
  561.         }
  562.         }
  563.  
  564.     # See if a heading.
  565.     if( data ~ "%h.*" )
  566.         {
  567.         data= substr( data, 3 );
  568.         print ".SH " "\"" toupper(data) "\"" nofill
  569.         }
  570.  
  571.     # else a regular line
  572.     else
  573.         {
  574.         # convert indent marks to spaces
  575.         gsub( "%@", lp_indent, data )
  576.  
  577.         # add embolding
  578.         data= bold data
  579.  
  580.         # print the data
  581.             print data
  582.         }
  583.     }
  584.  
  585.     # This section is for producing ascii formatted output.
  586.     else
  587.     {
  588.     # see if a special formatting command
  589.     if( length(data) == 3 )
  590.         {
  591.         # Ignore fill and bold transitions.
  592.         if( (data == ".FI") || (data == ".NF") ||
  593.         (data == ".BO") || (data == ".NB") )
  594.         return;
  595.  
  596.         # see if should skip a line
  597.         if( data == ".SK" )
  598.         {
  599.         print
  600.         return;
  601.         }
  602.         }
  603.  
  604.     # See if a heading.
  605.     if( data ~ "%h.*" )
  606.         {
  607.         data= substr( data, 3 );
  608.         print toupper(data)
  609.         }
  610.  
  611.     # else a regular line
  612.     else
  613.         {
  614.         # convert indent marks to spaces
  615.         gsub( "%@", lp_indent, data )
  616.  
  617.         # add default indent amount
  618.         data= lp_indent data
  619.  
  620.         # if more then 79 characters, trim it
  621.         if( length(data) > 79 )
  622.             data= substr( data, 1, 79 );
  623.             print data
  624.         }
  625.     }
  626.     }
  627.  
  628. # This routine is called once to perform any device specific initialization
  629. # and to setup the title line and the date line.
  630. function format_start( titlename, library, header, date, namehead )
  631.     {
  632.     # This section is for producing troff output.
  633.     if( device == "troff" )
  634.     {
  635.     print ".\\\" Generated automatically by genman.awk version 2 from "
  636.     print ".\\\"     "    FILENAME
  637.     print ".\\\""
  638.     printf( ".TH %s %s \"%s\" \"\" \"%s\" \n",
  639.            titlename, library, date, header );
  640.     sub( "-", "\\-", namehead )
  641.     format_line( "%h" "name" )
  642.     format_line( namehead )
  643.     format_line( ".SK" )
  644.     }
  645.  
  646.     # This section is for producing ascii formatted output.
  647.     else
  648.     {
  649.     hlen= (length( header ) +1) / 2;
  650.     hlen= hlen * 2;
  651.     tlen= (78 - hlen) / 2;
  652.     fmtstr= sprintf( "%%-%ds%%-%ds%%%ds\n", tlen, hlen, tlen );
  653.     titlename= titlename "(" library ")"
  654.     print
  655.     printf( fmtstr, titlename, header, titlename );
  656.     print
  657.     printf( "%77s\n", date )
  658.     format_line( "%h" "name" )
  659.     format_line( namehead )
  660.     format_line( ".SK" )
  661.     }
  662.     }
  663.  
  664. # This routine is called once to perform any device specific
  665. # cleanup.
  666. function format_end()
  667.     {
  668.     # This section is for producing troff output.
  669.     if( device == "troff" )
  670.     {
  671.     }
  672.  
  673.     # This section is for producing ascii formatted output.
  674.     else
  675.     {
  676.     }
  677.     }
  678.