| #!/usr/bin/perl |
| |
| ##################################################################################### |
| # |
| # c2man.pl v0.1 Copyright (C) 2000 Mike McCormack |
| # |
| # Generates Documents from C source code. |
| # |
| # Input is source code with specially formatted comments, output |
| # is man pages. The functionality is meant to be similar to c2man. |
| # The following is an example provided in the Wine documentation. |
| # |
| # This library is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU Lesser General Public |
| # License as published by the Free Software Foundation; either |
| # version 2.1 of the License, or (at your option) any later version. |
| # |
| # This library is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # Lesser General Public License for more details. |
| # |
| # You should have received a copy of the GNU Lesser General Public |
| # License along with this library; if not, write to the Free Software |
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| # |
| # TODO: |
| # Write code to generate HTML output with the -Th option. |
| # Need somebody who knows about TROFF to help touch up the man page generation. |
| # Parse spec files passed with -w option and generate pages for the functions |
| # in the spec files only. |
| # Modify Makefiles to pass multiple C files to speed up man page generation. |
| # Use nm on the shared libraries specified in the spec files to determine which |
| # source files should be parsed, and only parse them.(requires wine to be compiled) |
| # |
| ##################################################################################### |
| # Input from C source file: |
| # |
| # /****************************************************************** |
| # * CopyMetaFile32A (GDI32.23) |
| # * |
| # * Copies the metafile corresponding to hSrcMetaFile to either |
| # * a disk file, if a filename is given, or to a new memory based |
| # * metafile, if lpFileName is NULL. |
| # * |
| # * RETURNS |
| # * |
| # * Handle to metafile copy on success, NULL on failure. |
| # * |
| # * BUGS |
| # * |
| # * Copying to disk returns NULL even if successful. |
| # */ |
| # HMETAFILE32 WINAPI CopyMetaFile32A( |
| # HMETAFILE32 hSrcMetaFile, /* handle of metafile to copy */ |
| # LPCSTR lpFilename /* filename if copying to a file */ |
| # ) { ... } |
| # |
| ##################################################################################### |
| # Output after processing with nroff -man |
| # |
| # CopyMetaFileA(3w) CopyMetaFileA(3w) |
| # |
| # |
| # NAME |
| # CopyMetaFileA - CopyMetaFile32A (GDI32.23) |
| # |
| # SYNOPSIS |
| # HMETAFILE32 CopyMetaFileA |
| # ( |
| # HMETAFILE32 hSrcMetaFile, |
| # LPCSTR lpFilename |
| # ); |
| # |
| # PARAMETERS |
| # HMETAFILE32 hSrcMetaFile |
| # Handle of metafile to copy. |
| # |
| # LPCSTR lpFilename |
| # Filename if copying to a file. |
| # |
| # DESCRIPTION |
| # Copies the metafile corresponding to hSrcMetaFile to |
| # either a disk file, if a filename is given, or to a new |
| # memory based metafile, if lpFileName is NULL. |
| # |
| # RETURNS |
| # Handle to metafile copy on success, NULL on failure. |
| # |
| # BUGS |
| # Copying to disk returns NULL even if successful. |
| # |
| # SEE ALSO |
| # GetMetaFileA(3w), GetMetaFileW(3w), CopyMetaFileW(3w), |
| # PlayMetaFile(3w), SetMetaFileBitsEx(3w), GetMetaFileBit- |
| # sEx(3w) |
| # |
| ##################################################################################### |
| |
| sub output_manpage |
| { |
| my ($buffer,$apiref) = @_; |
| my $parameters; |
| my $desc; |
| |
| # join all the lines of the description together and highlight the headings |
| for (@$buffer) { |
| s/\n//g; |
| s/^\s*//g; |
| s/\s*$//g; |
| if ( /^([A-Z]+)$/ ) { |
| $desc = $desc.".SH $1\n.PP\n"; |
| } |
| elsif ( /^$/ ) { |
| $desc = "$desc\n"; |
| } |
| else { |
| $desc = "$desc $_"; |
| } |
| } |
| |
| #seperate out all the parameters |
| |
| $plist = join ( ' ', @$apiref ); |
| |
| $name_type = $plist; |
| $name_type =~ s/\n//g; # remove newlines |
| $name_type =~ s/\(.*$//; |
| $name_type =~ s/WINAPI//; |
| |
| #check that this is a function that we want |
| if ( $funcdb{$apiname."ORD"} eq "" ) { return; } |
| print "Generating $apiname.$section\n"; |
| |
| $plist =~ s/\n//g; # remove newlines |
| $plist =~ s/^.*\(\s*//; # remove leading bracket and before |
| $plist =~ s/\s*\).*$//; # remove trailing bracket and leftovers |
| $plist =~ s/\s*,?\s*\/\*([^*]*)\*\// - $1,/g; # move the comma to the back |
| @params = split ( /,/ , $plist); # split parameters |
| for(@params) { |
| s/^\s*//; |
| s/\s*$//; |
| } |
| |
| # figure the month and the year |
| @datetime = localtime; |
| @months = ( "January", "Febuary", "March", "April", "May", "June", |
| "July", "August", "September", "October", "November", "December" ); |
| $date = "$months[$datetime[4]] $datetime[5]"; |
| |
| # create the manual page |
| $manfile = "$mandir/$apiname.$section"; |
| open(MAN,">$manfile") || die "Couldn't create the man page file $manfile\n"; |
| print MAN ".\\\" DO NOT MODIFY THIS FILE! It was generated by gendoc 1.0.\n"; |
| print MAN ".TH $apiname \"$section\" \"$date\" \"Wine API\" \"The Wine Project\"\n"; |
| print MAN ".SH NAME\n"; |
| print MAN "$apiname ($apientry)\n"; |
| print MAN ".SH SYNOPSIS\n"; |
| print MAN ".PP\n"; |
| print MAN "$name_type\n"; |
| print MAN " (\n"; |
| for($i=0; $i<@params; $i++) { |
| $x = ($i == (@params-1)) ? "" : ","; |
| $c = $params[$i]; |
| $c =~ s/-.*//; |
| print MAN " $c$x\n"; |
| } |
| print MAN " );\n"; |
| print MAN ".SH PARAMETERS\n"; |
| print MAN ".PP\n"; |
| for($i=0; $i<@params; $i++) { |
| print MAN " $params[$i]\n"; |
| } |
| print MAN ".SH DESCRIPTION\n"; |
| print MAN ".PP\n"; |
| print MAN $desc; |
| close(MAN); |
| } |
| |
| # |
| # extract the comments from source file |
| # |
| sub parse_source |
| { |
| my $file = $_[0]; |
| print "Processing $file\n"; |
| |
| open(SOURCE,"<$file") || die "Couldn't open the source file $file\n"; |
| $state = 0; |
| while(<SOURCE>) { |
| if($state == 0 ) { |
| if ( /^\/\**$/ ) { |
| # find the start of the comment /************** |
| $state = 3; |
| @buffer = (); |
| } |
| } |
| elsif ($state == 3) { |
| #extract the wine API name and DLLNAME.XXX string |
| if ( / *([A-Za-z_0-9]+) *\(([A-Za-z0-9_]+\.(([0-9]+)|@))\) *$/ ) { |
| $apiname = $1; |
| $apientry = $2; |
| $state = 1; |
| } |
| else { |
| $state = 0; |
| } |
| } |
| elsif ($state == 1) { |
| #save the comment text into buffer, removing leading astericks |
| if ( /^ \*\// ) { |
| $state = 2; |
| } |
| else { |
| # find the end of the comment |
| if ( s/^ \*// ) { |
| @buffer = ( @buffer , $_ ); |
| } |
| else { |
| $state = 0; |
| } |
| } |
| } |
| elsif ($state == 2) { |
| # check that the comment is followed by the declaration of |
| # a WINAPI function. |
| if ( /WINAPI/ ) { |
| @apidef = ( $_ ); |
| #check if the function's parameters end on this line |
| if( /\)/ ) { |
| output_manpage(\@buffer, \@apidef); |
| $state = 0; |
| } |
| else { |
| $state = 4; |
| } |
| } |
| else { |
| $state = 0; |
| } |
| } |
| elsif ($state == 4) { |
| @apidef = ( @apidef , $_ ); |
| #find the end of the parameters list |
| if( /\)/ ) { |
| output_manpage(\@buffer, \@apidef); |
| $state = 0; |
| } |
| } |
| } |
| close(SOURCE); |
| } |
| |
| # generate a database of functions to have man pages created from the source |
| # creates funclist and funcdb |
| sub parse_spec |
| { |
| my $spec = $_[0]; |
| my $name,$type,$ord,$func; |
| |
| open(SPEC,"<$spec") || die "Couldn't open the spec file $spec\n"; |
| while(<SPEC>) |
| { |
| if( /^#/ ) { next; } |
| if( /^name/ ) { next; } |
| if( /^type/ ) { next; } |
| if( /^init/ ) { next; } |
| if( /^rsrc/ ) { next; } |
| if( /^import/ ) { next; } |
| if( /^\s*$/ ) { next; } |
| if( /^\s*(([0-9]+)|@)/ ) { |
| s/\(.*\)//; #remove all the args |
| ($ord,$type,$name,$func) = split( /\s+/ ); |
| if(( $type eq "stub" ) || ($type eq "forward")) {next;} |
| if( $func eq "" ) { next; } |
| @funclist = ( @funclist , $func ); |
| $funcdb{$func."ORD"} = $ord; |
| $funcdb{$func."TYPE"} = $type; |
| $funcdb{$func."NAME"} = $name; |
| $funcdb{$func."SPEC"} = $spec; |
| } |
| } |
| close(SPEC); |
| } |
| |
| ###################################################################### |
| |
| #main starts here |
| |
| $mandir = "man3w"; |
| $section = "3"; |
| |
| #process args |
| while(@ARGV) { |
| if($ARGV[0] eq "-o") { # extract output directory |
| shift @ARGV; |
| $mandir = $ARGV[0]; |
| shift @ARGV; |
| next; |
| } |
| if($ARGV[0] =~ s/^-S// ) { # extract man section |
| $section = $ARGV[0]; |
| shift @ARGV; |
| next; |
| } |
| if($ARGV[0] =~ s/^-w// ) { # extract man section |
| shift @ARGV; |
| @specfiles = ( @specfiles , $ARGV[0] ); |
| shift @ARGV; |
| next; |
| } |
| if($ARGV[0] =~ s/^-T// ) { |
| die "FIXME: Only NROFF supported\n"; |
| } |
| if($ARGV[0] =~ s/^-[LDiI]// ) { #compatible with C2MAN flags |
| shift @ARGV; |
| next; |
| } |
| last; # stop after there's no more flags |
| } |
| |
| #print "manual section: $section\n"; |
| #print "man directory : $mandir\n"; |
| #print "input files : @ARGV\n"; |
| #print "spec files : @specfiles\n"; |
| |
| while(@specfiles) { |
| parse_spec($specfiles[0]); |
| shift @specfiles; |
| } |
| |
| #print "Functions: @funclist\n"; |
| |
| while(@ARGV) { |
| parse_source($ARGV[0]); |
| shift @ARGV; |
| } |
| |