#!/usr/bin/perl # This script takes inline comments from C files and turns them into docbook # documentation files... It was orginally written for the Panda project # http://www.stillhq.com/cgi-bin/getpage?area=panda&page=index.htm # It has now been extended to read the inline comment format used for Freetype # as well # $docbook is a state indicator: # 0 -- no state currently defined # 1 -- inside a DOCBOOK formatted comment # 2 -- inside a
formatted comment # 3 -- inside a formatted comment # 4 -- inside a formatted comment # 5 -- inside a formatted comment # 6 -- inside a formatted comment # The Freetype stuff has the concept of subitems, which means that some things # cannot be processed until the end of the file is reached. Waiting stores the # names of the elements which are waiting until the end of the file, and # subitems stores the elements which will be needed at that time. # This code is (c) Michael Still 2001, 2002 and is released under the terms of the # GNU GPL use strict; my($CFILE, $filename, $docbook, $blockmode, $blockstring, $blockkey, %myhash); my($key, $value, $tempString, $OUTPUTFILE, $docbooktoman, @sgmls, $sgmlcount); my($i, $outputfilename, $outputtargets, $templine, %subitems, %waiting); # Do some initialisation stuff -- the command line stuff should be changed to # use getopt sometime soon... $filename = shift(); $outputtargets = shift(); $docbook = 0; $sgmlcount = 0; print "Opening $filename and finding all the documentation comments within it\n"; print " "; # Run through every line the the file open CFILE, "< $filename"; while(){ chomp; # Deal with special docbook characters s///g; s/&/&/g; s//>/g; # The docbook start and stop tags are treated as special cases if(/DOCBOOK START/){ $docbook = 1; } elsif(/DOCBOOK END/){ print "\b+"; $docbook = 0; finalise(0, %myhash); # Clean up myhash while(($key, $value) = each %myhash){ delete $myhash{$key}; } } elsif((/([A-Z]*)[ \t]*([^\r]+)[ \t]*/) && ($docbook == 1)){ if($blockmode == 0){ if($2 eq "START"){ # We are entering block mode $blockmode = 1; $blockstring = ""; $blockkey = $1; } elsif($1 ne ""){ # Outside of block mode we ignore blank lines $myhash{ $1 } = $2; } } else{ # We are in block mode if($2 eq "END"){ $myhash{ $blockkey } = $blockstring; $blockmode = 0; } else{ $blockstring = "$blockstring $1$2\n"; } } } elsif($docbook == 1){ print $_; } ################################################################## # Handle Freetype style markup elsif(/\/\*[ \t]*
.*/i){ if($docbook ne 0){ setblockkey("DONE", ""); finalise(0, %myhash); cleanup(); } $docbook = 2; setblockkey("FUNCTION", ""); } elsif((/\/\*[ \t]*.*/i) && ($docbook == 2)){ setblockkey("PURPOSE", ""); } elsif((/\/\*[ \t]*<abstract>.*/i) && ($docbook == 2)){ setblockkey("SYNOPSIS", ""); } elsif((/\/\*[ \t]*<description>.*/i) && ($docbook > 1)){ setblockkey("DESCRIPTION", ""); } elsif((/\/\*[ \t]*<order>.*/i) && ($docbook == 2)){ setblockkey("SUBITEMS", ""); } elsif(/\/\*[ \t]*<struct>.*/i){ if($docbook ne 0){ setblockkey("DONE", ""); finalise(0, %myhash); cleanup(); } $docbook = 3; setblockkey("FUNCTION", ""); } elsif((/\/\*[ \t]*<fields>.*/i) && (($docbook == 3) || ($docbook == 5))){ setblockkey("SYNOPSIS", ""); } elsif(/\/\*[ \t]*<function>.*/i){ if($docbook ne 0){ setblockkey("DONE", ""); finalise(0, %myhash); cleanup(); } $docbook = 4; setblockkey("FUNCTION", ""); } elsif((/\/\*[ \t]*<input>.*/i) && ($docbook == 4)){ setblockkey("DESCRIPTION", "Input"); } elsif((/\/\*[ \t]*<return>.*/i) && ($docbook == 4)){ setblockkey("RETURNS", ""); } elsif((/\/\*[ \t]*<inout>.*/i) && ($docbook == 4)){ setblockkey("DESCRIPTION", "Input / Output"); } elsif(/\/\*[ \t]*<note>.*/i){ setblockkey("DESCRIPTION", "Notes"); } elsif(/\/\*[ \t]*<enum>.*/i){ if($docbook ne 0){ setblockkey("DONE", ""); finalise(0, %myhash); cleanup(); } $docbook = 5; setblockkey("FUNCTION", ""); } elsif((/\/\*[ \t]*<output>.*/i) && ($docbook == 4)){ setblockkey("DESCRIPTION", "Output"); } elsif(/\/\*[ \t]*<type>.*/i){ setblockkey("DESCRIPTION", ""); } elsif(/\/\*[ \t]*<constant>.*/i){ if($docbook ne 0){ setblockkey("DONE", ""); finalise(0, %myhash); cleanup(); } $docbook = 6; setblockkey("FUNCTION", ""); } elsif(/\/\*[ \t]*<macro>.*/i){ setblockkey("DESCRIPTION", ""); } elsif(/\/\*[ \t]*<.*>/){ print "\n\n*** Undefined tag $_ ***\n\n"; } elsif($docbook gt 1){ s/\/\*[ \t]/ /; s/\*\///; s/[ \t]+/ /; chomp; s/^ +//; s/ +$//; s/ +:: +/ :: /; s/\/\*+//; $templine = $_; if(/.*::.*/){ $templine = "</para><para>$templine"; } if(length $templine ne 0){ if($blockstring ne ""){ if($blockkey ne "SUBITEMS"){ $blockstring = "$blockstring $templine "; } else{ $blockstring = "$blockstring,$templine"; } } else{ $blockstring = $templine; } } else{ # Deal with paragraphs } } } # Deal with the final one for the document if($docbook ne 0){ setblockkey("DONE", ""); finalise(0, %myhash); cleanup(); } # Process the elements with subitems print "\n\nNow processing those pages with subitems:"; while(($key, $value) = each %waiting){ print "\n $key".$subitems{"$key-FUNCTION"}."\n "; # Rebuild the hash table we would have had for this element $myhash{FUNCTION} = $subitems{"$key-FUNCTION"}; $myhash{PURPOSE} = $subitems{"$key-PURPOSE"}; $myhash{DESCRIPTION} = $subitems{"$key-DESCRIPTION"}; $myhash{SYNOPSIS} = $subitems{"$key-SYNOPSIS"}; $myhash{SUBITEMS} = $subitems{"$key-SUBITEMS"}; $myhash{RETURNS} = $subitems{"$key-RETURNS"}; $myhash{EXAMPLE} = $subitems{"$key-EXAMPLE"}; $myhash{SEEALSO} = $subitems{"$key-SEEALSO"}; setblockkey("DONE", ""); finalise(1, %myhash); cleanup(); } # Do some output conversion if($outputtargets ne ""){ print "\n\nNow converting the generated SGML into the requested formats\n"; # What formats do we support? Perhaps just use strings which we can append # to docbook2... to come up with a command to execute $docbooktoman=`which docbook2man`; chomp($docbooktoman); if($docbooktoman ne ""){ print " docbook2man found at $docbooktoman\n"; for($i = 0; $i < $sgmlcount; $i++){ $outputfilename=`echo "$sgmls[$i]" | sed 's/sgml/man/'`; chomp($outputfilename); print " Output file: $sgmls[$i] --> $outputfilename\n"; `$docbooktoman $sgmls[$i] 2> /dev/null`; print "Done.\n"; } } else{ print " docbook2man missing\n"; } } else{ print "\n\nNo output conversion requested\n"; } print "\n"; exit; ############################################################################### # This function call is used to finalise docbook generation in the Freetype # stuff sub finalise(){ my($isEOF) = @_; my($OUTPUTFILE); # Store the data that we might need later while(($key, $value) = each %myhash){ $subitems{"$myhash{FUNCTION}-$key"} = $value; } # If there are sub items and this is not the end of the input file, then # just record that we are waiting for this one... if(($myhash{SUBITEMS} ne "") && ($isEOF == 0)){ print "-"; $waiting{$myhash{FUNCTION}} = $myhash{FUNCTION}; return; } else{ print "+"; } # Open the output file or flag an error open OUTPUTFILE, "> man/$myhash{FUNCTION}.sgml" or die "Could not open man/$myhash{FUNCTION}.sgml"; # Dump the hash for this piece of documentation... # We should know that there is a key named FUNCTION which is the name of the docbook output print OUTPUTFILE `cat man/docbook/head.sgml`; print OUTPUTFILE "<refentry id=\"$myhash{FUNCTION}\">\n"; print OUTPUTFILE "<refmeta>\n"; print OUTPUTFILE "<refentrytitle>$myhash{FUNCTION}</refentrytitle>\n"; print OUTPUTFILE "<manvolnum>3</manvolnum>\n"; print OUTPUTFILE "</refmeta>\n\n"; print OUTPUTFILE "<refnamediv>\n"; print OUTPUTFILE "<refname>$myhash{FUNCTION}</refname>\n"; if($myhash{PURPOSE} ne ""){ print OUTPUTFILE "<refpurpose>$myhash{PURPOSE}</refpurpose>\n"; } print OUTPUTFILE "</refnamediv>\n\n"; if($myhash{SYNOPSIS} ne ""){ print OUTPUTFILE "<refsynopsisdiv>\n"; print OUTPUTFILE "<synopsis>\n"; print OUTPUTFILE "$myhash{SYNOPSIS}\n"; print OUTPUTFILE "</synopsis>\n"; print OUTPUTFILE "</refsynopsisdiv>\n\n"; } if($myhash{DESCRIPTION} ne ""){ print OUTPUTFILE "<refsect1>\n"; print OUTPUTFILE "<title>DESCRIPTION\n"; print OUTPUTFILE "$myhash{DESCRIPTION}\n"; print OUTPUTFILE "\n\n"; } if($myhash{SUBITEMS} ne ""){ foreach $key (split(/,/, $myhash{SUBITEMS})){ print OUTPUTFILE "\n"; print OUTPUTFILE "$key\n"; if($subitems{"$key-PURPOSE"} ne ""){ print OUTPUTFILE "Purpose:\n"; print OUTPUTFILE $subitems{"$key-PURPOSE"}; print OUTPUTFILE "\n"; } if($subitems{"$key-DESCRIPTION"} ne ""){ print OUTPUTFILE "Description:\n"; print OUTPUTFILE $subitems{"$key-DESCRIPTION"}; print OUTPUTFILE "\n"; print "*"; } else{ print "!"; print OUTPUTFILE "Content missing for this item\n"; } if($subitems{"$key-SYNOPSIS"} ne ""){ print OUTPUTFILE "Synopsis:\n"; print OUTPUTFILE $subitems{"$key-SYNOPSIS"}; print OUTPUTFILE "\n"; } if($subitems{"$key-RETURNS"} ne ""){ print OUTPUTFILE "Returns:\n"; print OUTPUTFILE $subitems{"$key-RETURNS"}; print OUTPUTFILE "\n"; } if($subitems{"$key-EXAMPLE"} ne ""){ print OUTPUTFILE "Example:\n"; print OUTPUTFILE $subitems{"$key-EXAMPLE"}; print OUTPUTFILE "\n"; } if($subitems{"$key-SEEALSO"} ne ""){ print OUTPUTFILE "See also:\n"; print OUTPUTFILE $subitems{"$key-SEEALSO"}; print OUTPUTFILE "\n"; } print OUTPUTFILE "\n\n"; } } if($myhash{RETURNS} ne ""){ print OUTPUTFILE "\n"; print OUTPUTFILE "RETURNS\n"; print OUTPUTFILE "$myhash{RETURNS}\n"; print OUTPUTFILE "\n\n"; } if($myhash{EXAMPLE} ne ""){ print OUTPUTFILE "\n"; print OUTPUTFILE "EXAMPLE\n"; print OUTPUTFILE "\n$myhash{EXAMPLE}\n"; print OUTPUTFILE "\n\n"; } if($myhash{SEEALSO} ne ""){ print OUTPUTFILE "\n"; print OUTPUTFILE "SEE ALSO\n"; print OUTPUTFILE "$myhash{SEEALSO}\n"; print OUTPUTFILE "\n\n"; } print OUTPUTFILE `cat man/docbook/foot.sgml`; close OUTPUTFILE; @sgmls[$sgmlcount] = "man/$myhash{FUNCTION}.sgml"; $sgmlcount++; } sub cleanup{ my($key, $value); while(($key, $value) = each %myhash){ delete $myhash{$key}; } } sub setblockkey{ my($newkey, $subhead) = @_; # If this is currently the key (already) if($blockkey ne $newkey){ $myhash{$blockkey} = "$myhash{$blockkey}$blockstring"; $blockstring = "$myhash{$newkey}"; # Set the new key $blockkey = $newkey; } if($blockstring ne ""){ $blockstring = "$blockstring "; } # If this is a subheading, then deal with that as well if($subhead ne ""){ $blockstring = "$blockstring$subhead:"; } }